Compare commits

..

1 Commits

Author SHA1 Message Date
Thomas Lovén
bda951e6d1 POC 2020-09-14 14:25:40 +02:00
83 changed files with 1251 additions and 2559 deletions

View File

@@ -153,7 +153,7 @@ export class HassioUpdate extends LitElement {
item.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: `Update ${item.name}`,
text: `Are you sure you want to update ${item.name} to version ${item.version}?`,
text: `Are you sure you want to upgrade ${item.name} to version ${item.version}?`,
confirmText: "update",
dismissText: "cancel",
});

View File

@@ -79,7 +79,6 @@ class HassioSnapshots extends LitElement {
},
{ slug: "ssl", name: "SSL", checked: true },
{ slug: "share", name: "Share", checked: true },
{ slug: "media", name: "Media", checked: true },
{ slug: "addons/local", name: "Local add-ons", checked: true },
];
@@ -242,7 +241,7 @@ class HassioSnapshots extends LitElement {
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this.refreshData();
this._updateSnapshots();
}
protected updated(changedProps: PropertyValues) {

View File

@@ -14,6 +14,7 @@ import {
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import { atLeastVersion } from "../../../src/common/config/version";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
@@ -84,7 +85,8 @@ class HassioHostInfo extends LitElement {
</mwc-button>
</ha-settings-row>`
: ""}
${this.hostInfo.features.includes("network")
${this.hostInfo.features.includes("network") &&
atLeastVersion(this.hass.config.version, 0, 115)
? html` <ha-settings-row>
<span slot="heading">
IP address

View File

@@ -213,7 +213,7 @@ class HassioSupervisorInfo extends LitElement {
const confirmed = await showConfirmationDialog(this, {
title: "Update supervisor",
text: `Are you sure you want to update supervisor to version ${this.supervisorInfo.version_latest}?`,
text: `Are you sure you want to upgrade supervisor to version ${this.supervisorInfo.version_latest}?`,
confirmText: "update",
dismissText: "cancel",
});

View File

@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
version="20200915.0",
version="20200912.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",

View File

@@ -1,14 +1,14 @@
import { darkStyles, derivedStyles } from "../../resources/styles";
import { derivedStyles, darkStyles } from "../../resources/styles";
import { HomeAssistant, Theme } from "../../types";
import {
hex2rgb,
lab2hex,
lab2rgb,
rgb2hex,
rgb2lab,
lab2rgb,
lab2hex,
} from "../color/convert-color";
import { labBrighten, labDarken } from "../color/lab";
import { rgbContrast } from "../color/rgb";
import { labDarken, labBrighten } from "../color/lab";
interface ProcessedTheme {
keys: { [key: string]: "" };
@@ -105,12 +105,12 @@ const processTheme = (
const keys = {};
for (const key of Object.keys(combinedTheme)) {
const prefixedKey = `--${key}`;
const value = String(combinedTheme[key]);
const value = String(combinedTheme[key]!);
styles[prefixedKey] = value;
keys[prefixedKey] = "";
// Try to create a rgb value for this key if it is not a var
if (!value.startsWith("#")) {
if (value.startsWith("#")) {
// Can't convert non hex value
continue;
}

View File

@@ -11,18 +11,11 @@ import "./ha-progress-button";
class HaCallServiceButton extends EventsMixin(PolymerElement) {
static get template() {
return html`
<style>
ha-progress-button {
width: 100%;
}
</style>
<ha-progress-button
id="progress"
progress="[[progress]]"
on-click="buttonTapped"
tabindex="0"
raised="[[raised]]"
outlined="[[outlined]]"
><slot></slot
></ha-progress-button>
`;
@@ -55,16 +48,6 @@ class HaCallServiceButton extends EventsMixin(PolymerElement) {
confirmation: {
type: String,
},
raised: {
type: Boolean,
value: false,
},
outlined: {
type: Boolean,
value: false,
},
};
}

View File

@@ -21,15 +21,12 @@ class HaProgressButton extends LitElement {
@property({ type: Boolean }) public raised = false;
@property({ type: Boolean }) public outlined = false;
@query("mwc-button") private _button?: Button;
public render(): TemplateResult {
return html`
<mwc-button
?raised=${this.raised}
?outlined=${this.outlined}
.disabled=${this.disabled || this.progress}
@click=${this._buttonTapped}
>
@@ -74,7 +71,6 @@ class HaProgressButton extends LitElement {
mwc-button {
transition: all 1s;
width: 100%;
}
mwc-button.success {

View File

@@ -1,16 +1,17 @@
import "@material/mwc-button";
import "@material/mwc-menu";
import type { Corner, Menu } from "@material/mwc-menu";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
query,
TemplateResult,
LitElement,
CSSResult,
css,
query,
property,
} from "lit-element";
import "@material/mwc-button";
import "@material/mwc-menu";
import type { Menu, Corner } from "@material/mwc-menu";
import "./ha-icon-button";
@customElement("ha-button-menu")
@@ -21,8 +22,6 @@ export class HaButtonMenu extends LitElement {
@property({ type: Boolean }) public activatable = false;
@property({ type: Boolean }) public disabled = false;
@query("mwc-menu") private _menu?: Menu;
public get items() {
@@ -49,9 +48,6 @@ export class HaButtonMenu extends LitElement {
}
private _handleClick(): void {
if (this.disabled) {
return;
}
this._menu!.anchor = this;
this._menu!.show();
}

View File

@@ -32,9 +32,6 @@ class HaCameraStream extends LitElement {
@property({ type: Boolean, attribute: "muted" })
public muted = false;
@property({ type: Boolean, attribute: "allow-exoplayer" })
public allowExoPlayer = false;
// We keep track if we should force MJPEG with a string
// that way it automatically resets if we change entity.
@internalProperty() private _forceMJPEG?: string;
@@ -64,7 +61,6 @@ class HaCameraStream extends LitElement {
<ha-hls-player
autoplay
playsinline
.allowExoPlayer=${this.allowExoPlayer}
.muted=${this.muted}
.controls=${this.controls}
.hass=${this.hass}

View File

@@ -12,6 +12,7 @@ import {
} from "lit-element";
import { fireEvent } from "../common/dom/fire_event";
import { nextRender } from "../common/util/render-status";
import { getExternalConfig } from "../external_app/external_config";
import type { HomeAssistant } from "../types";
type HLSModule = typeof import("hls.js");
@@ -34,9 +35,6 @@ class HaHLSPlayer extends LitElement {
@property({ type: Boolean, attribute: "playsinline" })
public playsInline = false;
@property({ type: Boolean, attribute: "allow-exoplayer" })
public allowExoPlayer = false;
@query("video") private _videoEl!: HTMLVideoElement;
@internalProperty() private _attached = false;
@@ -93,7 +91,11 @@ class HaHLSPlayer extends LitElement {
}
private async _getUseExoPlayer(): Promise<boolean> {
return false;
if (!this.hass!.auth.external) {
return false;
}
const externalConfig = await getExternalConfig(this.hass!.auth.external);
return externalConfig && externalConfig.hasExoPlayer;
}
private async _startHls(): Promise<void> {
@@ -135,10 +137,7 @@ class HaHLSPlayer extends LitElement {
this._videoEl.style.visibility = "hidden";
await this.hass!.auth.external!.sendMessage({
type: "exoplayer/play_hls",
payload: {
url: new URL(url, window.location.href).toString(),
muted: this.muted,
},
payload: new URL(url, window.location.href).toString(),
});
}

View File

@@ -159,6 +159,8 @@ const computePanels = memoizeOne(
let Sortable;
let sortStyles: CSSResult;
@customElement("ha-sidebar")
class HaSidebar extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -169,12 +171,12 @@ class HaSidebar extends LitElement {
@property({ type: Boolean, reflect: true }) public expanded = false;
@property({ type: Boolean }) public editMode = false;
@internalProperty() private _externalConfig?: ExternalConfig;
@internalProperty() private _notifications?: PersistentNotification[];
@internalProperty() private _editMode = false;
// property used only in css
// @ts-ignore
@property({ type: Boolean, reflect: true }) public rtl = false;
@@ -225,12 +227,19 @@ class HaSidebar extends LitElement {
}
return html`
${this._editMode
? html`
<style>
${sortStyles?.cssText}
</style>
`
: ""}
<div
class="menu"
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: !this.editMode,
disabled: this.editMode,
hasHold: !this._editMode,
disabled: this._editMode,
})}
>
${!this.narrow
@@ -248,7 +257,7 @@ class HaSidebar extends LitElement {
`
: ""}
<div class="title">
${this.editMode
${this._editMode
? html`<mwc-button outlined @click=${this._closeEditMode}>
${hass.localize("ui.sidebar.done")}
</mwc-button>`
@@ -264,7 +273,7 @@ class HaSidebar extends LitElement {
@scroll=${this._listboxScroll}
@keydown=${this._listboxKeydown}
>
${this.editMode
${this._editMode
? html`<div id="sortable">
${guard([this._hiddenPanels, this._renderEmptySortable], () =>
this._renderEmptySortable
@@ -274,7 +283,7 @@ class HaSidebar extends LitElement {
</div>`
: this._renderPanels(beforeSpacer)}
<div class="spacer" disabled></div>
${this.editMode && this._hiddenPanels.length
${this._editMode && this._hiddenPanels.length
? html`
${this._hiddenPanels.map((url) => {
const panel = this.hass.panels[url];
@@ -298,7 +307,7 @@ class HaSidebar extends LitElement {
: hass.localize(`panel.${panel.title}`) ||
panel.title}</span
>
<mwc-icon-button class="show-panel">
<mwc-icon-button class="hide-panel">
<ha-svg-icon .path=${mdiPlus}></ha-svg-icon>
</mwc-icon-button>
</paper-icon-item>`;
@@ -403,10 +412,10 @@ class HaSidebar extends LitElement {
changedProps.has("alwaysExpand") ||
changedProps.has("_externalConfig") ||
changedProps.has("_notifications") ||
changedProps.has("editMode") ||
changedProps.has("_editMode") ||
changedProps.has("_renderEmptySortable") ||
changedProps.has("_hiddenPanels") ||
(changedProps.has("_panelOrder") && !this.editMode)
(changedProps.has("_panelOrder") && !this._editMode)
) {
return true;
}
@@ -440,6 +449,9 @@ class HaSidebar extends LitElement {
subscribeNotifications(this.hass.connection, (notifications) => {
this._notifications = notifications;
});
window.addEventListener("hass-edit-sidebar", () =>
this._activateEditMode()
);
}
protected updated(changedProps) {
@@ -447,13 +459,6 @@ class HaSidebar extends LitElement {
if (changedProps.has("alwaysExpand")) {
this.expanded = this.alwaysExpand;
}
if (changedProps.has("editMode")) {
if (this.editMode) {
this._activateEditMode();
} else {
this._deactivateEditMode();
}
}
if (!changedProps.has("hass")) {
return;
}
@@ -484,7 +489,7 @@ class HaSidebar extends LitElement {
return;
}
fireEvent(this, "hass-edit-sidebar", { editMode: true });
this._activateEditMode();
}
private async _activateEditMode() {
@@ -494,14 +499,15 @@ class HaSidebar extends LitElement {
import("../resources/ha-sortable-style"),
]);
const style = document.createElement("style");
style.innerHTML = sortStylesImport.sortableStyles.cssText;
this.shadowRoot!.appendChild(style);
sortStyles = sortStylesImport.sortableStyles;
Sortable = sortableImport.Sortable;
Sortable.mount(sortableImport.OnSpill);
Sortable.mount(sortableImport.AutoScroll());
}
this._editMode = true;
fireEvent(this, "hass-open-menu");
await this.updateComplete;
@@ -513,20 +519,16 @@ class HaSidebar extends LitElement {
animation: 150,
fallbackClass: "sortable-fallback",
dataIdAttr: "data-panel",
handle: "paper-icon-item",
onSort: async () => {
this._panelOrder = this._sortable.toArray();
},
});
}
private _deactivateEditMode() {
private _closeEditMode() {
this._sortable?.destroy();
this._sortable = undefined;
}
private _closeEditMode() {
fireEvent(this, "hass-edit-sidebar", { editMode: false });
this._editMode = false;
}
private async _hidePanel(ev: Event) {
@@ -690,16 +692,16 @@ class HaSidebar extends LitElement {
></ha-svg-icon>`
: html`<ha-icon slot="item-icon" .icon=${icon}></ha-icon>`}
<span class="item-text">${title}</span>
${this._editMode
? html`<mwc-icon-button
class="hide-panel"
.panel=${urlPath}
@click=${this._hidePanel}
>
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>`
: ""}
</paper-icon-item>
${this.editMode
? html`<mwc-icon-button
class="hide-panel"
.panel=${urlPath}
@click=${this._hidePanel}
>
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>`
: ""}
</a>
`;
}
@@ -776,11 +778,6 @@ class HaSidebar extends LitElement {
width: 100%;
}
#sortable,
.hidden-panel {
display: none;
}
paper-listbox {
padding: 4px 0;
display: flex;

View File

@@ -25,7 +25,7 @@ import { debounce } from "../../common/util/debounce";
import {
browseLocalMediaPlayer,
browseMediaPlayer,
BROWSER_PLAYER,
BROWSER_SOURCE,
MediaClassBrowserSettings,
MediaPickedEvent,
MediaPlayerBrowseAction,
@@ -35,7 +35,6 @@ import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
import { installResizeObserver } from "../../panels/lovelace/common/install-resize-observer";
import { haStyle } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
import "../entity/ha-entity-picker";
import "../ha-button-menu";
import "../ha-card";
@@ -109,11 +108,9 @@ export class HaMediaPlayerBrowse extends LitElement {
text: this._renderError(this._error),
});
} else {
return html`
<div class="container">
${this._renderError(this._error)}
</div>
`;
return html`<div class="container">
${this._renderError(this._error)}
</div>`;
}
}
@@ -238,7 +235,7 @@ export class HaMediaPlayerBrowse extends LitElement {
</div>
${this._error
? html`
<div class="container">
<div class="container error">
${this._renderError(this._error)}
</div>
`
@@ -357,31 +354,7 @@ export class HaMediaPlayerBrowse extends LitElement {
`
: html`
<div class="container">
${this.hass.localize("ui.components.media-browser.no_items")}<br />
${currentItem.media_content_id.startsWith(
"media-source://media_source/local_source"
)
? html`${this.hass.localize(
"ui.components.media-browser.learn_adding_local_media",
"documentation",
html`<a
href="${documentationUrl(
this.hass,
"/more-info/local-media/add-media"
)}"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.components.media-browser.documentation"
)}</a
>`
)}
<br />
${this.hass.localize(
"ui.components.media-browser.local_media_files"
)}.`
: ""}
${this.hass.localize("ui.components.media-browser.no_items")}
</div>
`}
`;
@@ -483,7 +456,7 @@ export class HaMediaPlayerBrowse extends LitElement {
mediaContentType?: string
): Promise<MediaPlayerItem> {
const itemData =
this.entityId !== BROWSER_PLAYER
this.entityId !== BROWSER_SOURCE
? await browseMediaPlayer(
this.hass,
this.entityId,
@@ -525,35 +498,29 @@ export class HaMediaPlayerBrowse extends LitElement {
private _renderError(err: { message: string; code: string }) {
if (err.message === "Media directory does not exist.") {
return html`
<h2>
${this.hass.localize(
"ui.components.media-browser.no_local_media_found"
)}
</h2>
<h2>No local media found.</h2>
<p>
${this.hass.localize("ui.components.media-browser.no_media_folder")}
<br />
${this.hass.localize(
"ui.components.media-browser.setup_local_help",
"documentation",
html`<a
href="${documentationUrl(
this.hass,
"/more-info/local-media/setup-media"
)}"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.components.media-browser.documentation"
)}</a
>`
)}
<br />
${this.hass.localize("ui.components.media-browser.local_media_files")}
It looks like you have not yet created a media directory.
<br />Create a directory with the name <b>"media"</b> in the
configuration directory of Home Assistant
(${this.hass.config.config_dir}). <br />Place your video, audio and
image files in this directory to be able to browse and play them in
the browser or on supported media players.
</p>
<p>
Check the
<a
href="https://www.home-assistant.io/integrations/media_source/#local-media"
target="_blank"
rel="noreferrer"
>documentation</a
>
for more info
</p>
`;
}
return html`<span class="error">${err.message}</span>`;
return html`<span class="error">err.message</span>`;
}
static get styles(): CSSResultArray {

View File

@@ -43,16 +43,16 @@ class PersonBadge extends LitElement {
display: contents;
}
.picture {
width: var(--person-picture-size, 40px);
height: var(--person-picture-size, 40px);
width: 40px;
height: 40px;
background-size: cover;
border-radius: 50%;
}
.initials {
display: inline-block;
box-sizing: border-box;
width: var(--person-picture-size, 40px);
line-height: var(--person-picture-size, 40px);
width: 40px;
line-height: 40px;
border-radius: 50%;
text-align: center;
background-color: var(--light-primary-color);

View File

@@ -58,7 +58,6 @@ export type CloudStatus = CloudStatusBase | CloudStatusLoggedIn;
export interface SubscriptionInfo {
human_description: string;
provider: string;
}
export interface CloudWebhook {

View File

@@ -1,23 +1,23 @@
import {
mdiAccountMusic,
mdiAccountMusicOutline,
mdiAlbum,
mdiApplication,
mdiDramaMasks,
mdiFileMusic,
mdiFolder,
mdiGamepadVariant,
mdiImage,
mdiMovie,
mdiMusic,
mdiPlaylistMusic,
mdiPodcast,
mdiTelevisionClassic,
mdiVideo,
mdiWeb,
} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { HomeAssistant } from "../types";
import {
mdiFolder,
mdiPlaylistMusic,
mdiFileMusic,
mdiAlbum,
mdiMusic,
mdiTelevisionClassic,
mdiMovie,
mdiVideo,
mdiImage,
mdiWeb,
mdiGamepadVariant,
mdiAccountMusic,
mdiPodcast,
mdiApplication,
mdiAccountMusicOutline,
mdiDramaMasks,
} from "@mdi/js";
export const SUPPORT_PAUSE = 1;
export const SUPPORT_SEEK = 2;
@@ -38,7 +38,7 @@ export const CONTRAST_RATIO = 4.5;
export type MediaPlayerBrowseAction = "pick" | "play";
export const BROWSER_PLAYER = "browser";
export const BROWSER_SOURCE = "browser";
export type MediaClassBrowserSetting = {
icon: string;

View File

@@ -20,7 +20,6 @@ import { LocalizeFunc } from "../../common/translations/localize";
import "../../components/ha-icon-next";
import { domainToName } from "../../data/integration";
import { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
import { FlowConfig } from "./show-dialog-data-entry-flow";
import { configFlowContentStyles } from "./styles";
@@ -123,7 +122,7 @@ class StepFlowPickHandler extends LitElement {
${this.hass.localize(
"ui.panel.config.integrations.note_about_website_reference"
)}<a
href="${documentationUrl(this.hass, "/integrations/")}"
href="https://www.home-assistant.io/integrations/"
target="_blank"
rel="noreferrer"
>${this.hass.localize(

View File

@@ -48,7 +48,6 @@ class MoreInfoCamera extends LitElement {
<ha-camera-stream
.hass=${this.hass}
.stateObj=${this.stateObj}
allow-exoplayer
controls
></ha-camera-stream>
${this._cameraPrefs

View File

@@ -32,7 +32,7 @@ class MoreInfoPerson extends LitElement {
return html`
<ha-attributes
.stateObj=${this.stateObj}
extra-filters="id,user_id,editable"
extraFilters="id,user_id,editable"
></ha-attributes>
${this.stateObj.attributes.latitude && this.stateObj.attributes.longitude
? html`
@@ -78,9 +78,6 @@ class MoreInfoPerson extends LitElement {
margin: 36px 0 8px 0;
text-align: right;
}
ha-map {
margin-top: 16px;
}
`;
}
}

View File

@@ -26,8 +26,10 @@ import { navigate } from "../../common/navigate";
import "../../components/ha-dialog";
import "../../components/ha-header-bar";
import "../../components/ha-svg-icon";
import "../../components/state-history-charts";
import { removeEntityRegistryEntry } from "../../data/entity_registry";
import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor";
import "../../panels/logbook/ha-logbook";
import { haStyleDialog } from "../../resources/styles";
import "../../state-summary/state-card-content";
import { HomeAssistant } from "../../types";
@@ -392,9 +394,7 @@ export class MoreInfoDialog extends LitElement {
--dialog-content-padding: 0;
}
state-card-content,
ha-more-info-history,
ha-more-info-logbook:not(:last-child) {
state-card-content {
display: block;
margin-bottom: 16px;
}

View File

@@ -1,4 +1,5 @@
import {
css,
customElement,
html,
internalProperty,
@@ -12,6 +13,7 @@ import { throttle } from "../../common/util/throttle";
import "../../components/state-history-charts";
import { getRecentWithCache } from "../../data/cached-history";
import { HistoryResult } from "../../data/history";
import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
@customElement("ha-more-info-history")
@@ -86,6 +88,18 @@ export class MoreInfoHistory extends LitElement {
this.hass!.language
);
}
static get styles() {
return [
haStyle,
css`
state-history-charts {
display: block;
margin-bottom: 16px;
}
`,
];
}
}
declare global {

View File

@@ -152,6 +152,8 @@ export class MoreInfoLogbook extends LitElement {
ha-logbook {
max-height: 250px;
overflow: auto;
display: block;
margin-top: 16px;
}
ha-circular-progress {
display: flex;

View File

@@ -7,13 +7,12 @@ import {
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
PropertyValues,
TemplateResult,
} from "lit-element";
import { fireEvent, HASSDomEvent } from "../common/dom/fire_event";
import { fireEvent } from "../common/dom/fire_event";
import { listenMediaQuery } from "../common/dom/media_query";
import { toggleAttribute } from "../common/dom/toggle_attribute";
import { showNotificationDrawer } from "../dialogs/notifications/show-notification-drawer";
@@ -25,17 +24,10 @@ const NON_SWIPABLE_PANELS = ["map"];
declare global {
// for fire event
interface HASSDomEvents {
"hass-open-menu": undefined;
"hass-toggle-menu": undefined;
"hass-edit-sidebar": EditSideBarEvent;
"hass-show-notifications": undefined;
}
interface HTMLElementEventMap {
"hass-edit-sidebar": HASSDomEvent<EditSideBarEvent>;
}
}
interface EditSideBarEvent {
editMode: boolean;
}
@customElement("home-assistant-main")
@@ -44,9 +36,7 @@ class HomeAssistantMain extends LitElement {
@property() public route?: Route;
@property({ type: Boolean }) public narrow?: boolean;
@internalProperty() private _sidebarEditMode = false;
@property({ type: Boolean }) private narrow?: boolean;
protected render(): TemplateResult {
const hass = this.hass;
@@ -58,9 +48,7 @@ class HomeAssistantMain extends LitElement {
const sidebarNarrow = this._sidebarNarrow;
const disableSwipe =
this._sidebarEditMode ||
!sidebarNarrow ||
NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1;
!sidebarNarrow || NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1;
// Style block in render because of the mixin that is not supported
return html`
@@ -88,7 +76,6 @@ class HomeAssistantMain extends LitElement {
<ha-sidebar
.hass=${hass}
.narrow=${sidebarNarrow}
.editMode=${this._sidebarEditMode}
.alwaysExpand=${sidebarNarrow ||
this.hass.dockedSidebar === "docked"}
></ha-sidebar>
@@ -106,28 +93,18 @@ class HomeAssistantMain extends LitElement {
protected firstUpdated() {
import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar");
this.addEventListener(
"hass-edit-sidebar",
(ev: HASSDomEvent<EditSideBarEvent>) => {
this._sidebarEditMode = ev.detail.editMode;
if (this._sidebarEditMode) {
if (this._sidebarNarrow) {
this.drawer.open();
} else {
fireEvent(this, "hass-dock-sidebar", {
dock: "docked",
});
setTimeout(() => this.appLayout.resetLayout());
}
}
this.addEventListener("hass-open-menu", () => {
if (this._sidebarNarrow) {
this.drawer.open();
} else {
fireEvent(this, "hass-dock-sidebar", {
dock: "docked",
});
setTimeout(() => this.appLayout.resetLayout());
}
);
});
this.addEventListener("hass-toggle-menu", () => {
if (this._sidebarEditMode) {
return;
}
if (this._sidebarNarrow) {
if (this.drawer.opened) {
this.drawer.close();

View File

@@ -39,7 +39,6 @@ import "../../../layouts/ha-app-layout";
import "../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import "../ha-config-section";
import { configSections } from "../ha-panel-config";
import "./action/ha-automation-action";
@@ -160,10 +159,7 @@ export class HaAutomationEditor extends LitElement {
"ui.panel.config.automation.editor.modes.description",
"documentation_link",
html`<a
href="${documentationUrl(
this.hass,
"/integrations/automation/#automation-modes"
)}"
href="https://www.home-assistant.io/integrations/automation/#automation-modes"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
@@ -251,10 +247,7 @@ export class HaAutomationEditor extends LitElement {
)}
</p>
<a
href="${documentationUrl(
this.hass,
"/docs/automation/trigger/"
)}"
href="https://home-assistant.io/docs/automation/trigger/"
target="_blank"
rel="noreferrer"
>
@@ -283,10 +276,7 @@ export class HaAutomationEditor extends LitElement {
)}
</p>
<a
href="${documentationUrl(
this.hass,
"/docs/scripts/conditions/"
)}"
href="https://home-assistant.io/docs/scripts/conditions/"
target="_blank"
rel="noreferrer"
>
@@ -315,10 +305,7 @@ export class HaAutomationEditor extends LitElement {
)}
</p>
<a
href="${documentationUrl(
this.hass,
"/docs/automation/action/"
)}"
href="https://home-assistant.io/docs/automation/action/"
target="_blank"
rel="noreferrer"
>

View File

@@ -4,13 +4,13 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { formatDateTime } from "../../../../common/datetime/format_date_time";
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
import "../../../../components/buttons/ha-call-api-button";
import "../../../../components/ha-card";
import { fetchCloudSubscriptionInfo } from "../../../../data/cloud";
import "../../../../layouts/hass-subpage";
import { EventsMixin } from "../../../../mixins/events-mixin";
import LocalizeMixin from "../../../../mixins/localize-mixin";
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
import "../../../../styles/polymer-ha-style";
import "../../ha-config-section";
import "./cloud-alexa-pref";
@@ -60,32 +60,10 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
a {
color: var(--primary-color);
}
.integrations {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.integrations cloud-alexa-pref,
.integrations cloud-google-pref {
width: calc(50% - 12px);
margin-top: 24px;
}
.integrations cloud-webhooks {
margin-top: 24px;
width: 100%;
}
.integrations.narrow cloud-alexa-pref,
.integrations.narrow cloud-google-pref {
width: 100%;
}
</style>
<hass-subpage header="[[localize('ui.panel.config.cloud.caption')]]">
<div class="content">
<ha-config-section side-by-side is-wide="[[isWide]]">
<ha-config-section is-wide="[[isWide]]">
<span slot="header"
>[[localize('ui.panel.config.cloud.caption')]]</span
>
@@ -131,7 +109,7 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
</ha-card>
</ha-config-section>
<ha-config-section side-by-side is-wide="[[isWide]]">
<ha-config-section is-wide="[[isWide]]">
<span slot="header"
>[[localize('ui.panel.config.cloud.account.integrations')]]</span
>
@@ -150,32 +128,30 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
>.
</p>
</div>
<cloud-remote-pref
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-remote-pref>
</ha-config-section>
<ha-config-section no-header is-wide="[[isWide]]">
<div class$="integrations [[_computeIsNarrow(isWide)]]">
<cloud-alexa-pref
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-alexa-pref>
<cloud-google-pref
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-google-pref>
<cloud-alexa-pref
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-alexa-pref>
<cloud-webhooks
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-webhooks>
</div>
<cloud-google-pref
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-google-pref>
<cloud-webhooks
hass="[[hass]]"
cloud-status="[[cloudStatus]]"
dir="[[_rtlDirection]]"
></cloud-webhooks>
</ha-config-section>
</div>
</hass-subpage>
@@ -251,10 +227,6 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
_computeRTLDirection(hass) {
return computeRTLDirection(hass);
}
_computeIsNarrow(isWide) {
return isWide ? "" : "narrow";
}
}
customElements.define("cloud-account", CloudAccount);

View File

@@ -32,17 +32,17 @@ export class CloudAlexaPref extends LitElement {
return html`
<ha-card
.header=${this.hass!.localize(
header=${this.hass!.localize(
"ui.panel.config.cloud.account.alexa.title"
)}
>
<div class="switch">
<ha-switch
.checked=${alexa_enabled}
@change=${this._enabledToggleChanged}
></ha-switch>
</div>
<div class="card-content">
<div class="switch">
<ha-switch
.checked=${alexa_enabled}
@change=${this._enabledToggleChanged}
></ha-switch>
</div>
${this.hass!.localize("ui.panel.config.cloud.account.alexa.info")}
<ul>
<li>
@@ -197,15 +197,6 @@ export class CloudAlexaPref extends LitElement {
margin-right: 7px;
margin-left: 0.5em;
}
ha-card {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}
.card-content {
flex: 1;
}
`;
}
}

View File

@@ -124,26 +124,6 @@ class CloudAlexa extends LitElement {
? exposedCards
: notExposedCards;
const iconButton = html`<mwc-icon-button
slot="trigger"
class=${classMap({
exposed: isExposed!,
"not-exposed": !isExposed,
})}
.disabled=${!emptyFilter}
.title=${this.hass!.localize("ui.panel.config.cloud.google.expose")}
>
<ha-svg-icon
.path=${config.should_expose !== null
? isExposed
? mdiCheckboxMarked
: mdiCloseBox
: isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-icon-button>`;
target.push(html`
<ha-card>
<div class="card-content">
@@ -159,50 +139,67 @@ class CloudAlexa extends LitElement {
.map((ifc) => ifc.replace(/(Alexa.|Controller)/g, ""))
.join(", ")}
</state-info>
${!emptyFilter
? html`${iconButton}`
: html`<ha-button-menu
corner="BOTTOM_START"
.entityId=${stateObj.entity_id}
@action=${this._exposeChanged}
>
${iconButton}
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.expose_entity"
)}
<ha-svg-icon
class="exposed"
slot="meta"
.path=${mdiCheckboxMarked}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.dont_expose_entity"
)}
<ha-svg-icon
class="not-exposed"
slot="meta"
.path=${mdiCloseBox}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.follow_domain"
)}
<ha-svg-icon
class=${classMap({
exposed: isDomainExposed,
"not-exposed": !isDomainExposed,
})}
slot="meta"
.path=${isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-list-item>
</ha-button-menu>`}
<ha-button-menu
corner="BOTTOM_START"
.entityId=${stateObj.entity_id}
@action=${this._exposeChanged}
>
<mwc-icon-button
slot="trigger"
class=${classMap({
exposed: isExposed!,
"not-exposed": !isExposed,
})}
.title=${this.hass!.localize(
"ui.panel.config.cloud.alexa.expose"
)}
>
<ha-svg-icon
.path=${config.should_expose !== null
? isExposed
? mdiCheckboxMarked
: mdiCloseBox
: isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.alexa.expose_entity"
)}
<ha-svg-icon
class="exposed"
slot="meta"
.path=${mdiCheckboxMarked}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.alexa.dont_expose_entity"
)}
<ha-svg-icon
class="not-exposed"
slot="meta"
.path=${mdiCloseBox}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.alexa.follow_domain"
)}
<ha-svg-icon
class=${classMap({
exposed: isDomainExposed,
"not-exposed": !isDomainExposed,
})}
slot="meta"
.path=${isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-list-item>
</ha-button-menu>
</div>
</div>
</ha-card>

View File

@@ -14,7 +14,6 @@ import type { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialo
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import { documentationUrl } from "../../../../util/documentation-url";
import { WebhookDialogParams } from "./show-dialog-manage-cloudhook";
const inputLabel = "Public URL Click to copy to clipboard";
@@ -38,11 +37,8 @@ export class DialogManageCloudhook extends LitElement {
const { webhook, cloudhook } = this._params;
const docsUrl =
webhook.domain === "automation"
? documentationUrl(
this.hass!,
"/docs/automation/trigger/#webhook-trigger"
)
: documentationUrl(this.hass!, `/integrations/${webhook.domain}/`);
? "https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger"
: `https://www.home-assistant.io/integrations/${webhook.domain}/`;
return html`
<ha-paper-dialog with-backdrop>
<h2>

View File

@@ -130,26 +130,6 @@ class CloudGoogleAssistant extends LitElement {
? exposedCards
: notExposedCards;
const iconButton = html`<mwc-icon-button
slot="trigger"
class=${classMap({
exposed: isExposed!,
"not-exposed": !isExposed,
})}
.disabled=${!emptyFilter}
.title=${this.hass!.localize("ui.panel.config.cloud.google.expose")}
>
<ha-svg-icon
.path=${config.should_expose !== null
? isExposed
? mdiCheckboxMarked
: mdiCloseBox
: isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-icon-button>`;
target.push(html`
<ha-card>
<div class="card-content">
@@ -164,50 +144,67 @@ class CloudGoogleAssistant extends LitElement {
.map((trait) => trait.substr(trait.lastIndexOf(".") + 1))
.join(", ")}
</state-info>
${!emptyFilter
? html`${iconButton}`
: html`<ha-button-menu
corner="BOTTOM_START"
.entityId=${stateObj.entity_id}
@action=${this._exposeChanged}
>
${iconButton}
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.expose_entity"
)}
<ha-svg-icon
class="exposed"
slot="meta"
.path=${mdiCheckboxMarked}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.dont_expose_entity"
)}
<ha-svg-icon
class="not-exposed"
slot="meta"
.path=${mdiCloseBox}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.follow_domain"
)}
<ha-svg-icon
class=${classMap({
exposed: isDomainExposed,
"not-exposed": !isDomainExposed,
})}
slot="meta"
.path=${isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-list-item>
</ha-button-menu>`}
<ha-button-menu
corner="BOTTOM_START"
.entityId=${stateObj.entity_id}
@action=${this._exposeChanged}
>
<mwc-icon-button
slot="trigger"
class=${classMap({
exposed: isExposed!,
"not-exposed": !isExposed,
})}
.title=${this.hass!.localize(
"ui.panel.config.cloud.google.expose"
)}
>
<ha-svg-icon
.path=${config.should_expose !== null
? isExposed
? mdiCheckboxMarked
: mdiCloseBox
: isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.expose_entity"
)}
<ha-svg-icon
class="exposed"
slot="meta"
.path=${mdiCheckboxMarked}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.dont_expose_entity"
)}
<ha-svg-icon
class="not-exposed"
slot="meta"
.path=${mdiCloseBox}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item hasMeta>
${this.hass!.localize(
"ui.panel.config.cloud.google.follow_domain"
)}
<ha-svg-icon
class=${classMap({
exposed: isDomainExposed,
"not-exposed": !isDomainExposed,
})}
slot="meta"
.path=${isDomainExposed
? mdiCheckboxMultipleMarked
: mdiCloseBoxMultiple}
></ha-svg-icon>
</mwc-list-item>
</ha-button-menu>
</div>
${entity.might_2fa
? html`

View File

@@ -78,7 +78,7 @@ class CloudLogin extends LocalizeMixin(
</style>
<hass-subpage header="[[localize('ui.panel.config.cloud.caption')]]">
<div class="content">
<ha-config-section side-by-side is-wide="[[isWide]]">
<ha-config-section is-wide="[[isWide]]">
<span slot="header"
>[[localize('ui.panel.config.cloud.caption')]]</span
>

View File

@@ -8,7 +8,6 @@ import "../../../../layouts/hass-subpage";
import { EventsMixin } from "../../../../mixins/events-mixin";
import LocalizeMixin from "../../../../mixins/localize-mixin";
import "../../../../styles/polymer-ha-style";
import { documentationUrl } from "../../../../util/documentation-url";
import "../../ha-config-section";
/*
@@ -49,7 +48,7 @@ class CloudRegister extends LocalizeMixin(EventsMixin(PolymerElement)) {
</style>
<hass-subpage header="[[localize('ui.panel.config.cloud.register.title')]]">
<div class="content">
<ha-config-section side-by-side is-wide="[[isWide]]">
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.cloud.register.headline')]]</span>
<div slot="introduction">
<p>
@@ -71,8 +70,8 @@ class CloudRegister extends LocalizeMixin(EventsMixin(PolymerElement)) {
<p>
[[localize('ui.panel.config.cloud.register.information4')]]
</p><ul>
<li><a href="[[_computeDocumentationUrlTos(hass)]]" target="_blank" rel="noreferrer">[[localize('ui.panel.config.cloud.register.link_terms_conditions')]]</a></li>
<li><a href="[[_computeDocumentationUrlPrivacy(hass)]]" target="_blank" rel="noreferrer">[[localize('ui.panel.config.cloud.register.link_privacy_policy')]]</a></li>
<li><a href="https://home-assistant.io/tos/" target="_blank" rel="noreferrer">[[localize('ui.panel.config.cloud.register.link_terms_conditions')]]</a></li>
<li><a href="https://home-assistant.io/privacy/" target="_blank" rel="noreferrer">[[localize('ui.panel.config.cloud.register.link_privacy_policy')]]</a></li>
</ul>
</p>
</div>
@@ -138,14 +137,6 @@ class CloudRegister extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
}
_computeDocumentationUrlTos(hass) {
return documentationUrl(hass, "/tos/");
}
_computeDocumentationUrlPrivacy(hass) {
return documentationUrl(hass, "/privacy/");
}
_handleRegister() {
let invalid = false;

View File

@@ -0,0 +1,73 @@
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "../../../components/ha-icon-button";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../layouts/hass-tabs-subpage";
import LocalizeMixin from "../../../mixins/localize-mixin";
import "../../../styles/polymer-ha-style";
import { configSections } from "../ha-panel-config";
import "./ha-config-section-core";
/*
* @appliesMixin LocalizeMixin
*/
class HaConfigCore extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
padding-bottom: 32px;
}
.border {
margin: 32px auto 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
max-width: 1040px;
}
.narrow .border {
max-width: 640px;
}
</style>
<hass-tabs-subpage
hass="[[hass]]"
narrow="[[narrow]]"
route="[[route]]"
back-path="/config"
tabs="[[_computeTabs()]]"
show-advanced="[[showAdvanced]]"
>
<div class$="[[computeClasses(isWide)]]">
<ha-config-section-core
is-wide="[[isWide]]"
show-advanced="[[showAdvanced]]"
hass="[[hass]]"
></ha-config-section-core>
</div>
</hass-tabs-subpage>
`;
}
static get properties() {
return {
hass: Object,
isWide: Boolean,
narrow: Boolean,
showAdvanced: Boolean,
route: Object,
};
}
_computeTabs() {
return configSections.general;
}
computeClasses(isWide) {
return isWide ? "content" : "content narrow";
}
}
customElements.define("ha-config-core", HaConfigCore);

View File

@@ -1,66 +0,0 @@
import {
LitElement,
CSSResult,
css,
TemplateResult,
html,
property,
customElement,
} from "lit-element";
import type { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config";
import "../../../layouts/hass-tabs-subpage";
import "./ha-config-section-core";
@customElement("ha-config-core")
export class HaConfigCore extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public isWide!: boolean;
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public showAdvanced!: boolean;
protected render(): TemplateResult {
return html`
<hass-tabs-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
back-path="/config"
.tabs=${configSections.general}
show-advanced=${this.showAdvanced}
>
<ha-config-section-core
.isWide=${this.isWide}
.narrow=${this.narrow}
.showAdvanced=${this.showAdvanced}
.hass=${this.hass}
></ha-config-section-core>
</hass-tabs-subpage>
`;
}
computeClasses(isWide) {
return isWide ? "content" : "content narrow";
}
static get styles(): CSSResult {
return css`
ha-config-section-core {
display: block;
padding-bottom: 32px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-core": HaConfigCore;
}
}

View File

@@ -10,8 +10,6 @@ import {
property,
internalProperty,
TemplateResult,
CSSResult,
css,
} from "lit-element";
import "../../../components/ha-card";
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
@@ -89,21 +87,6 @@ class ConfigNameForm extends LitElement {
this._working = false;
}
}
static get styles(): CSSResult {
return css`
:host {
display: flex;
}
ha-card {
justify-content: space-between;
display: flex;
flex-direction: column;
width: 100%;
}
`;
}
}
declare global {

View File

@@ -0,0 +1,126 @@
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-card";
import LocalizeMixin from "../../../mixins/localize-mixin";
import "../../../styles/polymer-ha-style";
import "../ha-config-section";
import "./ha-config-core-form";
import "./ha-config-name-form";
import "./ha-config-url-form";
/*
* @appliesMixin LocalizeMixin
*/
class HaConfigSectionCore extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
.validate-container {
@apply --layout-vertical;
@apply --layout-center-center;
height: 140px;
}
.validate-result {
color: var(--success-color);
font-weight: 500;
margin-bottom: 1em;
}
.config-invalid {
margin: 1em 0;
}
.config-invalid .text {
color: var(--error-color);
font-weight: 500;
}
.config-invalid mwc-button {
float: right;
}
.validate-log {
white-space: pre-wrap;
direction: ltr;
}
</style>
<ha-config-section is-wide="[[isWide]]">
<span slot="header"
>[[localize('ui.panel.config.core.section.core.header')]]</span
>
<span slot="introduction"
>[[localize('ui.panel.config.core.section.core.introduction')]]</span
>
<ha-config-name-form hass="[[hass]]"></ha-config-name-form>
<ha-config-core-form hass="[[hass]]"></ha-config-core-form>
<ha-config-url-form hass="[[hass]]"></ha-config-url-form>
</ha-config-section>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
isWide: {
type: Boolean,
value: false,
},
validating: {
type: Boolean,
value: false,
},
isValid: {
type: Boolean,
value: null,
},
validateLog: {
type: String,
value: "",
},
showAdvanced: Boolean,
};
}
groupLoaded(hass) {
return isComponentLoaded(hass, "group");
}
automationLoaded(hass) {
return isComponentLoaded(hass, "automation");
}
scriptLoaded(hass) {
return isComponentLoaded(hass, "script");
}
validateConfig() {
this.validating = true;
this.validateLog = "";
this.isValid = null;
this.hass.callApi("POST", "config/core/check_config").then((result) => {
this.validating = false;
this.isValid = result.result === "valid";
if (!this.isValid) {
this.validateLog = result.errors;
}
});
}
}
customElements.define("ha-config-section-core", HaConfigSectionCore);

View File

@@ -1,75 +0,0 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import type { HomeAssistant } from "../../../types";
import "../ha-config-section";
import "./ha-config-core-form";
import "./ha-config-name-form";
import "./ha-config-url-form";
@customElement("ha-config-section-core")
export class HaConfigSectionCore extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public isWide!: boolean;
@property({ type: Boolean, attribute: "narrow", reflect: true })
public narrow!: boolean;
protected render(): TemplateResult {
return html`
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.core.section.core.header")}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.core.section.core.introduction"
)}
</div>
<div class="content">
<ha-config-name-form .hass=${this.hass}></ha-config-name-form>
<ha-config-url-form .hass=${this.hass}></ha-config-url-form>
<ha-config-core-form .hass=${this.hass}></ha-config-core-form>
</div>
</ha-config-section>
`;
}
static get styles(): CSSResult {
return css`
.content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
ha-config-name-form,
ha-config-url-form {
width: calc(50% - 12px);
}
:host([narrow]) ha-config-url-form,
ha-config-core-form {
margin-top: 24px;
width: 100%;
}
:host([narrow]) ha-config-name-form {
width: 100%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-section-core": HaConfigSectionCore;
}
}

