mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-15 13:26:34 +00:00
20220201.0 (#11508)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Co-authored-by: Thomas Lovén <thomasloven@gmail.com> Co-authored-by: Zack Barett <arnett.zackary@gmail.com> Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Co-authored-by: Philip Allgaier <mail@spacegaier.de> Co-authored-by: Yosi Levy <37745463+yosilevy@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Patrick ZAJDA <patrick@zajda.fr> Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
This commit is contained in:
parent
9fee7a2829
commit
7c4b9a0410
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@ -41,7 +41,7 @@ jobs:
|
||||
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
||||
- name: Build and release package
|
||||
run: |
|
||||
python3 -m pip install twine
|
||||
python3 -m pip install twine build
|
||||
export TWINE_USERNAME="__token__"
|
||||
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
include README.md
|
||||
include LICENSE.md
|
||||
graft hass_frontend
|
||||
graft hass_frontend_es5
|
||||
recursive-exclude * *.py[co]
|
||||
|
@ -26,11 +26,11 @@ module.exports = {
|
||||
},
|
||||
version() {
|
||||
const version = fs
|
||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
||||
.match(/\d{8}\.\d+/);
|
||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.cfg"), "utf8")
|
||||
.match(/version\W+=\W(\d{8}\.\d)/);
|
||||
if (!version) {
|
||||
throw Error("Version not found");
|
||||
}
|
||||
return version[0];
|
||||
return version[1];
|
||||
},
|
||||
};
|
||||
|
10
package.json
10
package.json
@ -110,7 +110,7 @@
|
||||
"js-yaml": "^4.1.0",
|
||||
"leaflet": "^1.7.1",
|
||||
"leaflet-draw": "^1.0.4",
|
||||
"lit": "^2.0.2",
|
||||
"lit": "^2.1.2",
|
||||
"lit-vaadin-helpers": "^0.2.1",
|
||||
"marked": "^3.0.2",
|
||||
"memoize-one": "^5.2.1",
|
||||
@ -236,10 +236,10 @@
|
||||
"resolutions": {
|
||||
"@polymer/polymer": "patch:@polymer/polymer@3.4.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
||||
"@webcomponents/webcomponentsjs": "^2.2.10",
|
||||
"lit": "^2.0.2",
|
||||
"lit-html": "2.0.1",
|
||||
"lit-element": "3.0.1",
|
||||
"@lit/reactive-element": "1.0.1"
|
||||
"lit": "^2.1.2",
|
||||
"lit-html": "2.1.2",
|
||||
"lit-element": "3.1.2",
|
||||
"@lit/reactive-element": "1.2.1"
|
||||
},
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ["setuptools~=60.5", "wheel~=0.37.1"]
|
||||
build-backend = "setuptools.build_meta"
|
@ -11,6 +11,6 @@ yarn install
|
||||
|
||||
script/build_frontend
|
||||
|
||||
rm -rf dist
|
||||
python3 setup.py -q sdist
|
||||
rm -rf dist home_assistant_frontend.egg-info
|
||||
python3 -m build
|
||||
python3 -m twine upload dist/* --skip-existing
|
||||
|
@ -50,14 +50,14 @@ async function main(args) {
|
||||
return;
|
||||
}
|
||||
|
||||
const setup = fs.readFileSync("setup.py", "utf8");
|
||||
const setup = fs.readFileSync("setup.cfg", "utf8");
|
||||
const version = setup.match(/\d{8}\.\d+/)[0];
|
||||
const newVersion = method(version);
|
||||
|
||||
console.log("Current version:", version);
|
||||
console.log("New version:", newVersion);
|
||||
|
||||
fs.writeFileSync("setup.py", setup.replace(version, newVersion), "utf-8");
|
||||
fs.writeFileSync("setup.cfg", setup.replace(version, newVersion), "utf-8");
|
||||
|
||||
if (!commit) {
|
||||
return;
|
||||
|
21
setup.cfg
Normal file
21
setup.cfg
Normal file
@ -0,0 +1,21 @@
|
||||
[metadata]
|
||||
name = home-assistant-frontend
|
||||
version = 20220201.0
|
||||
author = The Home Assistant Authors
|
||||
author_email = hello@home-assistant.io
|
||||
license = Apache-2.0
|
||||
platforms = any
|
||||
description = The Home Assistant frontend
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
url = https://github.com/home-assistant/frontend
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
zip_safe = False
|
||||
include_package_data = True
|
||||
python_requires = >= 3.4.0
|
||||
|
||||
[options.packages.find]
|
||||
include =
|
||||
hass_frontend*
|
19
setup.py
19
setup.py
@ -1,14 +1,7 @@
|
||||
from setuptools import setup, find_packages
|
||||
"""
|
||||
Entry point for setuptools. Required for editable installs.
|
||||
TODO: Remove file after updating to pip 21.3
|
||||
"""
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20220127.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/frontend",
|
||||
author="The Home Assistant Authors",
|
||||
author_email="hello@home-assistant.io",
|
||||
license="Apache-2.0",
|
||||
packages=find_packages(include=["hass_frontend", "hass_frontend.*"]),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
)
|
||||
setup()
|
||||
|
@ -183,12 +183,7 @@ class StateHistoryChartLine extends LitElement {
|
||||
prevValues = datavalues;
|
||||
};
|
||||
|
||||
const addDataSet = (
|
||||
nameY: string,
|
||||
step = false,
|
||||
fill = false,
|
||||
color?: string
|
||||
) => {
|
||||
const addDataSet = (nameY: string, fill = false, color?: string) => {
|
||||
if (!color) {
|
||||
color = getGraphColorByIndex(colorIndex, computedStyles);
|
||||
colorIndex++;
|
||||
@ -198,7 +193,7 @@ class StateHistoryChartLine extends LitElement {
|
||||
fill: fill ? "origin" : false,
|
||||
borderColor: color,
|
||||
backgroundColor: color + "7F",
|
||||
stepped: step ? "before" : false,
|
||||
stepped: "before",
|
||||
pointRadius: 0,
|
||||
data: [],
|
||||
});
|
||||
@ -239,14 +234,12 @@ class StateHistoryChartLine extends LitElement {
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.climate.current_temperature", {
|
||||
name: name,
|
||||
})}`,
|
||||
true
|
||||
})}`
|
||||
);
|
||||
if (hasHeat) {
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.climate.heating", { name: name })}`,
|
||||
true,
|
||||
true,
|
||||
computedStyles.getPropertyValue("--state-climate-heat-color")
|
||||
);
|
||||
// The "heating" series uses steppedArea to shade the area below the current
|
||||
@ -256,7 +249,6 @@ class StateHistoryChartLine extends LitElement {
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.climate.cooling", { name: name })}`,
|
||||
true,
|
||||
true,
|
||||
computedStyles.getPropertyValue("--state-climate-cool-color")
|
||||
);
|
||||
// The "cooling" series uses steppedArea to shade the area below the current
|
||||
@ -268,22 +260,19 @@ class StateHistoryChartLine extends LitElement {
|
||||
`${this.hass.localize("ui.card.climate.target_temperature_mode", {
|
||||
name: name,
|
||||
mode: this.hass.localize("ui.card.climate.high"),
|
||||
})}`,
|
||||
true
|
||||
})}`
|
||||
);
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.climate.target_temperature_mode", {
|
||||
name: name,
|
||||
mode: this.hass.localize("ui.card.climate.low"),
|
||||
})}`,
|
||||
true
|
||||
})}`
|
||||
);
|
||||
} else {
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.climate.target_temperature_entity", {
|
||||
name: name,
|
||||
})}`,
|
||||
true
|
||||
})}`
|
||||
);
|
||||
}
|
||||
|
||||
@ -318,14 +307,12 @@ class StateHistoryChartLine extends LitElement {
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.humidifier.target_humidity_entity", {
|
||||
name: name,
|
||||
})}`,
|
||||
true
|
||||
})}`
|
||||
);
|
||||
addDataSet(
|
||||
`${this.hass.localize("ui.card.humidifier.on_entity", {
|
||||
name: name,
|
||||
})}`,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
@ -337,9 +324,7 @@ class StateHistoryChartLine extends LitElement {
|
||||
pushData(new Date(entityState.last_changed), series);
|
||||
});
|
||||
} else {
|
||||
// Only interpolate for sensors
|
||||
const isStep = domain !== "sensor";
|
||||
addDataSet(name, isStep);
|
||||
addDataSet(name);
|
||||
|
||||
let lastValue: number;
|
||||
let lastDate: Date;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import "@material/mwc-textfield";
|
||||
import type { TextField } from "@material/mwc-textfield";
|
||||
import "@material/mwc-slider";
|
||||
import type { Slider } from "@material/mwc-slider";
|
||||
import {
|
||||
css,
|
||||
@ -14,6 +13,7 @@ import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { HaCheckbox } from "../ha-checkbox";
|
||||
import { HaFormElement, HaFormIntegerData, HaFormIntegerSchema } from "./types";
|
||||
import "../ha-slider";
|
||||
|
||||
@customElement("ha-form-integer")
|
||||
export class HaFormInteger extends LitElement implements HaFormElement {
|
||||
@ -54,15 +54,16 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
||||
></ha-checkbox>
|
||||
`
|
||||
: ""}
|
||||
<mwc-slider
|
||||
discrete
|
||||
<ha-slider
|
||||
pin
|
||||
ignore-bar-touch
|
||||
.value=${this._value}
|
||||
.min=${this.schema.valueMin}
|
||||
.max=${this.schema.valueMax}
|
||||
.disabled=${this.disabled ||
|
||||
(this.data === undefined && this.schema.optional)}
|
||||
@change=${this._valueChanged}
|
||||
></mwc-slider>
|
||||
></ha-slider>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@ -168,7 +169,7 @@ export class HaFormInteger extends LitElement implements HaFormElement {
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
mwc-slider {
|
||||
ha-slider {
|
||||
flex: 1;
|
||||
}
|
||||
mwc-textfield {
|
||||
|
@ -104,7 +104,7 @@ export class HaForm extends LitElement implements HaFormElement {
|
||||
return css`
|
||||
.root {
|
||||
margin-bottom: -24px;
|
||||
overflow: auto;
|
||||
overflow: clip visible;
|
||||
}
|
||||
.root > * {
|
||||
display: block;
|
||||
|
@ -30,7 +30,6 @@ import { debounce } from "../../common/util/debounce";
|
||||
import { getSignedPath } from "../../data/auth";
|
||||
import type { MediaPlayerItem } from "../../data/media-player";
|
||||
import {
|
||||
browseLocalMediaPlayer,
|
||||
browseMediaPlayer,
|
||||
BROWSER_PLAYER,
|
||||
MediaClassBrowserSettings,
|
||||
@ -50,6 +49,7 @@ import "../ha-circular-progress";
|
||||
import "../ha-icon-button";
|
||||
import "../ha-svg-icon";
|
||||
import "../ha-fab";
|
||||
import { browseLocalMediaPlayer } from "../../data/media_source";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -417,6 +417,9 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
if (!changedProps.has("navigateIds")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._setError(undefined);
|
||||
|
||||
const oldNavigateIds = changedProps.get("navigateIds") as
|
||||
| this["navigateIds"]
|
||||
| undefined;
|
||||
|
@ -55,7 +55,13 @@ export const computeDeviceName = (
|
||||
device.name_by_user ||
|
||||
device.name ||
|
||||
(entities && fallbackDeviceName(hass, entities)) ||
|
||||
hass.localize("ui.panel.config.devices.unnamed_device");
|
||||
hass.localize(
|
||||
"ui.panel.config.devices.unnamed_device",
|
||||
"type",
|
||||
hass.localize(
|
||||
`ui.panel.config.devices.type.${device.entry_type || "device"}`
|
||||
)
|
||||
);
|
||||
|
||||
export const devicesInArea = (devices: DeviceRegistryEntry[], areaId: string) =>
|
||||
devices.filter((device) => device.area_id === areaId);
|
||||
|
@ -185,15 +185,6 @@ export const browseMediaPlayer = (
|
||||
media_content_type: mediaContentType,
|
||||
});
|
||||
|
||||
export const browseLocalMediaPlayer = (
|
||||
hass: HomeAssistant,
|
||||
mediaContentId?: string
|
||||
): Promise<MediaPlayerItem> =>
|
||||
hass.callWS<MediaPlayerItem>({
|
||||
type: "media_source/browse_media",
|
||||
media_content_id: mediaContentId,
|
||||
});
|
||||
|
||||
export const getCurrentProgress = (stateObj: MediaPlayerEntity): number => {
|
||||
let progress = stateObj.attributes.media_position!;
|
||||
|
||||
@ -321,8 +312,8 @@ export const computeMediaControls = (
|
||||
return buttons.length > 0 ? buttons : undefined;
|
||||
};
|
||||
|
||||
export const formatMediaTime = (seconds: number): string => {
|
||||
if (!seconds) {
|
||||
export const formatMediaTime = (seconds: number | undefined): string => {
|
||||
if (seconds === undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
import { MediaPlayerItem } from "./media-player";
|
||||
|
||||
export interface ResolvedMediaSource {
|
||||
url: string;
|
||||
@ -13,3 +14,12 @@ export const resolveMediaSource = (
|
||||
type: "media_source/resolve_media",
|
||||
media_content_id,
|
||||
});
|
||||
|
||||
export const browseLocalMediaPlayer = (
|
||||
hass: HomeAssistant,
|
||||
mediaContentId?: string
|
||||
): Promise<MediaPlayerItem> =>
|
||||
hass.callWS<MediaPlayerItem>({
|
||||
type: "media_source/browse_media",
|
||||
media_content_id: mediaContentId,
|
||||
});
|
||||
|
@ -116,15 +116,14 @@ class DataEntryFlowDialog extends LitElement {
|
||||
params.continueFlowId
|
||||
);
|
||||
} catch (err: any) {
|
||||
this._step = undefined;
|
||||
this._params = undefined;
|
||||
this.closeDialog();
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.error"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
text: `${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.could_not_load"
|
||||
),
|
||||
)}: ${err.message || err.body}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -177,6 +176,7 @@ class DataEntryFlowDialog extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
this._loading = undefined;
|
||||
this._step = undefined;
|
||||
this._params = undefined;
|
||||
this._devices = undefined;
|
||||
@ -372,15 +372,14 @@ class DataEntryFlowDialog extends LitElement {
|
||||
try {
|
||||
step = await this._params!.flowConfig.createFlow(this.hass, handler);
|
||||
} catch (err: any) {
|
||||
this._step = undefined;
|
||||
this._params = undefined;
|
||||
this.closeDialog();
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.error"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
text: `${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.could_not_load"
|
||||
),
|
||||
)}: ${err.message || err.body}`,
|
||||
});
|
||||
return;
|
||||
} finally {
|
||||
@ -405,6 +404,15 @@ class DataEntryFlowDialog extends LitElement {
|
||||
this._loading = "loading_step";
|
||||
try {
|
||||
this._step = await step;
|
||||
} catch (err: any) {
|
||||
this.closeDialog();
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.integrations.config_flow.error"
|
||||
),
|
||||
text: err.message || err.body,
|
||||
});
|
||||
return;
|
||||
} finally {
|
||||
this._loading = undefined;
|
||||
}
|
||||
|
@ -185,13 +185,14 @@ export class QuickBar extends LitElement {
|
||||
.label=${this.hass!.localize("ui.common.clear")}
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button>`}
|
||||
${this._narrow &&
|
||||
html`
|
||||
<mwc-button
|
||||
.label=${this.hass!.localize("ui.common.close")}
|
||||
@click=${this.closeDialog}
|
||||
></mwc-button>
|
||||
`}
|
||||
${this._narrow
|
||||
? html`
|
||||
<mwc-button
|
||||
.label=${this.hass!.localize("ui.common.close")}
|
||||
@click=${this.closeDialog}
|
||||
></mwc-button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { setPassiveTouchGestures } from "@polymer/polymer/lib/utils/settings";
|
||||
import {
|
||||
setPassiveTouchGestures,
|
||||
setCancelSyntheticClickEvents,
|
||||
} from "@polymer/polymer/lib/utils/settings";
|
||||
import "../layouts/home-assistant";
|
||||
import "../resources/ha-style";
|
||||
import "../resources/roboto";
|
||||
import "../util/legacy-support";
|
||||
|
||||
setPassiveTouchGestures(true);
|
||||
setCancelSyntheticClickEvents(false);
|
||||
|
@ -1,11 +1,14 @@
|
||||
// Compat needs to be first import
|
||||
import "../resources/compatibility";
|
||||
import { setCancelSyntheticClickEvents } from "@polymer/polymer/lib/utils/settings";
|
||||
import "../auth/ha-authorize";
|
||||
import "../resources/ha-style";
|
||||
import "../resources/roboto";
|
||||
import "../resources/safari-14-attachshadow-patch";
|
||||
import "../resources/array.flat.polyfill";
|
||||
|
||||
setCancelSyntheticClickEvents(false);
|
||||
|
||||
/* polyfill for paper-dropdown */
|
||||
setTimeout(
|
||||
() => import("web-animations-js/web-animations-next-lite.min"),
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Compat needs to be first import
|
||||
import "../resources/compatibility";
|
||||
import { setCancelSyntheticClickEvents } from "@polymer/polymer/lib/utils/settings";
|
||||
import "../resources/safari-14-attachshadow-patch";
|
||||
|
||||
import { PolymerElement } from "@polymer/polymer";
|
||||
@ -15,6 +16,8 @@ import { createCustomPanelElement } from "../util/custom-panel/create-custom-pan
|
||||
import { loadCustomPanel } from "../util/custom-panel/load-custom-panel";
|
||||
import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-properties";
|
||||
|
||||
setCancelSyntheticClickEvents(false);
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
loadES5Adapter: () => Promise<unknown>;
|
||||
@ -47,7 +50,7 @@ function initialize(
|
||||
) {
|
||||
const style = document.createElement("style");
|
||||
|
||||
style.innerHTML = `body { margin:0; }
|
||||
style.innerHTML = `body { margin:0; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #111111;
|
||||
|
@ -1,11 +1,14 @@
|
||||
// Compat needs to be first import
|
||||
import "../resources/compatibility";
|
||||
import { setCancelSyntheticClickEvents } from "@polymer/polymer/lib/utils/settings";
|
||||
import "../onboarding/ha-onboarding";
|
||||
import "../resources/ha-style";
|
||||
import "../resources/roboto";
|
||||
import "../resources/safari-14-attachshadow-patch";
|
||||
import "../resources/array.flat.polyfill";
|
||||
|
||||
setCancelSyntheticClickEvents(false);
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
stepsPromise: Promise<Response>;
|
||||
|
@ -315,7 +315,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
? html`
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations"
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
)}
|
||||
>
|
||||
${groupedAutomations?.length
|
||||
@ -362,7 +362,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
? html`
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
)}
|
||||
>
|
||||
${groupedScenes?.length
|
||||
@ -401,7 +401,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
? html`
|
||||
<ha-card
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts"
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
)}
|
||||
>
|
||||
${groupedScripts?.length
|
||||
|
@ -137,6 +137,7 @@ export class CloudGooglePref extends LitElement {
|
||||
"ui.panel.config.cloud.account.google.enter_pin_info"
|
||||
)}
|
||||
<mwc-textfield
|
||||
id="google_secure_devices_pin"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.google.devices_pin"
|
||||
)}
|
||||
|
@ -3,7 +3,14 @@ import "@material/mwc-list/mwc-list-item";
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../components/ha-card";
|
||||
@ -26,6 +33,7 @@ import "./ha-config-navigation";
|
||||
import "./ha-config-updates";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { showToast } from "../../../util/toast";
|
||||
|
||||
@customElement("ha-config-dashboard")
|
||||
class HaConfigDashboard extends LitElement {
|
||||
@ -43,6 +51,8 @@ class HaConfigDashboard extends LitElement {
|
||||
|
||||
@property() public showAdvanced!: boolean;
|
||||
|
||||
private _notifyUpdates = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-app-layout>
|
||||
@ -129,6 +139,26 @@ class HaConfigDashboard extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
protected override updated(changedProps: PropertyValues): void {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!changedProps.has("supervisorUpdates") || !this._notifyUpdates) {
|
||||
return;
|
||||
}
|
||||
this._notifyUpdates = false;
|
||||
if (this.supervisorUpdates?.length) {
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.config.updates.updates_refreshed"
|
||||
),
|
||||
});
|
||||
} else {
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.panel.config.updates.no_new_updates"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _showQuickBar(): void {
|
||||
showQuickBar(this, {
|
||||
commandMode: true,
|
||||
@ -140,6 +170,7 @@ class HaConfigDashboard extends LitElement {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
this._notifyUpdates = true;
|
||||
await refreshSupervisorAvailableUpdates(this.hass);
|
||||
fireEvent(this, "ha-refresh-supervisor");
|
||||
return;
|
||||
|
@ -23,7 +23,15 @@ export class HaDeviceCard extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card
|
||||
.header=${this.hass.localize("ui.panel.config.devices.device_info")}
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.device_info",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
this.device.entry_type || "device"
|
||||
}_heading`
|
||||
)
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this.device.model
|
||||
|
@ -82,12 +82,26 @@ class DialogDeviceRegistryDetail extends LitElement {
|
||||
</ha-switch>
|
||||
<div>
|
||||
<div>
|
||||
${this.hass.localize("ui.panel.config.devices.enabled_label")}
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.enabled_label",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
${this._disabledBy && this._disabledBy !== "user"
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.enabled_cause",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
),
|
||||
"cause",
|
||||
this.hass.localize(
|
||||
`config_entry.disabled_by.${this._disabledBy}`
|
||||
|
@ -296,6 +296,10 @@ export class HaConfigDevicePage extends LitElement {
|
||||
<ha-alert alert-type="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.enabled_cause",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${device.entry_type || "device"}`
|
||||
),
|
||||
"cause",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.disabled_by.${device.disabled_by}`
|
||||
@ -485,17 +489,29 @@ export class HaConfigDevicePage extends LitElement {
|
||||
<ha-card>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations"
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showAutomationDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create_disabled"
|
||||
"ui.panel.config.devices.automation.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create"
|
||||
"ui.panel.config.devices.automation.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
@ -547,6 +563,12 @@ export class HaConfigDevicePage extends LitElement {
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
@ -561,7 +583,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
<ha-card>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
)}
|
||||
|
||||
<ha-icon-button
|
||||
@ -569,10 +591,22 @@ export class HaConfigDevicePage extends LitElement {
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create_disabled"
|
||||
"ui.panel.config.devices.scene.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.scene.create"
|
||||
"ui.panel.config.devices.scene.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
@ -627,6 +661,12 @@ export class HaConfigDevicePage extends LitElement {
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
@ -641,17 +681,29 @@ export class HaConfigDevicePage extends LitElement {
|
||||
<ha-card>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts"
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
)}
|
||||
<ha-icon-button
|
||||
@click=${this._showScriptDialog}
|
||||
.disabled=${device.disabled_by}
|
||||
.label=${device.disabled_by
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.devices.script.create_disabled"
|
||||
"ui.panel.config.devices.script.create_disabled",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.script.create"
|
||||
"ui.panel.config.devices.script.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
@ -685,6 +737,12 @@ export class HaConfigDevicePage extends LitElement {
|
||||
"name",
|
||||
this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts"
|
||||
),
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
@ -1065,6 +1123,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.column > *:not(:first-child) {
|
||||
|
@ -338,7 +338,7 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
${this.hass.localize("ui.panel.config.devices.disabled")}
|
||||
</paper-tooltip>
|
||||
</div>`
|
||||
: "",
|
||||
: "—",
|
||||
};
|
||||
}
|
||||
return columns;
|
||||
|
@ -42,7 +42,7 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { showDeviceRegistryDetailDialog } from "../devices/device-registry-detail/show-dialog-device-registry-detail";
|
||||
|
||||
const OVERRIDE_DEVICE_CLASSES = {
|
||||
cover: ["window", "door", "garage"],
|
||||
cover: ["window", "door", "garage", "gate"],
|
||||
binary_sensor: ["window", "door", "garage_door", "opening"],
|
||||
};
|
||||
|
||||
|
@ -237,7 +237,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
template: (disabled_by) =>
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.disabled_by.${disabled_by}`
|
||||
) || disabled_by,
|
||||
) ||
|
||||
disabled_by ||
|
||||
"—",
|
||||
},
|
||||
status: {
|
||||
title: this.hass.localize(
|
||||
|
@ -21,6 +21,7 @@ import type { PageNavigation } from "../../../../../layouts/hass-tabs-subpage";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import "../../../ha-config-section";
|
||||
import "../../../../../components/ha-alert";
|
||||
|
||||
export const ozwTabs: PageNavigation[] = [];
|
||||
|
||||
@ -64,6 +65,30 @@ class OZWConfigDashboard extends LitElement {
|
||||
.tabs=${ozwTabs}
|
||||
back-path="/config/integrations"
|
||||
>
|
||||
<ha-alert
|
||||
alert-type="warning"
|
||||
title="This integration will stop working soon"
|
||||
>
|
||||
The OpenZWave integration is deprecated and will no longer receive any
|
||||
updates. The technical dependencies will render this integration
|
||||
unusable in the near future. We strongly advise you to migrate to the
|
||||
new
|
||||
<a
|
||||
href="https://www.home-assistant.io/integrations/zwave_js"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>Z-Wave JS integration</a
|
||||
>.
|
||||
<a
|
||||
slot="action"
|
||||
href="https://alerts.home-assistant.io/#ozw.markdown"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<mwc-button>learn more</mwc-button>
|
||||
</a>
|
||||
</ha-alert>
|
||||
|
||||
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
|
||||
<div slot="header">
|
||||
${this.hass.localize("ui.panel.config.ozw.select_instance.header")}
|
||||
@ -162,6 +187,13 @@ class OZWConfigDashboard extends LitElement {
|
||||
:host([narrow]) ha-config-section {
|
||||
margin-top: -20px;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin: 16px;
|
||||
}
|
||||
ha-alert a {
|
||||
text-decoration: none;
|
||||
}
|
||||
ha-card {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { computeStateName } from "../../../../../common/entity/compute_state_nam
|
||||
import { sortStatesByName } from "../../../../../common/entity/states_sort_by_name";
|
||||
import "../../../../../components/buttons/ha-call-service-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-icon";
|
||||
import "../../../../../components/ha-icon-button";
|
||||
import "../../../../../components/ha-icon-button-arrow-prev";
|
||||
@ -43,6 +44,14 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin: 16px;
|
||||
}
|
||||
ha-alert a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 24px;
|
||||
}
|
||||
@ -101,6 +110,30 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
</app-toolbar>
|
||||
</app-header>
|
||||
|
||||
<ha-alert
|
||||
alert-type="warning"
|
||||
title="This integration will stop working soon"
|
||||
>
|
||||
This Z-Wave integration is deprecated and will no longer receive any
|
||||
updates. The technical dependencies will render this integration
|
||||
unusable in the near future. We strongly advise you to migrate to the
|
||||
new
|
||||
<a
|
||||
href="https://www.home-assistant.io/integrations/zwave_js"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>Z-Wave JS integration</a
|
||||
>.
|
||||
<a
|
||||
slot="action"
|
||||
href="https://alerts.home-assistant.io/#zwave.markdown"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<mwc-button>learn more</mwc-button>
|
||||
</a>
|
||||
</ha-alert>
|
||||
|
||||
<ha-config-section is-wide="[[isWide]]">
|
||||
<ha-card
|
||||
class="content"
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import memoize from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
|
||||
import { navigate } from "../../../../common/navigate";
|
||||
@ -53,9 +54,19 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
icon: {
|
||||
title: "",
|
||||
type: "icon",
|
||||
template: (icon) =>
|
||||
template: (icon, dashboard) =>
|
||||
icon
|
||||
? html` <ha-icon slot="item-icon" .icon=${icon}></ha-icon> `
|
||||
? html`
|
||||
<ha-icon
|
||||
slot="item-icon"
|
||||
.icon=${icon}
|
||||
style=${ifDefined(
|
||||
dashboard.iconColor
|
||||
? `color: ${dashboard.iconColor}`
|
||||
: undefined
|
||||
)}
|
||||
></ha-icon>
|
||||
`
|
||||
: html``,
|
||||
},
|
||||
title: {
|
||||
@ -64,7 +75,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
grows: true,
|
||||
template: (title, dashboard: any) => {
|
||||
const titleTemplate = html`
|
||||
@ -194,12 +204,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
url_path: "lovelace",
|
||||
mode: defaultMode,
|
||||
filename: defaultMode === "yaml" ? "ui-lovelace.yaml" : "",
|
||||
iconColor: "var(--primary-color)",
|
||||
},
|
||||
...dashboards.map((dashboard) => ({
|
||||
filename: "",
|
||||
...dashboard,
|
||||
default: defaultUrlPath === dashboard.url_path,
|
||||
})),
|
||||
];
|
||||
if (isComponentLoaded(this.hass, "energy")) {
|
||||
result.push({
|
||||
@ -209,8 +215,19 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
mode: "storage",
|
||||
url_path: "energy",
|
||||
filename: "",
|
||||
iconColor: "var(--label-badge-yellow)",
|
||||
});
|
||||
}
|
||||
|
||||
result.push(
|
||||
...dashboards
|
||||
.sort((a, b) => stringCompare(a.title, b.title))
|
||||
.map((dashboard) => ({
|
||||
filename: "",
|
||||
...dashboard,
|
||||
default: defaultUrlPath === dashboard.url_path,
|
||||
}))
|
||||
);
|
||||
return result;
|
||||
});
|
||||
|
||||
|
@ -51,7 +51,12 @@ export class EnergySetupWizard extends LitElement implements LovelaceCard {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<p>Step ${this._step + 1} of 5</p>
|
||||
<p>
|
||||
${this.hass.localize("ui.panel.energy.setup.step", {
|
||||
step: this._step + 1,
|
||||
steps: 5,
|
||||
})}
|
||||
</p>
|
||||
${this._step === 0
|
||||
? html`<ha-energy-grid-settings
|
||||
.hass=${this.hass}
|
||||
|
@ -170,6 +170,21 @@ export class HuiEnergyDevicesGraphCard
|
||||
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
|
||||
);
|
||||
|
||||
const startMinHour = addHours(energyData.start, -1);
|
||||
|
||||
Object.values(this._data).forEach((stat) => {
|
||||
// if the start of the first value is after the requested period, we have the first data point, and should add a zero point
|
||||
if (stat.length && new Date(stat[0].start) > startMinHour) {
|
||||
stat.unshift({
|
||||
...stat[0],
|
||||
start: startMinHour.toISOString(),
|
||||
end: startMinHour.toISOString(),
|
||||
sum: 0,
|
||||
state: 0,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const data: Array<ChartDataset<"bar", ParsedDataType<"bar">>["data"]> = [];
|
||||
const borderColor: string[] = [];
|
||||
const backgroundColor: string[] = [];
|
||||
|
@ -115,7 +115,9 @@ class BarMediaPlayer extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
const isBrowser = this.entityId === BROWSER_PLAYER;
|
||||
const stateObj = this._stateObj;
|
||||
const controls = !this.narrow
|
||||
const controls = !stateObj
|
||||
? undefined
|
||||
: !this.narrow
|
||||
? computeMediaControls(stateObj)
|
||||
: (stateObj.state === "playing" &&
|
||||
(supportsFeature(stateObj, SUPPORT_PAUSE) ||
|
||||
@ -144,13 +146,16 @@ class BarMediaPlayer extends LitElement {
|
||||
},
|
||||
]
|
||||
: [{}];
|
||||
const mediaDescription = computeMediaDescription(stateObj);
|
||||
const mediaDuration = formatMediaTime(stateObj!.attributes.media_duration!);
|
||||
const mediaTitleClean = cleanupMediaTitle(stateObj.attributes.media_title);
|
||||
const mediaDescription = stateObj ? computeMediaDescription(stateObj) : "";
|
||||
const mediaDuration = formatMediaTime(stateObj?.attributes.media_duration);
|
||||
const mediaTitleClean = cleanupMediaTitle(
|
||||
stateObj?.attributes.media_title || ""
|
||||
);
|
||||
|
||||
const mediaArt =
|
||||
stateObj.attributes.entity_picture_local ||
|
||||
stateObj.attributes.entity_picture;
|
||||
const mediaArt = stateObj
|
||||
? stateObj.attributes.entity_picture_local ||
|
||||
stateObj.attributes.entity_picture
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<div
|
||||
@ -216,7 +221,7 @@ class BarMediaPlayer extends LitElement {
|
||||
slot="trigger"
|
||||
.label=${this.narrow
|
||||
? ""
|
||||
: `${computeStateName(stateObj)}
|
||||
: `${stateObj ? computeStateName(stateObj) : this.entityId}
|
||||
`}
|
||||
>
|
||||
<ha-svg-icon
|
||||
@ -288,7 +293,7 @@ class BarMediaPlayer extends LitElement {
|
||||
if (
|
||||
!this._progressInterval &&
|
||||
this._showProgressBar &&
|
||||
stateObj.state === "playing"
|
||||
stateObj?.state === "playing"
|
||||
) {
|
||||
this._progressInterval = window.setInterval(
|
||||
() => this._updateProgressBar(),
|
||||
@ -296,21 +301,20 @@ class BarMediaPlayer extends LitElement {
|
||||
);
|
||||
} else if (
|
||||
this._progressInterval &&
|
||||
(!this._showProgressBar || stateObj.state !== "playing")
|
||||
(!this._showProgressBar || stateObj?.state !== "playing")
|
||||
) {
|
||||
clearInterval(this._progressInterval);
|
||||
this._progressInterval = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private get _stateObj(): MediaPlayerEntity {
|
||||
if (this._browserPlayer) {
|
||||
return this._browserPlayer.toStateObj();
|
||||
private get _stateObj(): MediaPlayerEntity | undefined {
|
||||
if (this.entityId === BROWSER_PLAYER) {
|
||||
return this._browserPlayer
|
||||
? this._browserPlayer.toStateObj()
|
||||
: BrowserMediaPlayer.idleStateObj();
|
||||
}
|
||||
return (
|
||||
(this.hass!.states[this.entityId] as MediaPlayerEntity | undefined) ||
|
||||
BrowserMediaPlayer.idleStateObj()
|
||||
);
|
||||
return this.hass!.states[this.entityId] as MediaPlayerEntity | undefined;
|
||||
}
|
||||
|
||||
private _openMoreInfo() {
|
||||
@ -328,6 +332,7 @@ class BarMediaPlayer extends LitElement {
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
return (
|
||||
stateObj &&
|
||||
(stateObj.state === "playing" || stateObj.state === "paused") &&
|
||||
"media_duration" in stateObj.attributes &&
|
||||
"media_position" in stateObj.attributes
|
||||
@ -343,19 +348,21 @@ class BarMediaPlayer extends LitElement {
|
||||
}
|
||||
|
||||
private _updateProgressBar(): void {
|
||||
if (!this._progressBar || !this._currentProgress) {
|
||||
const stateObj = this._stateObj;
|
||||
|
||||
if (!this._progressBar || !this._currentProgress || !stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._stateObj.attributes.media_duration) {
|
||||
if (!stateObj.attributes.media_duration) {
|
||||
this._progressBar.progress = 0;
|
||||
this._currentProgress.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const currentProgress = getCurrentProgress(this._stateObj);
|
||||
const currentProgress = getCurrentProgress(stateObj);
|
||||
this._progressBar.progress =
|
||||
currentProgress / this._stateObj.attributes.media_duration;
|
||||
currentProgress / stateObj.attributes.media_duration;
|
||||
|
||||
if (this._currentProgress) {
|
||||
this._currentProgress.innerHTML = formatMediaTime(currentProgress);
|
||||
|
@ -28,6 +28,7 @@ import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../types";
|
||||
import "./ha-bar-media-player";
|
||||
import { showWebBrowserPlayMediaDialog } from "./show-media-player-dialog";
|
||||
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
|
||||
|
||||
@customElement("ha-panel-media-browser")
|
||||
class PanelMediaBrowser extends LitElement {
|
||||
@ -112,6 +113,23 @@ class PanelMediaBrowser extends LitElement {
|
||||
.split("/");
|
||||
|
||||
if (routePlayer !== this._entityId) {
|
||||
// Detect if picked player doesn't exist (anymore)
|
||||
// Can happen if URL bookmarked or stored in local storage
|
||||
if (
|
||||
routePlayer !== BROWSER_PLAYER &&
|
||||
this.hass.states[routePlayer] === undefined
|
||||
) {
|
||||
navigate(`/media-browser/${BROWSER_PLAYER}`, { replace: true });
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.media-browser.error.player_not_exist",
|
||||
{
|
||||
name: routePlayer,
|
||||
}
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
this._entityId = routePlayer;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Caution before editing - For latest builds, this module is replaced with emptiness and thus not imported (see build-scripts/bundle.js)
|
||||
import "core-js";
|
||||
import "regenerator-runtime/runtime";
|
||||
import "lit/polyfill-support";
|
||||
|
@ -733,6 +733,7 @@
|
||||
"cover": {
|
||||
"door": "Door",
|
||||
"garage": "Garage door",
|
||||
"gate": "Gate",
|
||||
"window": "Window"
|
||||
}
|
||||
},
|
||||
@ -1011,6 +1012,8 @@
|
||||
"description": "You need to run the Home Assistant operating system to be able to check and install updates from the Home Assistant user interface."
|
||||
},
|
||||
"check_updates": "Check for updates",
|
||||
"no_new_updates": "No new updates found",
|
||||
"updates_refreshed": "Updates refreshed",
|
||||
"title": "{count} {count, plural,\n one {update}\n other {updates}\n}",
|
||||
"unable_to_fetch": "Unable to load updates",
|
||||
"version_available": "Version {version_available} is available",
|
||||
@ -2205,18 +2208,18 @@
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"add_prompt": "No {name} have been added using this device yet. You can add one by clicking the + button above.",
|
||||
"add_prompt": "No {name} have been added using this {type} yet. You can add one by clicking the + button above.",
|
||||
"caption": "Devices",
|
||||
"description": "Manage configured devices",
|
||||
"device_info": "Device info",
|
||||
"device_info": "{type} info",
|
||||
"edit_settings": "Edit settings",
|
||||
"unnamed_device": "Unnamed device",
|
||||
"unnamed_device": "Unnamed {type}",
|
||||
"unknown_error": "Unknown error",
|
||||
"name": "Name",
|
||||
"update": "Update",
|
||||
"no_devices": "No devices",
|
||||
"enabled_label": "Enable device",
|
||||
"enabled_cause": "The device is disabled by {cause}.",
|
||||
"enabled_label": "Enable {type}",
|
||||
"enabled_cause": "The {type} is disabled by {cause}.",
|
||||
"disabled_by": {
|
||||
"user": "User",
|
||||
"integration": "Integration",
|
||||
@ -2226,12 +2229,19 @@
|
||||
"open_configuration_url_device": "Visit device",
|
||||
"open_configuration_url_service": "Visit service",
|
||||
"download_diagnostics": "Download diagnostics",
|
||||
"type": {
|
||||
"device_heading": "Device",
|
||||
"device": "device",
|
||||
"service_heading": "Service",
|
||||
"service": "service"
|
||||
},
|
||||
"automation": {
|
||||
"automations": "Automations",
|
||||
"automations_heading": "Automations",
|
||||
"automations": "automations",
|
||||
"no_automations": "No automations",
|
||||
"unknown_automation": "Unknown automation",
|
||||
"create": "Create automation with device",
|
||||
"create_disable": "Can't create automation with disabled device",
|
||||
"create": "Create automation with {type}",
|
||||
"create_disable": "Can't create automation with disabled {type}",
|
||||
"triggers": {
|
||||
"caption": "Do something when…",
|
||||
"no_triggers": "No triggers",
|
||||
@ -2250,19 +2260,21 @@
|
||||
"no_device_automations": "There are no automations available for this device."
|
||||
},
|
||||
"script": {
|
||||
"scripts": "Scripts",
|
||||
"scripts_heading": "Scripts",
|
||||
"scripts": "scripts",
|
||||
"no_scripts": "No scripts",
|
||||
"create": "Create script with device",
|
||||
"create_disable": "Can't create script with disabled device"
|
||||
"create": "Create script with {type}",
|
||||
"create_disable": "Can't create script with disabled {type}"
|
||||
},
|
||||
"scene": {
|
||||
"scenes": "Scenes",
|
||||
"scenes_heading": "Scenes",
|
||||
"scenes": "scenes",
|
||||
"no_scenes": "No scenes",
|
||||
"create": "Create scene with device",
|
||||
"create_disable": "Can't create scene with disabled device"
|
||||
"create": "Create scene with {type}",
|
||||
"create_disable": "Can't create scene with disabled {type}"
|
||||
},
|
||||
"cant_edit": "You can only edit items that are created in the UI.",
|
||||
"device_not_found": "Device not found.",
|
||||
"device_not_found": "Device / service not found.",
|
||||
"entities": {
|
||||
"entities": "Entities",
|
||||
"control": "Controls",
|
||||
@ -2274,8 +2286,6 @@
|
||||
"hide_disabled": "Hide disabled",
|
||||
"disabled_entities": "+{count} {count, plural,\n one {disabled entity}\n other {disabled entities}\n}"
|
||||
},
|
||||
"scripts": "Scripts",
|
||||
"scenes": "Scenes",
|
||||
"confirm_rename_entity_ids": "Do you also want to rename the entity IDs of your entities?",
|
||||
"confirm_rename_entity_ids_warning": "This will not change any configuration (like automations, scripts, scenes, dashboards) that is currently using these entities! You will have to update them yourself to use the new entity IDs!",
|
||||
"confirm_disable_config_entry": "There are no more devices for the config entry {entry_name}, do you want to instead disable the config entry?",
|
||||
@ -3644,6 +3654,11 @@
|
||||
"delete_prompt": "Delete this message?",
|
||||
"delete_button": "Delete"
|
||||
},
|
||||
"media-browser": {
|
||||
"error": {
|
||||
"player_not_exist": "Media player {name} does not exist"
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"edit_zones": "Edit Zones"
|
||||
},
|
||||
@ -4096,7 +4111,8 @@
|
||||
"setup": {
|
||||
"next": "Next",
|
||||
"back": "Back",
|
||||
"done": "Show me my energy dashboard!"
|
||||
"done": "Show me my energy dashboard!",
|
||||
"step": "Step {step} of {steps}"
|
||||
},
|
||||
"charts": {
|
||||
"stat_house_energy_meter": "Total energy consumption",
|
||||
|
44
yarn.lock
44
yarn.lock
@ -1958,10 +1958,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lit/reactive-element@npm:1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@lit/reactive-element@npm:1.0.1"
|
||||
checksum: 82f8eb195acb766413fa37dafab8dc853547e5fbb901318d9911b3f9410a15ceea37c9a4b0954ab37710e91140af243148af9f72ec3bd14fe71e1d03faaaad7a
|
||||
"@lit/reactive-element@npm:1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "@lit/reactive-element@npm:1.2.1"
|
||||
checksum: 58f1b62c54b1899180b11cd44009ee91ac35099f9016259d3b9cc2f969fc920ab7e7ec32a816986ce89a27c632e25568542c93fdfed6730c19c850f7db0ba4cf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9187,7 +9187,7 @@ fsevents@^1.2.7:
|
||||
leaflet: ^1.7.1
|
||||
leaflet-draw: ^1.0.4
|
||||
lint-staged: ^11.1.2
|
||||
lit: ^2.0.2
|
||||
lit: ^2.1.2
|
||||
lit-analyzer: ^1.2.1
|
||||
lit-vaadin-helpers: ^0.2.1
|
||||
lodash.template: ^4.5.0
|
||||
@ -10776,22 +10776,22 @@ fsevents@^1.2.7:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lit-element@npm:3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "lit-element@npm:3.0.1"
|
||||
"lit-element@npm:3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "lit-element@npm:3.1.2"
|
||||
dependencies:
|
||||
"@lit/reactive-element": ^1.0.0
|
||||
lit-html: ^2.0.0
|
||||
checksum: 3735cd1b96efb44f1ecdcb07406604d7c6feeab07f81cfc904a0f9ab806fab1211e8bf68827513b12e12e61448e3cd6508664d433abd3f0c5c4408b0a6b2d7a6
|
||||
"@lit/reactive-element": ^1.1.0
|
||||
lit-html: ^2.1.0
|
||||
checksum: 56ae568369af7c51cfe7187136ffb0782308ed3a12aa664085bd6761ff89fb60d3ac2ef286ce15154a2eb179d89f8655f7adaa18b8c083091c03dc75dd2ebf16
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lit-html@npm:2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "lit-html@npm:2.0.1"
|
||||
"lit-html@npm:2.1.2":
|
||||
version: 2.1.2
|
||||
resolution: "lit-html@npm:2.1.2"
|
||||
dependencies:
|
||||
"@types/trusted-types": ^2.0.2
|
||||
checksum: 7ee9e909ec59009539d5b2d7bd07ceb6e182ed5c6535f36da5265dd2f5dc39f9e5f445e8272953a26948ff5724cf110836c792c439883527a2a3b46ecdbbb395
|
||||
checksum: 0c87d83b3577dbb0a2c50743296b6600a6872eac2f23b48da7ba3e604b8c72a8b0e1e48cfe0e00dd6f4ca921ab57f97e20709756f2115077478ffb05efa6cea0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10804,14 +10804,14 @@ fsevents@^1.2.7:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lit@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "lit@npm:2.0.2"
|
||||
"lit@npm:^2.1.2":
|
||||
version: 2.1.2
|
||||
resolution: "lit@npm:2.1.2"
|
||||
dependencies:
|
||||
"@lit/reactive-element": ^1.0.0
|
||||
lit-element: ^3.0.0
|
||||
lit-html: ^2.0.0
|
||||
checksum: 52a04b25164da1683c7295b305087794f175165cd1561e03f0c50ae998823f0e26101c82add05dea773e35472fbe3ed84486a4685294897f588d126fe8419e05
|
||||
"@lit/reactive-element": ^1.1.0
|
||||
lit-element: ^3.1.0
|
||||
lit-html: ^2.1.0
|
||||
checksum: dc3d6f30d508e48ad665a5777383c26055ae6514a7bd6a5745ac75cfeeeff8db49aa3b0f32db1a19e43bd7eec2bccd7db8523d5ed445ca0035fe37fddd9fb646
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user