View File

@@ -51,31 +51,46 @@ class ConfigUrlForm extends LitElement {
`
: ""}
${this._error ? html`<div class="error">${this._error}</div>` : ""}
<div class="row">
<div class="flex">
${this.hass.localize(
"ui.panel.config.core.section.core.core_config.external_url"
)}
</div>
<paper-input
class="flex"
.label=${this.hass.localize(
"ui.panel.config.core.section.core.core_config.external_url"
)}
name="external_url"
type="url"
.disabled=${disabled}
.value=${this._externalUrlValue}
@value-changed=${this._handleChange}
>
</paper-input>
<paper-input
class="flex"
.label=${this.hass.localize(
"ui.panel.config.core.section.core.core_config.internal_url"
)}
name="internal_url"
type="url"
.disabled=${disabled}
.value=${this._internalUrlValue}
@value-changed=${this._handleChange}
>
</paper-input>
<paper-input
class="flex"
.label=${this.hass.localize(
"ui.panel.config.core.section.core.core_config.external_url"
)}
name="external_url"
type="url"
.disabled=${disabled}
.value=${this._externalUrlValue}
@value-changed=${this._handleChange}
>
</paper-input>
</div>
<div class="row">
<div class="flex">
${this.hass.localize(
"ui.panel.config.core.section.core.core_config.internal_url"
)}
</div>
<paper-input
class="flex"
.label=${this.hass.localize(
"ui.panel.config.core.section.core.core_config.internal_url"
)}
name="internal_url"
type="url"
.disabled=${disabled}
.value=${this._internalUrlValue}
@value-changed=${this._handleChange}
>
</paper-input>
</div>
</div>
<div class="card-actions">
<mwc-button @click=${this._save} .disabled=${disabled}>

View File

@@ -6,11 +6,10 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
import LocalizeMixin from "../../../mixins/localize-mixin";
import "../../../styles/polymer-ha-style";
import { documentationUrl } from "../../../util/documentation-url";
import hassAttributeUtil from "../../../util/hass-attributes-util";
import "../ha-form-style";
import "./ha-form-customize-attributes";
import "../ha-form-style";
import "../../../styles/polymer-ha-style";
class HaFormCustomize extends LocalizeMixin(PolymerElement) {
static get template() {
@@ -31,7 +30,7 @@ class HaFormCustomize extends LocalizeMixin(PolymerElement) {
<div class="warning">
[[localize('ui.panel.config.customize.warning.include_sentence')]]
<a
href="[[_computeDocumentationUrl(hass)]]"
href="https://www.home-assistant.io/docs/configuration/customizing-devices/#customization-using-the-ui"
target="_blank"
rel="noreferrer"
>[[localize('ui.panel.config.customize.warning.include_link')]]</a
@@ -211,13 +210,6 @@ class HaFormCustomize extends LocalizeMixin(PolymerElement) {
);
}
_computeDocumentationUrl(hass) {
return documentationUrl(
hass,
"/docs/configuration/customizing-devices/#customization-using-the-ui"
);
}
computeLocalAttributes(localConfig) {
if (!localConfig) return [];
const localKeys = Object.keys(localConfig);

File diff suppressed because it is too large Load Diff

View File

@@ -3,24 +3,16 @@ import { classMap } from "lit-html/directives/class-map";
@customElement("ha-config-section")
export class HaConfigSection extends LitElement {
@property({ type: Boolean }) public isWide = false;
@property({ type: Boolean }) public narrow?: boolean;
@property({ type: Boolean, attribute: "no-header" }) public noHeader = false;
@property() public isWide = false;
protected render() {
return html`
<div
class="content ${classMap({
narrow: this.narrow !== undefined ? this.narrow : !this.isWide,
"no-header": this.noHeader,
narrow: !this.isWide,
})}"
>
<div class="heading">
<div class="header"><slot name="header"></slot></div>
<div class="intro"><slot name="introduction"></slot></div>
</div>
<div class="header"><slot name="header"></slot></div>
<div
class="together layout ${classMap({
narrow: !this.isWide,
@@ -28,6 +20,7 @@ export class HaConfigSection extends LitElement {
horizontal: this.isWide,
})}"
>
<div class="intro"><slot name="introduction"></slot></div>
<div class="panel flex-auto"><slot></slot></div>
</div>
</div>
@@ -45,18 +38,10 @@ export class HaConfigSection extends LitElement {
margin: 0 auto;
}
:host([side-by-side]) .content:not(.narrow) {
display: flex;
}
.layout {
display: flex;
}
:host([side-by-side]) .content:not(.narrow) .layout {
width: 100%;
}
.horizontal {
flex-direction: row;
}
@@ -69,13 +54,7 @@ export class HaConfigSection extends LitElement {
flex: 1 1 auto;
}
:host([side-by-side]) .content:not(.narrow) .heading {
min-width: 400px;
max-width: 400px;
margin-right: 40px;
}
slot[name="header"]::slotted(*) {
.header {
font-family: var(--paper-font-headline_-_font-family);
-webkit-font-smoothing: var(
--paper-font-headline_-_-webkit-font-smoothing
@@ -85,14 +64,13 @@ export class HaConfigSection extends LitElement {
letter-spacing: var(--paper-font-headline_-_letter-spacing);
line-height: var(--paper-font-headline_-_line-height);
opacity: var(--dark-primary-opacity);
padding-bottom: 8px;
}
.together {
margin-top: 32px;
}
slot[name="introduction"]::slotted(*) {
.intro {
font-family: var(--paper-font-subhead_-_font-family);
-webkit-font-smoothing: var(
--paper-font-subhead_-_-webkit-font-smoothing
@@ -100,6 +78,7 @@ export class HaConfigSection extends LitElement {
font-weight: var(--paper-font-subhead_-_font-weight);
line-height: var(--paper-font-subhead_-_line-height);
width: 100%;
max-width: 400px;
margin-right: 40px;
opacity: var(--dark-primary-opacity);
font-size: 14px;
@@ -107,7 +86,7 @@ export class HaConfigSection extends LitElement {
}
.panel {
margin-top: -48px;
margin-top: -24px;
}
.panel ::slotted(*) {
@@ -121,21 +100,11 @@ export class HaConfigSection extends LitElement {
.narrow .together {
margin-top: 20px;
}
.narrow slot[name="introduction"]::slotted(*) {
.narrow .intro {
padding-bottom: 20px;
margin-right: 0;
max-width: 500px;
}
.no-header.content {
padding-top: 0;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-section": HaConfigSection;
}
}

View File

@@ -1,30 +1,10 @@
import {
mdiAccount,
mdiBadgeAccountHorizontal,
mdiDevices,
mdiHomeAssistant,
mdiInformation,
mdiMapMarkerRadius,
mdiMathLog,
mdiNfcVariant,
mdiPalette,
mdiPencil,
mdiPuzzle,
mdiRobot,
mdiScriptText,
mdiServer,
mdiShape,
mdiSofa,
mdiTools,
mdiViewDashboard,
} from "@mdi/js";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import { PolymerElement } from "@polymer/polymer";
import {
customElement,
internalProperty,
property,
internalProperty,
PropertyValues,
} from "lit-element";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
@@ -34,6 +14,26 @@ import "../../layouts/hass-loading-screen";
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
import { HomeAssistant, Route } from "../../types";
import {
mdiPuzzle,
mdiDevices,
mdiShape,
mdiSofa,
mdiRobot,
mdiPalette,
mdiScriptText,
mdiTools,
mdiViewDashboard,
mdiAccount,
mdiMapMarkerRadius,
mdiBadgeAccountHorizontal,
mdiHomeAssistant,
mdiServer,
mdiInformation,
mdiMathLog,
mdiPencil,
mdiNfcVariant,
} from "@mdi/js";
declare global {
// for fire event
@@ -167,6 +167,8 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconPath: mdiInformation,
core: true,
},
],
advanced: [
{
component: "customize",
path: "/config/customize",

View File

@@ -6,9 +6,9 @@ import {
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import { fireEvent } from "../../../../common/dom/fire_event";
@@ -48,12 +48,12 @@ class HaInputNumberForm extends LitElement {
this._max = item.max ?? 100;
this._min = item.min ?? 0;
this._mode = item.mode || "slider";
this._step = item.step ?? 1;
this._step = item.step || 1;
this._unit_of_measurement = item.unit_of_measurement;
} else {
this._item = {
min: 0,
max: 100,
max: 0,
};
this._name = "";
this._icon = "";
@@ -176,10 +176,8 @@ class HaInputNumberForm extends LitElement {
return;
}
ev.stopPropagation();
const target = ev.target as any;
const configValue = target.configValue;
const value =
target.type === "number" ? Number(ev.detail.value) : ev.detail.value;
const configValue = (ev.target as any).configValue;
const value = ev.detail.value;
if (this[`_${configValue}`] === value) {
return;
}

View File

@@ -6,13 +6,12 @@ import {
property,
TemplateResult,
} from "lit-element";
import "../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { configSections } from "../ha-panel-config";
import "./integrations-card";
import "./system-health-card";
import { documentationUrl } from "../../../util/documentation-url";
import { configSections } from "../ha-panel-config";
import "../../../layouts/hass-tabs-subpage";
const JS_TYPE = __BUILD__;
const JS_VERSION = __VERSION__;
@@ -43,7 +42,7 @@ class HaConfigInfo extends LitElement {
>
<div class="about">
<a
href="${documentationUrl(this.hass, "")}"
href="https://www.home-assistant.io"
target="_blank"
rel="noreferrer"
><img
@@ -64,7 +63,7 @@ class HaConfigInfo extends LitElement {
</p>
<p class="develop">
<a
href="${documentationUrl(this.hass, "/developers/credits/")}"
href="https://www.home-assistant.io/developers/credits/"
target="_blank"
rel="noreferrer"
>
@@ -94,10 +93,10 @@ class HaConfigInfo extends LitElement {
>Python 3</a
>,
<a
href="https://lit-element.polymer-project.org/"
href="https://www.polymer-project.org"
target="_blank"
rel="noreferrer"
>LitElement</a
>Polymer</a
>, ${this.hass.localize("ui.panel.config.info.icons_by")}
<a
href="https://www.google.com/design/icons/"

View File

@@ -159,13 +159,11 @@ class OZWNetworkDashboard extends LitElement {
}
private _generateServiceButton(service: string) {
const serviceData = { instance_id: this.ozwInstance };
return html`
<ha-call-service-button
.hass=${this.hass}
domain="ozw"
.service=${service}
.serviceData=${serviceData}
>
${this.hass!.localize(`ui.panel.config.ozw.services.${service}`)}
</ha-call-service-button>

View File

@@ -1,20 +1,20 @@
import "../../../../../components/ha-icon-button";
import "../../../../../components/ha-circular-progress";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import "../../../../../components/buttons/ha-call-api-button";
import "../../../../../components/buttons/ha-call-service-button";
import "../../../../../components/ha-card";
import "../../../../../components/ha-circular-progress";
import "../../../../../components/ha-icon";
import "../../../../../components/ha-icon-button";
import "../../../../../components/ha-service-description";
import {
fetchNetworkStatus,
@@ -26,7 +26,6 @@ import {
} from "../../../../../data/zwave";
import { haStyle } from "../../../../../resources/styles";
import { HomeAssistant } from "../../../../../types";
import { documentationUrl } from "../../../../../util/documentation-url";
import "../../../ha-config-section";
@customElement("zwave-network")
@@ -72,10 +71,7 @@ export class ZwaveNetwork extends LitElement {
)}
<p>
<a
href="${documentationUrl(
this.hass,
"/docs/z-wave/control-panel/"
)}"
href="https://www.home-assistant.io/docs/z-wave/control-panel/"
target="_blank"
rel="noreferrer"
>

View File

@@ -1,20 +1,20 @@
import "../../../components/ha-icon-button";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import "../../../components/ha-circular-progress";
import {
css,
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/buttons/ha-progress-button";
import "../../../components/ha-card";
import "../../../components/ha-circular-progress";
import "../../../components/ha-icon-button";
import { domainToName } from "../../../data/integration";
import {
fetchSystemLog,
@@ -164,10 +164,6 @@ export class SystemLogCard extends LitElement {
align-items: center;
justify-content: center;
}
.card-actions {
display: flex;
}
`;
}
}

View File

@@ -4,24 +4,23 @@ import {
css,
CSSResult,
html,
internalProperty,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import "../../../components/entity/ha-entities-picker";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-picture-upload";
import type { HaPictureUpload } from "../../../components/ha-picture-upload";
import "../../../components/entity/ha-entities-picker";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/user/ha-user-picker";
import { PersonMutableParams } from "../../../data/person";
import { CropOptions } from "../../../dialogs/image-cropper-dialog/show-image-cropper-dialog";
import { PolymerChangedEvent } from "../../../polymer-types";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { PersonDetailDialogParams } from "./show-dialog-person-detail";
import { CropOptions } from "../../../dialogs/image-cropper-dialog/show-image-cropper-dialog";
const includeDomains = ["device_tracker"];
@@ -154,10 +153,7 @@ class DialogPersonDetail extends LitElement {
<ul>
<li>
<a
href="${documentationUrl(
this.hass,
"/integrations/#presence-detection"
)}"
href="https://www.home-assistant.io/integrations/#presence-detection"
target="_blank"
rel="noreferrer"
>${this.hass!.localize(

View File

@@ -25,7 +25,6 @@ import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-tabs-subpage-data-table";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { showToast } from "../../../util/toast";
import { configSections } from "../ha-panel-config";
@@ -192,7 +191,7 @@ class HaSceneDashboard extends LitElement {
${this.hass.localize("ui.panel.config.scene.picker.introduction")}
<p>
<a
href="${documentationUrl(this.hass, "/docs/scene/editor/")}"
href="https://home-assistant.io/docs/scene/editor/"
target="_blank"
rel="noreferrer"
>

View File

@@ -1,47 +1,49 @@
import "@material/mwc-fab";
import { mdiContentSave } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import { PaperListboxElement } from "@polymer/paper-listbox";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import "../../../components/ha-icon-button";
import "../../../components/ha-button-menu";
import {
css,
CSSResult,
html,
internalProperty,
LitElement,
property,
internalProperty,
PropertyValues,
TemplateResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { computeObjectId } from "../../../common/entity/compute_object_id";
import { navigate } from "../../../common/navigate";
import { slugify } from "../../../common/string/slugify";
import { computeRTL } from "../../../common/util/compute_rtl";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-icon-input";
import "../../../components/ha-svg-icon";
import { showToast } from "../../../util/toast";
import "@material/mwc-fab";
import {
Action,
deleteScript,
getScriptEditorInitData,
MODES,
MODES_MAX,
ScriptConfig,
triggerScript,
MODES,
MODES_MAX,
} from "../../../data/script";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/ha-app-layout";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant, Route } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { showToast } from "../../../util/toast";
import "../automation/action/ha-automation-action";
import { HaDeviceAction } from "../automation/action/types/ha-automation-action-device_id";
import "../ha-config-section";
import { configSections } from "../ha-panel-config";
import "../../../components/ha-svg-icon";
import { mdiContentSave, mdiDotsVertical } from "@mdi/js";
import { PaperListboxElement } from "@polymer/paper-listbox";
import { slugify } from "../../../common/string/slugify";
export class HaScriptEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -64,6 +66,8 @@ export class HaScriptEditor extends LitElement {
@internalProperty() private _errors?: string;
@internalProperty() private _yamlMode = false;
protected render(): TemplateResult {
return html`
<hass-tabs-subpage
@@ -73,19 +77,46 @@ export class HaScriptEditor extends LitElement {
.backCallback=${() => this._backTapped()}
.tabs=${configSections.automation}
>
${!this.scriptEntityId
? ""
: html`
<ha-icon-button
class="warning"
slot="toolbar-icon"
title="${this.hass.localize(
"ui.panel.config.script.editor.delete_script"
)}"
icon="hass:delete"
@click=${this._deleteConfirm}
></ha-icon-button>
`}
<ha-button-menu
corner="BOTTOM_START"
slot="toolbar-icon"
@action=${this._handleAction}
>
<mwc-icon-button
slot="trigger"
.title=${this.hass.localize("ui.common.menu")}
.label=${this.hass.localize("ui.common.overflow_menu")}
><ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item
aria-label=${this._yamlMode
? this.hass.localize("ui.panel.config.automation.editor.edit_ui")
: this.hass.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
>
${this._yamlMode
? this.hass.localize("ui.panel.config.automation.editor.edit_ui")
: this.hass.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
</mwc-list-item>
${!this.scriptEntityId
? ""
: html`
<mwc-list-item
class="warning"
aria-label=${this.hass.localize(
"ui.panel.config.script.editor.delete_script"
)}
>
${this.hass.localize(
"ui.panel.config.script.editor.delete_script"
)}
</mwc-list-item>
`}
</ha-button-menu>
${this.narrow
? html` <span slot="header">${this._config?.alias}</span> `
: ""}
@@ -99,156 +130,195 @@ export class HaScriptEditor extends LitElement {
})}"
>
${this._config
? html`
<ha-config-section .isWide=${this.isWide}>
${!this.narrow
? html` <span slot="header">${this._config.alias}</span> `
: ""}
<span slot="introduction">
${this.hass.localize(
"ui.panel.config.script.editor.introduction"
)}
</span>
<ha-card>
<div class="card-content">
<paper-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.alias"
)}
name="alias"
.value=${this._config.alias}
@value-changed=${this._valueChanged}
@change=${this._aliasChanged}
>
</paper-input>
<ha-icon-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.icon"
)}
.name=${"icon"}
.value=${this._config.icon}
@value-changed=${this._valueChanged}
>
</ha-icon-input>
${!this.scriptEntityId
? html` <paper-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.id"
)}
.errorMessage=${this.hass.localize(
"ui.panel.config.script.editor.id_already_exists"
)}
.invalid=${this._idError}
.value=${this._entityId}
@value-changed=${this._idChanged}
? this._yamlMode
? html`
<ha-config-section .isWide=${false}>
${!this.narrow
? html`
<span slot="header">${this._config.alias}</span>
`
: ""}
<ha-card>
<div class="card-content">
<ha-yaml-editor
.defaultValue=${this._config}
@value-changed=${this._onYamlChange}
></ha-yaml-editor>
</div>
${this.scriptEntityId
? html`
<div
class="card-actions layout horizontal justified center"
>
<span></span>
<mwc-button
@click=${this._runScript}
title="${this.hass.localize(
"ui.panel.config.script.picker.activate_script"
)}"
?disabled=${this._dirty}
>
${this.hass.localize(
"ui.card.script.execute"
)}
</mwc-button>
</div>
`
: ``}
</ha-card>
</ha-config-section>
`
: html`
<ha-config-section .isWide=${this.isWide}>
${!this.narrow
? html`
<span slot="header">${this._config.alias}</span>
`
: ""}
<span slot="introduction">
${this.hass.localize(
"ui.panel.config.script.editor.introduction"
)}
</span>
<ha-card>
<div class="card-content">
<paper-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.alias"
)}
name="alias"
.value=${this._config.alias}
@value-changed=${this._valueChanged}
@change=${this._aliasChanged}
>
</paper-input>
<ha-icon-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.icon"
)}
.name=${"icon"}
.value=${this._config.icon}
@value-changed=${this._valueChanged}
>
</ha-icon-input>
${!this.scriptEntityId
? html` <paper-input
.label=${this.hass.localize(
"ui.panel.config.script.editor.id"
)}
.errorMessage=${this.hass.localize(
"ui.panel.config.script.editor.id_already_exists"
)}
.invalid=${this._idError}
.value=${this._entityId}
@value-changed=${this._idChanged}
>
</paper-input>`
: ""}
<p>
${this.hass.localize(
"ui.panel.config.script.editor.modes.description",
"documentation_link",
html`<a
href="https://www.home-assistant.io/integrations/script/#script-modes"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.panel.config.script.editor.modes.documentation"
)}</a
>`
)}
</p>
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.script.editor.modes.label"
)}
no-animations
>
<paper-listbox
slot="dropdown-content"
.selected=${this._config.mode
? MODES.indexOf(this._config.mode)
: 0}
@iron-select=${this._modeChanged}
>
</paper-input>`
: ""}
${MODES.map(
(mode) => html`
<paper-item .mode=${mode}>
${this.hass.localize(
`ui.panel.config.script.editor.modes.${mode}`
) || mode}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu-light>
${this._config.mode &&
MODES_MAX.includes(this._config.mode)
? html` <paper-input
.label=${this.hass.localize(
`ui.panel.config.script.editor.max.${this._config.mode}`
)}
type="number"
name="max"
.value=${this._config.max || "10"}
@value-changed=${this._valueChanged}
>
</paper-input>`
: html``}
</div>
${this.scriptEntityId
? html`
<div
class="card-actions layout horizontal justified center"
>
<span></span>
<mwc-button
@click=${this._runScript}
title="${this.hass.localize(
"ui.panel.config.script.picker.activate_script"
)}"
?disabled=${this._dirty}
>
${this.hass.localize(
"ui.card.script.execute"
)}
</mwc-button>
</div>
`
: ``}
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.script.editor.sequence"
)}
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.script.editor.modes.description",
"documentation_link",
html`<a
href="${documentationUrl(
this.hass,
"/integrations/script/#script-modes"
)}"
target="_blank"
rel="noreferrer"
>${this.hass.localize(
"ui.panel.config.script.editor.modes.documentation"
)}</a
>`
"ui.panel.config.script.editor.sequence_sentence"
)}
</p>
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.script.editor.modes.label"
)}
no-animations
<a
href="https://home-assistant.io/docs/scripts/"
target="_blank"
rel="noreferrer"
>
<paper-listbox
slot="dropdown-content"
.selected=${this._config.mode
? MODES.indexOf(this._config.mode)
: 0}
@iron-select=${this._modeChanged}
>
${MODES.map(
(mode) => html`
<paper-item .mode=${mode}>
${this.hass.localize(
`ui.panel.config.script.editor.modes.${mode}`
) || mode}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu-light>
${this._config.mode &&
MODES_MAX.includes(this._config.mode)
? html` <paper-input
.label=${this.hass.localize(
`ui.panel.config.script.editor.max.${this._config.mode}`
)}
type="number"
name="max"
.value=${this._config.max || "10"}
@value-changed=${this._valueChanged}
>
</paper-input>`
: html``}
</div>
${this.scriptEntityId
? html`
<div
class="card-actions layout horizontal justified center"
>
<span></span>
<mwc-button
@click=${this._runScript}
title="${this.hass.localize(
"ui.panel.config.script.picker.activate_script"
)}"
?disabled=${this._dirty}
>
${this.hass.localize("ui.card.script.execute")}
</mwc-button>
</div>
`
: ``}
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
${this.hass.localize(
"ui.panel.config.script.editor.sequence"
)}
</span>
<span slot="introduction">
<p>
${this.hass.localize(
"ui.panel.config.script.editor.sequence_sentence"
)}
</p>
<a
href="${documentationUrl(this.hass, "/docs/scripts/")}"
target="_blank"
rel="noreferrer"
>
${this.hass.localize(
"ui.panel.config.script.editor.link_available_actions"
)}
</a>
</span>
<ha-automation-action
.actions=${this._config.sequence}
@value-changed=${this._sequenceChanged}
.hass=${this.hass}
></ha-automation-action>
</ha-config-section>
`
${this.hass.localize(
"ui.panel.config.script.editor.link_available_actions"
)}
</a>
</span>
<ha-automation-action
.actions=${this._config.sequence}
@value-changed=${this._sequenceChanged}
.hass=${this.hass}
></ha-automation-action>
</ha-config-section>
`
: ""}
</div>
</div>
@@ -325,7 +395,7 @@ export class HaScriptEditor extends LitElement {
}
}
private async _runScript(ev) {
private async _runScript(ev: Event) {
ev.stopPropagation();
await triggerScript(this.hass, this.scriptEntityId);
showToast(this, {
@@ -337,6 +407,21 @@ export class HaScriptEditor extends LitElement {
});
}
private _handleAction(ev: CustomEvent<ActionDetail>) {
switch (ev.detail.index) {
case 0:
this._switchYamlMode();
break;
case 1:
this._deleteConfirm();
break;
}
}
private _switchYamlMode() {
this._yamlMode = !this._yamlMode;
}
private _modeChanged(ev: CustomEvent) {
const mode = ((ev.target as PaperListboxElement)?.selectedItem as any)
?.mode;
@@ -376,6 +461,15 @@ export class HaScriptEditor extends LitElement {
}
}
private _onYamlChange(ev: CustomEvent) {
ev.stopPropagation();
if (!ev.detail.isValid) {
return;
}
this._config = ev.detail.value;
this._dirty = true;
}
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
const target = ev.target as any;

View File

@@ -25,7 +25,6 @@ import { configSections } from "../ha-panel-config";
import "../../../components/ha-svg-icon";
import { mdiPlus } from "@mdi/js";
import { stateIcon } from "../../../common/entity/state_icon";
import { documentationUrl } from "../../../util/documentation-url";
@customElement("ha-script-picker")
class HaScriptPicker extends LitElement {
@@ -188,7 +187,7 @@ class HaScriptPicker extends LitElement {
${this.hass.localize("ui.panel.config.script.picker.introduction")}
<p>
<a
href="${documentationUrl(this.hass, "/docs/scripts/editor/")}"
href="https://home-assistant.io/docs/scripts/editor/"
target="_blank"
rel="noreferrer"
>

View File

@@ -12,8 +12,6 @@ import {
property,
TemplateResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { isServiceLoaded } from "../../../common/config/is_service_loaded";
import { componentsWithService } from "../../../common/config/components_with_service";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-card";
@@ -29,14 +27,13 @@ import { configSections } from "../ha-panel-config";
export class HaConfigServerControl extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public isWide!: boolean;
@property() public isWide!: boolean;
@property({ type: Boolean, attribute: "narrow", reflect: true })
public narrow!: boolean;
@property() public narrow!: boolean;
@property({ attribute: false }) public route!: Route;
@property() public route!: Route;
@property({ type: Boolean }) public showAdvanced!: boolean;
@property() public showAdvanced!: boolean;
@internalProperty() private _validating = false;
@@ -62,191 +59,170 @@ export class HaConfigServerControl extends LitElement {
protected render(): TemplateResult {
return html`
<hass-tabs-subpage
back-path="/config"
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
back-path="/config"
.tabs=${configSections.general}
.showAdvanced=${this.showAdvanced}
>
<ha-config-section
?side-by-side=${!this.showAdvanced}
.narrow=${this.narrow}
.isWide=${this.isWide}
>
<div slot="header">
${this.hass.localize("ui.panel.config.server_control.caption")}
</div>
<div slot="introduction">
${this.hass.localize("ui.panel.config.server_control.description")}
</div>
<div class="content">
${this.showAdvanced
? html`
<ha-card
class="validate-card"
header=${this.hass.localize(
"ui.panel.config.server_control.section.validation.heading"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.validation.introduction"
)}
${!this._validateLog
? html`
<div
class="validate-container layout vertical center-center"
>
${!this._validating
? html`
${this._isValid
? html` <div
class="validate-result"
id="result"
>
${this.hass.localize(
"ui.panel.config.server_control.section.validation.valid"
)}
</div>`
: ""}
<mwc-button
raised
@click=${this._validateConfig}
<ha-config-section .isWide=${this.isWide}>
<span slot="header"
>${this.hass.localize(
"ui.panel.config.server_control.caption"
)}</span
>
<span slot="introduction"
>${this.hass.localize(
"ui.panel.config.server_control.description"
)}</span
>
${this.showAdvanced
? html` <ha-card
header=${this.hass.localize(
"ui.panel.config.server_control.section.validation.heading"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.validation.introduction"
)}
${!this._validateLog
? html`
<div
class="validate-container layout vertical center-center"
>
${!this._validating
? html`
${this._isValid
? html` <div
class="validate-result"
id="result"
>
${this.hass.localize(
"ui.panel.config.server_control.section.validation.check_config"
"ui.panel.config.server_control.section.validation.valid"
)}
</mwc-button>
`
: html`
<ha-circular-progress
active
></ha-circular-progress>
`}
</div>
`
: html`
<div class="config-invalid">
<span class="text">
${this.hass.localize(
"ui.panel.config.server_control.section.validation.invalid"
)}
</span>
<mwc-button raised @click=${this._validateConfig}>
${this.hass.localize(
"ui.panel.config.server_control.section.validation.check_config"
)}
</mwc-button>
</div>
<div id="configLog" class="validate-log">
${this._validateLog}
</div>
`}
</div>
</ha-card>
`
: ""}
</div>`
: ""}
<mwc-button
raised
@click=${this._validateConfig}
>
${this.hass.localize(
"ui.panel.config.server_control.section.validation.check_config"
)}
</mwc-button>
`
: html`
<ha-circular-progress
active
></ha-circular-progress>
`}
</div>
`
: html`
<div class="config-invalid">
<span class="text">
${this.hass.localize(
"ui.panel.config.server_control.section.validation.invalid"
)}
</span>
<mwc-button raised @click=${this._validateConfig}>
${this.hass.localize(
"ui.panel.config.server_control.section.validation.check_config"
)}
</mwc-button>
</div>
<div id="configLog" class="validate-log">
${this._validateLog}
</div>
`}
</div>
</ha-card>`
: ""}
<ha-card
class="server-management-card ${classMap({
"no-advanced": !this.showAdvanced,
})}"
header=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.heading"
<ha-card
header=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.heading"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.server_management.introduction"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.server_management.introduction"
</div>
<div class="card-actions warning">
<ha-call-service-button
class="warning"
.hass=${this.hass}
domain="homeassistant"
service="restart"
.confirmation=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.confirm_restart"
)}
</div>
<div
class="server-management-container layout horizontal center-center warning"
>
<ha-call-service-button
raised
class="warning"
service="restart"
domain="homeassistant"
.hass=${this.hass}
.confirmation=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.confirm_restart"
>${this.hass.localize(
"ui.panel.config.server_control.section.server_management.restart"
)}
</ha-call-service-button>
<ha-call-service-button
class="warning"
.hass=${this.hass}
domain="homeassistant"
service="stop"
confirmation=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.confirm_stop"
)}
>${this.hass.localize(
"ui.panel.config.server_control.section.server_management.stop"
)}
</ha-call-service-button>
</div>
</ha-card>
${this.showAdvanced
? html`
<ha-card
header=${this.hass.localize(
"ui.panel.config.server_control.section.reloading.heading"
)}
>
${this.hass.localize(
"ui.panel.config.server_control.section.server_management.restart"
)}
</ha-call-service-button>
<ha-call-service-button
raised
class="warning"
.hass=${this.hass}
domain="homeassistant"
service="stop"
confirmation=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.confirm_stop"
)}
>
${this.hass.localize(
"ui.panel.config.server_control.section.server_management.stop"
)}
</ha-call-service-button>
</div>
</ha-card>
</div>
</ha-config-section>
<ha-config-section
no-header
.narrow=${this.narrow}
.isWide=${this.isWide}
>
<div class="content">
${this.showAdvanced
? html`
<ha-card
class="reload"
header=${this.hass.localize(
"ui.panel.config.server_control.section.reloading.heading"
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.reloading.introduction"
)}
>
<div class="card-content">
${this.hass.localize(
"ui.panel.config.server_control.section.reloading.introduction"
</div>
<div class="card-actions">
<ha-call-service-button
.hass=${this.hass}
domain="homeassistant"
service="reload_core_config"
>${this.hass.localize(
"ui.panel.config.server_control.section.reloading.core"
)}
</div>
<div class="actions">
<ha-call-service-button
outlined
domain="homeassistant"
service="reload_core_config"
.hass=${this.hass}
>
${this.hass.localize(
"ui.panel.config.server_control.section.reloading.core"
)}
</ha-call-service-button>
${this._reloadableDomains.map((domain) =>
isServiceLoaded(this.hass, domain, "reload")
? html`
<ha-call-service-button
outlined
service="reload"
.hass=${this.hass}
.domain=${domain}
>
${this.hass.localize(
`ui.panel.config.server_control.section.reloading.${domain}`
) || domainToName(this.hass.localize, domain)}
</ha-call-service-button>
`
: ""
)}
</div>
</ha-card>
`
: ""}
</div>
</ha-call-service-button>
</div>
${this._reloadableDomains.map(
(domain) =>
html`<div class="card-actions">
<ha-call-service-button
.hass=${this.hass}
.domain=${domain}
service="reload"
>${this.hass.localize(
`ui.panel.config.server_control.section.reloading.${domain}`
) ||
this.hass.localize(
"ui.panel.config.server_control.section.reloading.reload",
"domain",
domainToName(this.hass.localize, domain)
)}
</ha-call-service-button>
</div>`
)}
</ha-card>
`
: ""}
</ha-config-section>
</hass-tabs-subpage>
`;
@@ -270,48 +246,10 @@ export class HaConfigServerControl extends LitElement {
return [
haStyle,
css`
.heading {
max-width: 1040px;
margin: 0px auto;
}
.heading {
padding: 28px 20px 0px;
}
.content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.validate-card,
.server-management-card {
width: calc(50% - 12px);
}
.header {
font-size: 24px;
line-height: 32px;
padding-bottom: 8px;
opacity: var(--dark-primary-opacity);
}
.description {
opacity: var(--dark-primary-opacity);
font-size: 14px;
padding-bottom: 8px;
}
.validate-container,
.server-management-container {
.validate-container {
height: 140px;
}
.server-management-container ha-call-service-button {
padding-right: 16px;
}
.validate-result {
color: var(--success-color);
font-weight: 500;
@@ -336,50 +274,10 @@ export class HaConfigServerControl extends LitElement {
direction: ltr;
}
.warning {
--mdc-theme-primary: var(--error-color);
}
.reload {
margin-top: 24px;
}
.reload .actions {
width: 100%;
display: flex;
flex-wrap: wrap;
padding-bottom: 8px;
}
.reload ha-call-service-button {
padding: 0 8px;
display: inline-block;
width: calc(33% - 24px);
margin: 4px;
}
:host([narrow]) .validate-card,
:host([narrow]) .server-management-card,
.server-management-card.no-advanced {
width: 100%;
}
:host([narrow]) .server-management-card {
margin-top: 24px;
}
:host([narrow]) .reload ha-call-service-button {
width: 100%;
margin: 8px 0;
border: none;
ha-config-section {
padding-bottom: 24px;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-server-control": HaConfigServerControl;
}
}

View File

@@ -9,7 +9,6 @@ import "../../../components/ha-code-editor";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { EventsMixin } from "../../../mixins/events-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin";
import { documentationUrl } from "../../../util/documentation-url";
import "../../../styles/polymer-ha-style";
import "./event-subscribe-card";
import "./events-list";
@@ -62,7 +61,7 @@ class HaPanelDevEvent extends EventsMixin(LocalizeMixin(PolymerElement)) {
<p>
[[localize( 'ui.panel.developer-tools.tabs.events.description' )]]
<a
href="[[_computeDocumentationUrl(hass)]]"
href="https://www.home-assistant.io/docs/configuration/events/"
target="_blank"
rel="noreferrer"
>
@@ -150,10 +149,6 @@ class HaPanelDevEvent extends EventsMixin(LocalizeMixin(PolymerElement)) {
}
}
_computeDocumentationUrl(hass) {
return documentationUrl(hass, "/docs/configuration/events/");
}
_computeValidJSON(parsedJSON) {
return parsedJSON !== ERROR_SENTINEL;
}

View File

@@ -19,7 +19,6 @@ import {
} from "../../../data/ws-templates";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
const DEMO_TEMPLATE = `{## Imitate available variables: ##}
{% set my_test_json = {
@@ -108,10 +107,7 @@ class HaPanelDevTemplate extends LitElement {
</li>
<li>
<a
href="${documentationUrl(
this.hass,
"/docs/configuration/templating/"
)}"
href="https://home-assistant.io/docs/configuration/templating/"
target="_blank"
rel="noreferrer"
>

View File

@@ -285,7 +285,7 @@ class HaLogbook extends LitElement {
.narrow .entry {
flex-direction: column;
line-height: 1.5;
padding: 8px 0;
padding: 8px;
}
.narrow .icon-message ha-icon {

View File

@@ -63,9 +63,6 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
return {
type: "button",
tap_action: {
action: "toggle",
},
entity: foundEntities[0] || "",
};
}

View File

@@ -115,10 +115,7 @@ export class HuiDialogEditCard extends LitElement implements HassDialog {
const oldConfig = changedProps.get("_cardConfig") as LovelaceCardConfig;
if (oldConfig?.type !== this._cardConfig!.type) {
this._documentationURL = getCardDocumentationURL(
this.hass,
this._cardConfig!.type
);
this._documentationURL = getCardDocumentationURL(this._cardConfig!.type);
}
}

View File

@@ -1,17 +1,14 @@
import {
CUSTOM_TYPE_PREFIX,
getCustomCardEntry,
CUSTOM_TYPE_PREFIX,
} from "../../../data/lovelace_custom_cards";
import { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
export const getCardDocumentationURL = (
hass: HomeAssistant,
type: string
): string | undefined => {
const coreDocumentationURLBase = "https://www.home-assistant.io/lovelace/";
export const getCardDocumentationURL = (type: string): string | undefined => {
if (type.startsWith(CUSTOM_TYPE_PREFIX)) {
return getCustomCardEntry(type)?.documentationURL;
}
return `${documentationUrl(hass, "/lovelace/")}${type}`;
return `${coreDocumentationURLBase}${type}`;
};

View File

@@ -1,32 +1,33 @@
import "@material/mwc-button";
import "@material/mwc-icon-button/mwc-icon-button";
import { mdiHelpCircle } from "@mdi/js";
import {
css,
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
internalProperty,
TemplateResult,
} from "lit-element";
import { mdiHelpCircle } from "@mdi/js";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeRTLDirection } from "../../../common/util/compute_rtl";
import "../../../components/ha-circular-progress";
import "../../../components/ha-dialog";
import "../../../components/ha-formfield";
import "../../../components/ha-svg-icon";
import "../../../components/ha-switch";
import "../../../components/ha-yaml-editor";
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
import { haStyleDialog } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import type { SaveDialogParams } from "./show-save-config-dialog";
import { computeRTLDirection } from "../../../common/util/compute_rtl";
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
import "../../../components/ha-switch";
import "../../../components/ha-formfield";
import "../../../components/ha-yaml-editor";
import "../../../components/ha-svg-icon";
import "../../../components/ha-dialog";
import "../../../components/ha-circular-progress";
const EMPTY_CONFIG = { views: [] };
const coreDocumentationURLBase = "https://www.home-assistant.io/lovelace/";
@customElement("hui-dialog-save-config")
export class HuiSaveConfig extends LitElement implements HassDialog {
@property({ attribute: false }) public hass?: HomeAssistant;
@@ -67,7 +68,7 @@ export class HuiSaveConfig extends LitElement implements HassDialog {
"ui.panel.lovelace.editor.save_config.header"
)}<a
class="header_button"
href=${documentationUrl(this.hass!, "/lovelace/")}
href=${coreDocumentationURLBase}
title=${this.hass!.localize("ui.panel.lovelace.menu.help")}
target="_blank"
rel="noreferrer"

View File

@@ -53,7 +53,6 @@ import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
import { swapView } from "./editor/config-util";
import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog";
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
@@ -137,7 +136,7 @@ class HUIRoot extends LitElement {
</mwc-icon-button>
</div>
<a
href="${documentationUrl(this.hass, "/lovelace/")}"
href="https://www.home-assistant.io/lovelace/"
rel="noreferrer"
class="menu-link"
target="_blank"
@@ -267,7 +266,7 @@ class HUIRoot extends LitElement {
`
: ""}
<a
href="${documentationUrl(this.hass, "/lovelace/")}"
href="https://www.home-assistant.io/lovelace/"
rel="noreferrer"
class="menu-link"
target="_blank"

View File

@@ -17,7 +17,7 @@ import { supportsFeature } from "../../common/entity/supports-feature";
import "../../components/ha-menu-button";
import "../../components/media-player/ha-media-player-browse";
import {
BROWSER_PLAYER,
BROWSER_SOURCE,
MediaPickedEvent,
SUPPORT_BROWSE_MEDIA,
} from "../../data/media-player";
@@ -36,7 +36,7 @@ class PanelMediaBrowser extends LitElement {
// @ts-ignore
@LocalStorage("mediaBrowseEntityId", true)
private _entityId = BROWSER_PLAYER;
private _entityId = BROWSER_SOURCE;
protected render(): TemplateResult {
const stateObj = this._entityId
@@ -44,7 +44,7 @@ class PanelMediaBrowser extends LitElement {
: undefined;
const title =
this._entityId === BROWSER_PLAYER
this._entityId === BROWSER_SOURCE
? `${this.hass.localize("ui.components.media-browser.web-browser")}`
: stateObj?.attributes.friendly_name
? `${stateObj?.attributes.friendly_name}`
@@ -95,7 +95,7 @@ class PanelMediaBrowser extends LitElement {
ev: HASSDomEvent<MediaPickedEvent>
): Promise<void> {
const item = ev.detail.item;
if (this._entityId === BROWSER_PLAYER) {
if (this._entityId === BROWSER_SOURCE) {
const resolvedUrl: any = await this.hass.callWS({
type: "media_source/resolve_media",
media_content_id: item.media_content_id,

View File

@@ -1,5 +1,3 @@
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import {
@@ -15,8 +13,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import { computeStateName } from "../../common/entity/compute_state_name";
import { compare } from "../../common/string/compare";
import { createCloseHeading } from "../../components/ha-dialog";
import { UNAVAILABLE_STATES } from "../../data/entity";
import { BROWSER_PLAYER } from "../../data/media-player";
import { BROWSER_SOURCE } from "../../data/media-player";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import type { SelectMediaPlayerDialogParams } from "./show-select-media-source-dialog";
@@ -52,31 +49,30 @@ export class HuiDialogSelectMediaPlayer extends LitElement {
)}
@closed=${this.closeDialog}
>
<mwc-list>
<mwc-list-item .player=${BROWSER_PLAYER} @click=${this._selectPlayer}
<paper-listbox
attr-for-selected="itemName"
@iron-select=${this._selectSource}
><paper-item .itemName=${BROWSER_SOURCE}
>${this.hass.localize(
"ui.components.media-browser.web-browser"
)}</mwc-list-item
)}</paper-item
>
${this._params.mediaSources
.sort((a, b) => compare(computeStateName(a), computeStateName(b)))
.map(
(source) => html`
<mwc-list-item
.disabled=${UNAVAILABLE_STATES.includes(source.state)}
.player=${source.entity_id}
@click=${this._selectPlayer}
>${computeStateName(source)}</mwc-list-item
<paper-item .itemName=${source.entity_id}
>${computeStateName(source)}</paper-item
>
`
)}
</mwc-list>
</paper-listbox>
</ha-dialog>
`;
}
private _selectPlayer(ev: CustomEvent): void {
const entityId = (ev.currentTarget as any).player;
private _selectSource(ev: CustomEvent): void {
const entityId = ev.detail.item.itemName;
this._params!.sourceSelectedCallback(entityId);
this.closeDialog();
}
@@ -88,8 +84,8 @@ export class HuiDialogSelectMediaPlayer extends LitElement {
ha-dialog {
--dialog-content-padding: 0 24px 20px;
}
mwc-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
paper-item {
cursor: pointer;
}
`,
];

View File

@@ -1,5 +1,4 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-icon-button/mwc-icon-button";
import { mdiDelete } from "@mdi/js";
import {
css,
@@ -81,14 +80,14 @@ class HaLongLivedTokens extends LitElement {
)
)}
</div>
<mwc-icon-button
<mwc-button
.token=${token}
.disabled=${token.is_current}
.title=${this.hass.localize(`ui.common.delete`)}
@click=${this._deleteToken}
>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
</mwc-button>
</ha-settings-row>`
)}
</div>
@@ -186,9 +185,6 @@ class HaLongLivedTokens extends LitElement {
mwc-button {
--mdc-theme-primary: var(--primary-color);
}
mwc-icon-button {
color: var(--primary-text-color);
}
`,
];
}

View File

@@ -201,7 +201,7 @@ class HaPanelProfile extends LitElement {
}
private _customizeSidebar() {
fireEvent(this, "hass-edit-sidebar", { editMode: true });
fireEvent(this, "hass-edit-sidebar");
}
private async _refreshRefreshTokens() {

View File

@@ -1,25 +1,24 @@
import "@material/mwc-button/mwc-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import "../../components/ha-paper-dropdown-menu";
import { TemplateResult, html } from "lit-html";
import {
css,
CSSResult,
customElement,
property,
internalProperty,
LitElement,
property,
customElement,
PropertyValues,
CSSResult,
css,
} from "lit-element";
import { html, TemplateResult } from "lit-html";
import { HomeAssistant } from "../../types";
import "../../components/ha-settings-row";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/ha-formfield";
import "../../components/ha-paper-dropdown-menu";
import "../../components/ha-radio";
import "@polymer/paper-input/paper-input";
import type { HaRadio } from "../../components/ha-radio";
import "../../components/ha-settings-row";
import { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
import "@material/mwc-button/mwc-button";
@customElement("ha-pick-theme-row")
export class HaPickThemeRow extends LitElement {
@@ -46,10 +45,7 @@ export class HaPickThemeRow extends LitElement {
? this.hass.localize("ui.panel.profile.themes.error_no_theme")
: ""}
<a
href="${documentationUrl(
this.hass!,
"/integrations/frontend/#defining-themes"
)}"
href="https://www.home-assistant.io/integrations/frontend/#defining-themes"
target="_blank"
rel="noreferrer"
>

View File

@@ -7,7 +7,6 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { pushSupported } from "../../components/ha-push-notifications-toggle";
import LocalizeMixin from "../../mixins/localize-mixin";
import "../../components/ha-settings-row";
import { documentationUrl } from "../../util/documentation-url";
/*
* @appliesMixin LocalizeMixin
@@ -27,7 +26,7 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
<span slot="description">
[[_description(_platformLoaded, _pushSupported)]]
<a
href="[[_computeDocumentationUrl(hass)]]"
href="https://www.home-assistant.io/integrations/html5"
target="_blank"
rel="noreferrer"
>[[localize('ui.panel.profile.push_notifications.link_promo')]]</a
@@ -60,10 +59,6 @@ class HaPushNotificationsRow extends LocalizeMixin(PolymerElement) {
};
}
_computeDocumentationUrl(hass) {
return documentationUrl(hass, "/integrations/html5");
}
_compPlatformLoaded(hass) {
return isComponentLoaded(hass, "notify.html5");
}

View File

@@ -1,4 +1,4 @@
import "@material/mwc-icon-button/mwc-icon-button";
import "@material/mwc-button/mwc-button";
import { mdiDelete } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip";
import {
@@ -83,14 +83,14 @@ class HaRefreshTokens extends LitElement {
)}
</paper-tooltip>`
: ""}
<mwc-icon-button
<mwc-button
.token=${token}
.disabled=${token.is_current}
.title=${this.hass.localize(`ui.common.delete`)}
@click=${this._deleteToken}
>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
</mwc-button>
</div>
</ha-settings-row>`
)
@@ -135,8 +135,8 @@ class HaRefreshTokens extends LitElement {
ha-settings-row {
padding: 0;
}
mwc-icon-button {
color: var(--primary-text-color);
mwc-button {
--mdc-theme-primary: var(--primary-color);
}
`,
];

View File

@@ -18,22 +18,8 @@ export const sortableStyles = css`
animation-duration: 0.33s;
}
#sortable a {
height: 48px;
display: flex;
}
#sortable {
outline: none;
display: block;
}
.hidden-panel {
display: flex;
}
.sortable-fallback {
display: none;
}
.sortable-ghost {
@@ -68,25 +54,13 @@ export const sortableStyles = css`
}
}
.show-panel,
.hide-panel {
display: none;
position: absolute;
top: 0;
right: 0;
--mdc-icon-button-size: 40px;
}
.hide-panel {
top: 4px;
right: 8px;
}
:host([expanded]) .hide-panel {
display: block;
}
:host([expanded]) .show-panel {
display: inline-flex;
}

View File

@@ -16,11 +16,13 @@ declare global {
interface HASSDomEvents {
"hass-dock-sidebar": DockSidebarParams;
"hass-default-panel": DefaultPanelParams;
"hass-edit-sidebar": undefined;
}
// for add event listener
interface HTMLElementEventMap {
"hass-dock-sidebar": HASSDomEvent<DockSidebarParams>;
"hass-default-panel": HASSDomEvent<DefaultPanelParams>;
"hass-edit-sidebar": undefined;
}
}

View File

@@ -374,12 +374,6 @@
"video_not_supported": "Your browser does not support the video element.",
"media_not_supported": "The Browser Media Player does not support this type of media",
"media_browsing_error": "Media Browsing Error",
"learn_adding_local_media": "Learn more about adding media in the {documentation}.",
"local_media_files": "Place your video, audio and image files in the media directory to be able to browse and play them in the browser or on supported media players.",
"documentation": "documentation",
"no_local_media_found": "No local media found",
"no_media_folder": "It looks like you have not yet created a media directory.",
"setup_local_help": "Check the {documentation} on how to setup local media.",
"class": {
"album": "Album",
"app": "App",
@@ -866,37 +860,38 @@
},
"reloading": {
"heading": "YAML configuration reloading",
"introduction": "Some parts of Home Assistant can reload without requiring a restart. Clicking a button below will unload their current YAML configuration and load the new one.",
"core": "location & customizations",
"group": "groups, group entities, and notify services",
"automation": "automations",
"script": "scripts",
"scene": "scenes",
"person": "persons",
"zone": "zones",
"input_boolean": "input booleans",
"input_text": "input texts",
"input_number": "input numbers",
"input_datetime": "input date times",
"input_select": "input selects",
"template": "template entities",
"universal": "universal media player entities",
"rest": "rest entities and notify services",
"command_line": "command line entities",
"filter": "filter entities",
"statistics": "statistics entities",
"generic": "generic IP camera entities",
"generic_thermostat": "generic thermostat entities",
"homekit": "HomeKit",
"min_max": "min/max entities",
"history_stats": "history stats entities",
"trend": "trend entities",
"ping": "ping binary sensor entities",
"filesize": "file size entities",
"telegram": "telegram notify services",
"smtp": "smtp notify services",
"mqtt": "mqtt entities",
"rpi_gpio": "Raspberry Pi GPIO entities"
"introduction": "Some parts of Home Assistant can reload without requiring a restart. Hitting reload will unload their current YAML configuration and load the new one.",
"reload": "Reload {domain}",
"core": "Reload location & customizations",
"group": "Reload groups, group entities, and notify services",
"automation": "Reload automations",
"script": "Reload scripts",
"scene": "Reload scenes",
"person": "Reload persons",
"zone": "Reload zones",
"input_boolean": "Reload input booleans",
"input_text": "Reload input texts",
"input_number": "Reload input numbers",
"input_datetime": "Reload input date times",
"input_select": "Reload input selects",
"template": "Reload template entities",
"universal": "Reload universal media player entities",
"rest": "Reload rest entities and notify services",
"command_line": "Reload command line entities",
"filter": "Reload filter entities",
"statistics": "Reload statistics entities",
"generic": "Reload generic IP camera entities",
"generic_thermostat": "Reload generic thermostat entities",
"homekit": "Reload HomeKit",
"min_max": "Reload min/max entities",
"history_stats": "Reload history stats entities",
"trend": "Reload trend entities",
"ping": "Reload ping binary sensor entities",
"filesize": "Reload file size entities",
"telegram": "Reload telegram notify services",
"smtp": "Reload smtp notify services",
"mqtt": "Reload mqtt entities",
"rpi_gpio": "Reload Raspberry Pi GPIO entities"
},
"server_management": {
"heading": "Server management",
@@ -1321,8 +1316,6 @@
"description_login": "Logged in as {email}",
"description_not_login": "Not logged in",
"description_features": "Control away from home, integrate with Alexa and Google Assistant.",
"enabled": "Enabled",
"disabled": "Disabled",
"login": {
"title": "Cloud Login",
"introduction": "Home Assistant Cloud provides you with a secure remote connection to your instance while away from home. It also allows you to connect with cloud-only services: Amazon Alexa and Google Assistant.",
@@ -2157,7 +2150,7 @@
"save": "Save",
"unsaved_changes": "Unsaved changes",
"saved": "Saved",
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration?",
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration? We will automatically generate your Lovelace UI views with your areas and devices.",
"confirm_remove_config_text": "We will automatically generate your Lovelace UI views with your areas and devices if you remove your Lovelace UI configuration.",
"confirm_unsaved_changes": "You have unsaved changes, are you sure you want to exit?",
"confirm_unsaved_comments": "Your configuration contains comment(s), these will not be saved. Do you want to continue?",

View File

@@ -1,11 +0,0 @@
import { HomeAssistant } from "../types";
export const documentationUrl = (hass: HomeAssistant, path: string) => {
return `https://${
hass.config.version.includes("b")
? "rc"
: hass.config.version.includes("dev")
? "next"
: "www"
}.home-assistant.io${path}`;
};

View File

@@ -1,19 +0,0 @@
import * as assert from "assert";
import { documentationUrl } from "../../src/util/documentation-url";
describe("Generate documentation URL", function () {
it("Generate documentation url for stable", function () {
assert.strictEqual(
// @ts-ignore
documentationUrl({ config: { version: "1.0.0" } }, "/blog"),
"https://www.home-assistant.io/blog"
);
});
it("Generate documentation url for rc", function () {
assert.strictEqual(
// @ts-ignore
documentationUrl({ config: { version: "1.0.0b0" } }, "/blog"),
"https://rc.home-assistant.io/blog"
);
});
});

View File

@@ -507,7 +507,6 @@
"cancel": "Cancel·la",
"close": "Tanca",
"continue": "Continua",
"copied": "Copiat",
"delete": "Elimina",
"error_required": "Obligatori",
"loading": "Carregant",

View File

@@ -507,7 +507,6 @@
"cancel": "Zrušit",
"close": "Zavřít",
"continue": "Pokračovat",
"copied": "Zkopírováno",
"delete": "Smazat",
"error_required": "Povinné",
"loading": "Načítání",

View File

@@ -419,7 +419,6 @@
"unlock": "Entriegeln"
},
"media_player": {
"media_next_track": "Weiter",
"media_play": "Abspielen",
"sound_mode": "Sound-Modus",
"source": "Quelle",
@@ -502,8 +501,6 @@
"back": "Zurück",
"cancel": "Abbrechen",
"close": "Schließen",
"continue": "Weiter",
"copied": "Kopiert",
"delete": "Löschen",
"error_required": "Benötigt",
"loading": "Laden",
@@ -560,24 +557,8 @@
"loading_history": "Lade Zustandsverlauf...",
"no_history_found": "Kein Zustandsverlauf gefunden."
},
"logbook": {
"entries_not_found": "Keine Logbucheinträge gefunden."
},
"media-browser": {
"audio_not_supported": "Ihr Browser unterstützt das Audioelement nicht.",
"choose-source": "Quelle wählen",
"class": {
"album": "Album",
"app": "App",
"directory": "Bibliothek",
"episode": "Episode",
"game": "Spiel",
"movie": "Film",
"music": "Musik",
"season": "Episode",
"url": "URL",
"video": "Video"
},
"content-type": {
"album": "Album",
"artist": "Künstler",
@@ -585,13 +566,7 @@
"playlist": "Playlist",
"server": "Server"
},
"no_items": "Keine Einträge",
"play": "Abspielen",
"video_not_supported": "Ihr Browser unterstützt das Videoelement nicht."
},
"picture-upload": {
"label": "Bild",
"unsupported_format": "Nicht unterstütztes Format, bitte wähle ein JPEG-, PNG- oder GIF-Bild."
"play": "Abspielen"
},
"related-items": {
"area": "Bereich",
@@ -697,10 +672,8 @@
"yaml_not_editable": "Die Einstellungen dieser Entität können nicht über die Benutzeroberfläche bearbeitet werden. Nur über die Benutzeroberfläche eingerichtete Entitäten können über die Benutzeroberfläche konfiguriert werden."
},
"more_info_control": {
"details": "Details",
"dismiss": "Dialog ausblenden",
"edit": "Entität bearbeiten",
"history": "Verlauf",
"person": {
"create_zone": "Zone vom aktuellen Standort erstellen"
},
@@ -876,13 +849,7 @@
"type_select": "Aktionstyp",
"type": {
"choose": {
"add_option": "Option hinzufügen",
"conditions": "Bedingungen",
"default": "Standard-Aktionen",
"label": "Auswählen",
"option": "Option {number}",
"remove_option": "Option entfernen",
"sequence": "Aktionen"
"label": "Auswählen"
},
"condition": {
"label": "Bedingung"
@@ -905,7 +872,6 @@
},
"repeat": {
"label": "Wiederholen",
"sequence": "Aktionen",
"type_select": "Wiederholungstyp",
"type": {
"count": {
@@ -1078,7 +1044,6 @@
"value_template": "Wert-Template (optional)"
},
"state": {
"attribute": "Attribut (Optional)",
"for": "Für",
"from": "Von",
"label": "Zustand",
@@ -1103,8 +1068,7 @@
},
"time": {
"at": "Um",
"label": "Zeit",
"type_value": "Feste Zeit"
"label": "Zeit"
},
"webhook": {
"label": "Webhook",
@@ -1127,8 +1091,6 @@
"add_automation": "Automatisierung hinzufügen",
"delete_automation": "Automatisierung löschen",
"delete_confirm": "Bist du sicher, dass du diese Automatisierung löschen möchtest?",
"duplicate": "Duplizieren",
"duplicate_automation": "Automatisierung kopieren",
"edit_automation": "Automatisierung bearbeiten",
"header": "Automatisierungseditor",
"headers": {
@@ -1352,7 +1314,6 @@
}
},
"devices": {
"add_prompt": "Mit diesem Gerät wurden noch keine {name} hinzugefügt. Du kannst eins hinzufügen, indem du auf den + Knopf drückst.",
"automation": {
"actions": {
"caption": "Wenn etwas ausgelöst wird ..."
@@ -1516,7 +1477,6 @@
},
"integrations": {
"add_integration": "Integration hinzufügen",
"attention": "Aufmerksamkeit erforderlich",
"caption": "Integrationen",
"config_entry": {
"area": "In {area}",
@@ -1535,8 +1495,6 @@
"no_device": "Entitäten ohne Geräte",
"no_devices": "Diese Integration hat keine Geräte.",
"options": "Optionen",
"reload": "Neu laden",
"reload_confirm": "Die Integration wurde neu geladen",
"rename": "Umbenennen",
"restart_confirm": "Starte Home Assistant neu, um das Entfernen dieser Integration abzuschließen",
"settings_button": "Einstellungen für {integration} bearbeiten",
@@ -1585,7 +1543,6 @@
"none_found_detail": "Passe deine Suchkriterien an.",
"note_about_integrations": "Nicht alle Integrationen können über die Benutzeroberfläche konfiguriert werden.",
"note_about_website_reference": "Weitere Informationen findest du auf der ",
"reconfigure": "Neu konfigurieren",
"rename_dialog": "Bearbeite den Namen dieses Konfigurationseintrags",
"rename_input_label": "Eintragsname",
"search": "Such-Integrationen"
@@ -1696,11 +1653,8 @@
"topic": "Topic"
},
"ozw": {
"button": "Konfigurieren",
"common": {
"instance": "Instanz",
"network": "Netzwerk",
"zwave": "Z-Wave"
"instance": "Instanz"
},
"device_info": {
"zwave_info": "Z-Wave Infos"
@@ -1710,27 +1664,12 @@
"select_instance": "Instanz auswählen"
},
"network_status": {
"details": {
"driverremoved": "Der Treiber wurde entfernt",
"driverreset": "Der Treiber wurde zurückgesetzt",
"ready": "Bereit zum Verbinden",
"started": "Verbindung mit MQTT hergestellt",
"starting": "Verbinde zu MQTT"
},
"offline": "Offline",
"online": "Online",
"starting": "Startet",
"unknown": "Unbekannt"
},
"network": {
"header": "Netzwerkverwaltung"
},
"nodes_table": {
"failed": "Fehlgeschlagen",
"manufacturer": "Hersteller"
},
"refresh_node": {
"start_refresh_button": "Aktualisierung starten"
}
},
"person": {
@@ -1859,7 +1798,6 @@
"core": "Ort & Anpassungen neu laden",
"group": "Gruppen neu laden",
"heading": "Neuladen der YAML-Konfiguration",
"homekit": "HomeKit neu laden",
"input_boolean": "Eingabe-Booleans neu laden",
"input_datetime": "Eingabe-Datums- und Zeitfelder neu laden",
"input_number": "Eingabenummern neu laden",
@@ -1869,7 +1807,6 @@
"person": "Personen neu laden",
"scene": "Szenen neu laden",
"script": "Skripte neu laden",
"telegram": "Telegram-Benachrichtigungsdienste neu laden",
"zone": "Zonen neu laden"
},
"server_management": {
@@ -1891,18 +1828,12 @@
},
"tags": {
"detail": {
"delete": "Löschen",
"description": "Beschreibung",
"name": "Name",
"update": "Aktualisieren"
},
"edit": "Bearbeiten",
"headers": {
"last_scanned": "Zuletzt gescannt",
"name": "Name"
},
"never_scanned": "Nie gescannt",
"write": "Schreiben"
"headers": {
"name": "Name"
},
"never_scanned": "Nie gescannt"
},
"users": {
"add_user": {
@@ -1910,7 +1841,6 @@
"create": "Benutzerkonto anlegen",
"name": "Name",
"password": "Passwort",
"password_confirm": "Passwort bestätigen",
"username": "Benutzername"
},
"caption": "Benutzer",
@@ -1927,9 +1857,7 @@
"group": "Gruppe",
"id": "ID",
"name": "Name",
"new_password": "Neues Passwort",
"owner": "Besitzer",
"password_changed": "Das Passwort wurde geändert!",
"system_generated": "System generiert",
"system_generated_users_not_editable": "Systemgenerierte Benutzer können nicht aktualisiert werden.",
"system_generated_users_not_removable": "Vom System generierte Benutzer können nicht entfernt werden.",
@@ -2800,9 +2728,6 @@
"submit": "Absenden"
},
"current_user": "Sie sind derzeit als {fullName} angemeldet.",
"customize_sidebar": {
"button": "Bearbeiten"
},
"dashboard": {
"description": "Wähle ein Standard-Dashboard für dieses Gerät.",
"dropdown_label": "Dashboard",
@@ -2825,7 +2750,6 @@
"confirm_delete": "Möchten Sie den Zugriffs-Token für {name} wirklich löschen?",
"create": "Token erstellen",
"create_failed": "Das Zugriffs-Token konnte nicht erstellt werden.",
"created": "Erstellt am {date}",
"created_at": "Erstellt am {date}",
"delete_failed": "Fehler beim Löschen des Zugriffs-Tokens.",
"description": "Erstelle langlebige Zugriffstoken, damit deine Skripte mit deiner Home Assistant-Instanz interagieren können. Jedes Token ist ab der Erstellung für 10 Jahre gültig. Die folgenden langlebigen Zugriffstoken sind derzeit aktiv.",
@@ -2833,7 +2757,6 @@
"header": "Langlebige Zugangs-Token",
"last_used": "Zuletzt verwendet am {date} in {location}",
"learn_auth_requests": "Erfahre, wie du authentifizierte Anfragen stellen kannst.",
"name": "Name",
"not_used": "Wurde noch nie benutzt",
"prompt_copy_token": "Kopiere deinen Zugangs-Token. Er wird nicht wieder angezeigt werden.",
"prompt_name": "Name?"
@@ -2885,8 +2808,7 @@
"error_no_theme": "Keine Themen verfügbar.",
"header": "Thema",
"link_promo": "Erfahre mehr über Themen",
"primary_color": "Primärfarbe",
"reset": "zurücksetzen"
"primary_color": "Primärfarbe"
},
"vibrate": {
"description": "Aktiviere oder deaktiviere die Vibration an diesem Gerät, wenn du Geräte steuerst.",
@@ -2900,7 +2822,6 @@
}
},
"sidebar": {
"done": "fertig",
"external_app_configuration": "App-Konfiguration",
"sidebar_toggle": "Seitenleiste umschalten"
}

View File

@@ -2692,7 +2692,7 @@
},
"raw_editor": {
"confirm_remove_config_text": "We will automatically generate your Lovelace UI views with your areas and devices if you remove your Lovelace UI configuration.",
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration?",
"confirm_remove_config_title": "Are you sure you want to remove your Lovelace UI configuration? We will automatically generate your Lovelace UI views with your areas and devices.",
"confirm_unsaved_changes": "You have unsaved changes, are you sure you want to exit?",
"confirm_unsaved_comments": "Your configuration contains comment(s), these will not be saved. Do you want to continue?",
"error_invalid_config": "Your configuration is not valid: {error}",

View File

@@ -507,7 +507,6 @@
"cancel": "Cancelar",
"close": "Cerrar",
"continue": "Continuar",
"copied": "Copiado",
"delete": "Eliminar",
"error_required": "Obligatorio",
"loading": "Cargando",
@@ -568,27 +567,11 @@
"loading_history": "Cargando historial de estado...",
"no_history_found": "No se encontró historial de estado."
},
"logbook": {
"entries_not_found": "No se han encontrado entradas en el registro."
},
"media-browser": {
"audio_not_supported": "Tu navegador no es compatible con el elemento de audio.",
"choose_player": "Elige reproductor",
"choose-source": "Elige la fuente",
"class": {
"album": "Álbum",
"app": "Aplicación",
"artist": "Artista",
"channel": "Canal",
"composer": "Compositor",
"contributing_artist": "Artista colaborador",
"directory": "Biblioteca",
"episode": "Episodio",
"game": "Juego",
"genre": "Género",
"image": "Imagen",
"movie": "Película",
"music": "Música",
"playlist": "Lista de reproducción",
"podcast": "Podcast",
"season": "Temporada",
@@ -729,7 +712,6 @@
},
"more_info_control": {
"controls": "Controles",
"details": "Detalles",
"dismiss": "Descartar diálogo",
"edit": "Editar entidad",
"history": "Historial",
@@ -2375,14 +2357,9 @@
"title": "Estados"
},
"templates": {
"all_listeners": "Esta plantilla escucha todos los eventos de cambio de estado.",
"description": "Las plantillas se muestran utilizando el motor de plantillas Jinja2 con algunas extensiones específicas de Home Assistant.",
"domain": "Dominio",
"editor": "Editor de plantillas",
"entity": "Entidad",
"jinja_documentation": "Documentación de plantilla Jinja2",
"listeners": "Esta plantilla escucha los siguientes eventos de cambio de estado:",
"no_listeners": "Esta plantilla no escucha ningún evento de cambio de estado y no se actualizará automáticamente.",
"reset": "Reiniciar a la plantilla de demostración",
"template_extensions": "Extensiones de plantilla de Home Assistant",
"title": "Plantillas",
@@ -2969,11 +2946,6 @@
"submit": "Enviar"
},
"current_user": "Has iniciado sesión como {fullName}.",
"customize_sidebar": {
"button": "Editar",
"description": "También puedes mantener pulsada la cabecera de la barra lateral para activar el modo de edición.",
"header": "Cambiar el orden y ocultar elementos de la barra lateral"
},
"dashboard": {
"description": "Selecciona un panel de control predeterminado para este dispositivo.",
"dropdown_label": "Panel de control",
@@ -2996,7 +2968,6 @@
"confirm_delete": "¿Estás seguro de que quieres eliminar el token de acceso para {name}?",
"create": "Crear Token",
"create_failed": "No se ha podido crear el token de acceso.",
"created": "Creado en {date}",
"created_at": "Creado el {date}",
"delete_failed": "Error al eliminar el token de acceso.",
"description": "Crea tokens de acceso de larga duración para permitir que tus scripts interactúen con tu instancia de Home Assistant. Cada token será válido por 10 años desde la creación. Los siguientes tokens de acceso de larga duración están actualmente activos.",
@@ -3004,10 +2975,9 @@
"header": "Tokens de acceso de larga duración",
"last_used": "Último uso el {date} desde {location}",
"learn_auth_requests": "Aprende cómo realizar solicitudes autenticadas.",
"name": "Nombre",
"not_used": "Nunca ha sido usado",
"prompt_copy_token": "Copia tu token de acceso. No se mostrará de nuevo.",
"prompt_name": "Dale un nombre al token"
"prompt_name": "¿Nombre?"
},
"mfa_setup": {
"close": "Cerrar",
@@ -3071,7 +3041,6 @@
}
},
"sidebar": {
"done": "Hecho",
"external_app_configuration": "Configuración de la aplicación",
"sidebar_toggle": "Alternar barra lateral"
}

View File

@@ -507,7 +507,6 @@
"cancel": "Annuler",
"close": "Fermer",
"continue": "Continuer",
"copied": "Copié",
"delete": "Supprimer",
"error_required": "Obligatoire",
"loading": "Chargement",
@@ -568,35 +567,10 @@
"loading_history": "Chargement de l'historique des valeurs ...",
"no_history_found": "Aucun historique des valeurs trouvé."
},
"logbook": {
"entries_not_found": "Aucune entrée trouvée dans le journal."
},
"media-browser": {
"audio_not_supported": "Votre navigateur ne prend pas en charge l'élément audio.",
"choose_player": "Choisissez le lecteur",
"choose-source": "Choisissez la source",
"class": {
"album": "Album",
"app": "App",
"artist": "Artiste",
"channel": "Canal",
"composer": "Compositeur",
"contributing_artist": "Artiste collaborateur",
"directory": "Bibliothèque",
"episode": "Épisode",
"game": "Jeu",
"genre": "Genre",
"image": "Image",
"movie": "Film",
"music": "Musique",
"playlist": "Liste de lecture",
"podcast": "Podcast",
"season": "Saison",
"track": "Piste",
"tv_show": "Émission de télévision",
"url": "Url",
"video": "Vidéo"
},
"content-type": {
"album": "Album",
"artist": "Artiste",
@@ -729,7 +703,6 @@
},
"more_info_control": {
"controls": "Contrôles",
"details": "Détails",
"dismiss": "Fermer la fenêtre de dialogue",
"edit": "Modifier l'entité",
"history": "Historique",
@@ -961,12 +934,9 @@
"service_data": "Données du service"
},
"wait_for_trigger": {
"continue_timeout": "Continuer à l'expiration du délai",
"label": "Attendre le déclencheur",
"timeout": "Délai d'expiration (optionnel)"
"label": "Attendre le déclencheur"
},
"wait_template": {
"continue_timeout": "Continuer à l'expiration du délai",
"label": "Attendre",
"timeout": "Délai d'expiration (optionnel)",
"wait_template": "Template d'attente"
@@ -1030,9 +1000,7 @@
"time": {
"after": "Après",
"before": "Avant",
"label": "Heure",
"type_input": "Valeur d'une aide de date/heure",
"type_value": "Temps fixe"
"label": "Heure"
},
"zone": {
"entity": "Entité avec localisation",
@@ -1599,7 +1567,6 @@
"reload_restart_confirm": "Redémarrer Home Assistant pour finaliser le rechargement de cette intégration",
"rename": "Renommer",
"restart_confirm": "Redémarrer Home Assistant pour terminer la suppression de cette intégration",
"services": "{count} {count, plural,\n one {service}\n other {services}\n}",
"settings_button": "Modifier les paramètres pour {integration}",
"system_options": "Options système",
"system_options_button": "Options système pour {integration}",
@@ -2375,14 +2342,9 @@
"title": "États"
},
"templates": {
"all_listeners": "Ce modèle écoute tous les événements de changement d'état.",
"description": "Les modèles sont rendus à l'aide du moteur de modèles Jinja2 avec certaines extensions spécifiques de Home Assistant.",
"domain": "Domaine",
"editor": "Éditeur de modèles",
"entity": "Entité",
"jinja_documentation": "Documentation de modèle Jinja2",
"listeners": "Ce modèle écoute les événements de changement d'état suivants:",
"no_listeners": "Ce modèle n'écoute aucun événement de changement d'état et ne sera pas mis à jour automatiquement.",
"reset": "Réinitialiser au modèle de démonstration",
"template_extensions": "Extensions de modèles de Home Assistant",
"title": "Modèle",
@@ -2969,11 +2931,6 @@
"submit": "Envoyer"
},
"current_user": "Vous êtes actuellement connecté en tant que {fullName}.",
"customize_sidebar": {
"button": "Modifier",
"description": "Vous pouvez également appuyer et maintenir l'en-tête de la barre latérale pour activer le mode d'édition.",
"header": "Modifier l'ordre et masquer les éléments de la barre latérale"
},
"dashboard": {
"description": "Choisissez un tableau de bord par défaut pour cet appareil.",
"dropdown_label": "Tableau de bord",
@@ -2996,7 +2953,6 @@
"confirm_delete": "Êtes-vous sûr de vouloir supprimer le jeton d'accès de {name} ?",
"create": "Créer un jeton",
"create_failed": "Impossible de créer le jeton d'accès.",
"created": "Créé le {date}",
"created_at": "Créé le {date}",
"delete_failed": "Impossible de supprimer le jeton d'accès.",
"description": "Créez des jetons d'accès de longue durée pour permettre à vos scripts d'interagir avec votre instance de Home Assistant. Chaque jeton sera valable 10 ans à compter de sa création. Les jetons d'accès longue durée suivants sont actuellement actifs.",
@@ -3004,7 +2960,6 @@
"header": "Jetons d'accès de longue durée",
"last_used": "Dernière utilisation le {date} à partir de {location}",
"learn_auth_requests": "Apprenez comment faire des demandes authentifiées.",
"name": "Nom",
"not_used": "N'a jamais été utilisé",
"prompt_copy_token": "Copiez votre jeton d'accès. Il ne sera plus affiché à nouveau.",
"prompt_name": "Nom ?"
@@ -3071,7 +3026,6 @@
}
},
"sidebar": {
"done": "Terminé",
"external_app_configuration": "Configuration de l'application",
"sidebar_toggle": "Activer la barre latérale"
}

View File

@@ -507,7 +507,6 @@
"cancel": "Avbryt",
"close": "Lukk",
"continue": "Fortsette",
"copied": "Kopiert",
"delete": "Slett",
"error_required": "Nødvendig",
"loading": "Laster",
@@ -2375,14 +2374,11 @@
"title": "Tilstander"
},
"templates": {
"all_listeners": "Denne malen lytter etter alle tilstandsfornede hendelser.",
"description": "Maler blir rendret ved hjelp av Jinja2-malmotoren med noen spesifikke utvidelser for Home Assistant.",
"domain": "Domene",
"editor": "Maleditor",
"entity": "Entitet",
"jinja_documentation": "Jinja2 mal dokumentasjon",
"listeners": "Denne malen lytter etter følgende tilstandsfor endrede hendelser:",
"no_listeners": "Denne malen lytter ikke etter eventuelle tilstandsfornedne hendelser og oppdateres ikke automatisk.",
"reset": "Tilbakestill til demomal",
"template_extensions": "Mal utvidelser for Home Assistant",
"title": "Mal",
@@ -2970,8 +2966,6 @@
},
"current_user": "Du er logget inn som {fullName}.",
"customize_sidebar": {
"button": "Redigere",
"description": "Du kan også trykke på og holde nede overskriften på sidefeltet for å aktivere redigeringsmodus.",
"header": "Endre rekkefølgen og skjul elementer fra sidepanelet"
},
"dashboard": {
@@ -3007,7 +3001,7 @@
"name": "Navn",
"not_used": "Har aldri blitt brukt",
"prompt_copy_token": "Kopier tilgangstoken. Det blir ikke vist igjen.",
"prompt_name": "Gi tokenet et navn"
"prompt_name": "Navn?"
},
"mfa_setup": {
"close": "Lukk",

View File

@@ -507,7 +507,6 @@
"cancel": "Annuleren",
"close": "Sluiten",
"continue": "Ga verder",
"copied": "Gekopieerd",
"delete": "Verwijderen",
"error_required": "Verplicht",
"loading": "Bezig met laden",
@@ -2375,14 +2374,11 @@
"title": "Toestanden"
},
"templates": {
"all_listeners": "Deze template luistert naar alle gebeurtenissen met gewijzigde status.",
"description": "Sjablonen worden weergegeven met de Jinja2-sjabloonediter samen met enkele extensies van Home Assistant.",
"domain": "Domein",
"editor": "Sjabloonediter",
"entity": "Entiteit",
"jinja_documentation": "Jinja2-sjabloondocumentatie",
"listeners": "Deze template luistert naar de volgende gebeurtenissen met gewijzigde status:",
"no_listeners": "Deze template luistert niet naar gebeurtenissen met statuswijziging en wordt niet automatisch bijgewerkt.",
"reset": "Resetten naar demosjabloon",
"template_extensions": "Home Assistant sjabloon extensiesHome Assistant",
"title": "Sjablonen",
@@ -3007,7 +3003,7 @@
"name": "Naam",
"not_used": "Is nog nooit gebruikt",
"prompt_copy_token": "Kopieer je toegangstoken. Het wordt niet meer getoond.",
"prompt_name": "Geef het token een naam"
"prompt_name": "Naam?"
},
"mfa_setup": {
"close": "Sluiten",

View File

@@ -507,7 +507,6 @@
"cancel": "Anuluj",
"close": "Zamknij",
"continue": "Kontynuuj",
"copied": "Skopiowano",
"delete": "Usuń",
"error_required": "To pole jest wymagane",
"loading": "Ładowanie",

View File

@@ -489,7 +489,6 @@
"back": "Înapoi",
"cancel": "Revocare",
"close": "Închide",
"copied": "Copiat",
"delete": "Șterge",
"error_required": "Necesar",
"loading": "Se încarcă",
@@ -545,32 +544,6 @@
"loading_history": "Încărcarea istoricului de stare ...",
"no_history_found": "Nici un istoric de stare nu a fost găsit."
},
"logbook": {
"entries_not_found": "Nu s-au găsit intrări în jurnal."
},
"media-browser": {
"class": {
"album": "Album",
"app": "Aplicație",
"artist": "Artist",
"channel": "Canal",
"composer": "Compozitor",
"contributing_artist": "Artist contribuitor",
"directory": "Bibliotecă",
"episode": "Episod",
"game": "Joc",
"genre": "Gen",
"image": "Imagine",
"movie": "Film",
"music": "Muzică",
"playlist": "Playlist",
"podcast": "Podcast",
"season": "Sezon",
"tv_show": "Emisiune TV",
"url": "Url",
"video": "Video"
}
},
"related-items": {
"area": "Zonă",
"automation": "Parte din următoarele automatizări",
@@ -674,7 +647,6 @@
"yaml_not_editable": "Setările acestei entități nu se pot edita din interfața grafica. Numai entitățile configurate in interfața grafica sunt configurabile din interfața grafica."
},
"more_info_control": {
"details": "Detalii",
"dismiss": "Se respinge dialogul",
"edit": "Editează entitatea",
"person": {
@@ -878,13 +850,7 @@
"label": "Cheama serviciu",
"service_data": "Date serviciu"
},
"wait_for_trigger": {
"continue_timeout": "Continua la timeout",
"label": "Așteptați declanșatorul",
"timeout": "Timeout (optional)"
},
"wait_template": {
"continue_timeout": "Continuați la expirare",
"label": "Asteptare",
"timeout": "Timeout (opțional)",
"wait_template": "Sablon Asteptare"
@@ -1294,7 +1260,6 @@
},
"integrations": {
"add_integration": "Adăugați integrare",
"attention": "Atenție necesară",
"caption": "Integrări",
"config_entry": {
"delete": "Șterge",
@@ -1352,7 +1317,6 @@
"none": "Nimic nu a fost configurat încă",
"none_found": "Nu s-au găsit integrări",
"none_found_detail": "Ajustați criteriile de căutare.",
"reconfigure": "Reconfigurați",
"rename_dialog": "Editați numele acestei intrări de configurare",
"rename_input_label": "Introdu nume",
"search": "Căutare integrari"
@@ -1884,14 +1848,9 @@
"title": "Status"
},
"templates": {
"all_listeners": "Acest șablon ascultă următoarele evenimente modificate de stare:",
"description": "Șabloanele sunt redate utilizând motorul de șablon Jinja2 cu unele extensii specifice Home Assistant.",
"domain": "Domeniu",
"editor": "Editor șabloane",
"entity": "Entitate",
"jinja_documentation": "Șablon documentație Jinja2",
"listeners": "Acest șablon ascultă următoarele evenimente modificate de stare:",
"no_listeners": "Acest șablon ascultă următoarele evenimente modificate de stare:",
"template_extensions": "Șabloane de extensie pentru Home Assistant",
"title": "Sabloane",
"unknown_error_template": "Sa produs o eroare de randare necunoscută."
@@ -2394,11 +2353,6 @@
"submit": "Trimite"
},
"current_user": "În prezent sunteți conectat ca {fullName}.",
"customize_sidebar": {
"button": "Editeaza",
"description": "De asemenea, puteți apăsa și ține apăsat antetul barei laterale pentru a activa modul de editare.",
"header": "Schimbați ordinea și ascundeți elementele din bara laterală"
},
"dashboard": {
"description": "Alegeți un tablou de bord implicit pentru acest dispozitiv.",
"dropdown_label": "Tablou de bord",
@@ -2421,7 +2375,6 @@
"confirm_delete": "Sigur doriti sa stergeti tokenul de acces pentru {name}?",
"create": "Creaza un Token",
"create_failed": "Crearea tokenului de acces eşuată",
"created": "Creat in {data}",
"created_at": "Creat in {date}",
"delete_failed": "Ştergerea tokenului de acces eşuată",
"description": "Creați tokenuri de acces cu durată lungă de viață pentru a permite script-urilor dvs. să interacționeze cu instanța dvs. Home Assistant. Fiecare token va fi valabil timp de 10 ani de la creatie. Următoarele tokenuri de acces de lungă durată sunt active la ora actuala.",
@@ -2429,7 +2382,6 @@
"header": "Tokenuri de acces de lunga durata",
"last_used": "Ultima utilizare la {date} din {location}",
"learn_auth_requests": "Aflați cum să faceți cereri autentificate.",
"name": "Nume",
"not_used": "Nu a fost utilizat niciodata",
"prompt_copy_token": "Copia token-ul de acces. Acesta nu va fi afișat din nou.",
"prompt_name": "Nume?"
@@ -2491,7 +2443,6 @@
}
},
"sidebar": {
"done": "Terminat",
"external_app_configuration": "Configurație aplicație",
"sidebar_toggle": "Schimbati bara laterală"
}

View File

@@ -507,7 +507,6 @@
"cancel": "Отменить",
"close": "Закрыть",
"continue": "Продолжить",
"copied": "Скопировано",
"delete": "Удалить",
"error_required": "Обязательное поле",
"loading": "Загрузка",
@@ -581,7 +580,6 @@
"artist": "Исполнитель",
"channel": "Канал",
"composer": "Композитор",
"contributing_artist": "Соисполнитель",
"directory": "Библиотека",
"episode": "Эпизод",
"game": "Игра",
@@ -2375,14 +2373,11 @@
"title": "Состояния"
},
"templates": {
"all_listeners": "Этот шаблон отслеживает все события изменения состояния.",
"description": "Здесь Вы можете протестировать поведение шаблонов. В Home Assistant используется шаблонизатор Jinja2 с некоторыми специальными расширениями.",
"domain": "Домен",
"editor": "Редактор шаблонов",
"entity": "Объект",
"jinja_documentation": "Узнайте больше о шаблонизаторе Jinja2",
"listeners": "Этот шаблон отслеживает следующие события изменения состояния:",
"no_listeners": "Этот шаблон не отслеживает события изменения состояния и не обновляется автоматически.",
"reset": "Вернуться к демонстрационному шаблону",
"template_extensions": "Узнайте больше о шаблонах Home Assistant",
"title": "Шаблоны",

View File

@@ -507,7 +507,6 @@
"cancel": "取消",
"close": "關閉",
"continue": "繼續",
"copied": "已複製",
"delete": "刪除",
"error_required": "必填",
"loading": "讀取中",