Compare commits

...

16 Commits

Author SHA1 Message Date
Zack Arnett
359ddbf284 continued updates 2020-09-22 20:28:26 -05:00
Zack Arnett
49725b4fd3 media query 2020-09-19 01:12:03 -05:00
Zack Arnett
74183b93e7 more 2020-09-17 23:45:03 -05:00
Zack Arnett
ac711e8abc Fisrt commit of complete redesign 2020-09-17 15:31:47 -05:00
Zack Barett
c2cace0dd8 Merge branch 'dev' into confdig-section-redesign 2020-09-15 09:11:14 -05:00
Zack Arnett
2594fcbe33 remove translation redundency 2020-09-07 12:06:14 -05:00
Zack Arnett
96d220468e comments 2020-09-06 01:43:05 -05:00
Zack Arnett
7a73cf444e Update wording 2020-09-06 01:19:29 -05:00
Zack Arnett
220fae44b9 Merge branch 'confdig-section-redesign' of https://github.com/home-assistant/frontend into confdig-section-redesign 2020-09-06 01:12:27 -05:00
Zack Arnett
9e60e36a7e Update style 2020-09-06 01:10:51 -05:00
Zack Arnett
05cc3d71aa Merge branch 'dev' into confdig-section-redesign 2020-09-03 17:02:21 -05:00
Zack Arnett
5b031f46f2 Comments 2020-08-31 15:08:34 -05:00
Zack Arnett
ec2e3bcada Merge branch 'dev' of https://github.com/home-assistant/frontend into confdig-section-redesign 2020-08-31 14:38:35 -05:00
Zack Arnett
3f631cc34a Merge branch 'dev' of https://github.com/home-assistant/frontend into confdig-section-redesign 2020-08-31 14:34:01 -05:00
Zack Arnett
3ff8211a81 style updates 2020-08-29 01:52:48 -05:00
Zack Arnett
3ebdd11f4b style changes 2020-08-29 01:52:22 -05:00
21 changed files with 1584 additions and 612 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,7 +49,7 @@ class CloudRegister extends LocalizeMixin(EventsMixin(PolymerElement)) {
</style> </style>
<hass-subpage header="[[localize('ui.panel.config.cloud.register.title')]]"> <hass-subpage header="[[localize('ui.panel.config.cloud.register.title')]]">
<div class="content"> <div class="content">
<ha-config-section is-wide="[[isWide]]"> <ha-config-section side-by-side is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.cloud.register.headline')]]</span> <span slot="header">[[localize('ui.panel.config.cloud.register.headline')]]</span>
<div slot="introduction"> <div slot="introduction">
<p> <p>

View File

@@ -1,73 +0,0 @@
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

@@ -0,0 +1,66 @@
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,6 +10,8 @@ import {
property, property,
internalProperty, internalProperty,
TemplateResult, TemplateResult,
CSSResult,
css,
} from "lit-element"; } from "lit-element";
import "../../../components/ha-card"; import "../../../components/ha-card";
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core"; import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
@@ -87,6 +89,21 @@ class ConfigNameForm extends LitElement {
this._working = false; 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 { declare global {

View File

@@ -1,126 +0,0 @@
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

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,10 +1,30 @@
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";
import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item-body";
import { PolymerElement } from "@polymer/polymer"; import { PolymerElement } from "@polymer/polymer";
import { import {
customElement, customElement,
property,
internalProperty, internalProperty,
property,
PropertyValues, PropertyValues,
} from "lit-element"; } from "lit-element";
import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../common/config/is_component_loaded";
@@ -14,26 +34,6 @@ import "../../layouts/hass-loading-screen";
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page"; import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
import { PageNavigation } from "../../layouts/hass-tabs-subpage"; import { PageNavigation } from "../../layouts/hass-tabs-subpage";
import { HomeAssistant, Route } from "../../types"; 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 { declare global {
// for fire event // for fire event
@@ -167,8 +167,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconPath: mdiInformation, iconPath: mdiInformation,
core: true, core: true,
}, },
],
advanced: [
{ {
component: "customize", component: "customize",
path: "/config/customize", path: "/config/customize",

View File

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

View File

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

View File

@@ -12,6 +12,8 @@ import {
property, property,
TemplateResult, TemplateResult,
} from "lit-element"; } 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 { componentsWithService } from "../../../common/config/components_with_service";
import "../../../components/buttons/ha-call-service-button"; import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-card"; import "../../../components/ha-card";
@@ -27,13 +29,14 @@ import { configSections } from "../ha-panel-config";
export class HaConfigServerControl extends LitElement { export class HaConfigServerControl extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public isWide!: boolean; @property({ type: Boolean }) public isWide!: boolean;
@property() public narrow!: boolean; @property({ type: Boolean, attribute: "narrow", reflect: true })
public narrow!: boolean;
@property() public route!: Route; @property({ attribute: false }) public route!: Route;
@property() public showAdvanced!: boolean; @property({ type: Boolean }) public showAdvanced!: boolean;
@internalProperty() private _validating = false; @internalProperty() private _validating = false;
@@ -59,170 +62,191 @@ export class HaConfigServerControl extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<hass-tabs-subpage <hass-tabs-subpage
back-path="/config"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
.route=${this.route} .route=${this.route}
back-path="/config"
.tabs=${configSections.general} .tabs=${configSections.general}
.showAdvanced=${this.showAdvanced} .showAdvanced=${this.showAdvanced}
> >
<ha-config-section .isWide=${this.isWide}> <ha-config-section
<span slot="header" ?side-by-side=${!this.showAdvanced}
>${this.hass.localize( .narrow=${this.narrow}
"ui.panel.config.server_control.caption" .isWide=${this.isWide}
)}</span >
> <div slot="header">
<span slot="introduction" ${this.hass.localize("ui.panel.config.server_control.caption")}
>${this.hass.localize( </div>
"ui.panel.config.server_control.description" <div slot="introduction">
)}</span ${this.hass.localize("ui.panel.config.server_control.description")}
> </div>
<div class="content">
${this.showAdvanced ${this.showAdvanced
? html` <ha-card ? html`
header=${this.hass.localize( <ha-card
"ui.panel.config.server_control.section.validation.heading" 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" <div class="card-content">
)} ${this.hass.localize(
${!this._validateLog "ui.panel.config.server_control.section.validation.introduction"
? html` )}
<div ${!this._validateLog
class="validate-container layout vertical center-center" ? html`
> <div
${!this._validating class="validate-container layout vertical center-center"
? html` >
${this._isValid ${!this._validating
? html` <div ? html`
class="validate-result" ${this._isValid
id="result" ? 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}
> >
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.server_control.section.validation.valid" "ui.panel.config.server_control.section.validation.check_config"
)} )}
</div>` </mwc-button>
: ""} `
<mwc-button : html`
raised <ha-circular-progress
@click=${this._validateConfig} active
> ></ha-circular-progress>
${this.hass.localize( `}
"ui.panel.config.server_control.section.validation.check_config" </div>
)} `
</mwc-button> : html`
` <div class="config-invalid">
: html` <span class="text">
<ha-circular-progress ${this.hass.localize(
active "ui.panel.config.server_control.section.validation.invalid"
></ha-circular-progress> )}
`} </span>
</div> <mwc-button raised @click=${this._validateConfig}>
` ${this.hass.localize(
: html` "ui.panel.config.server_control.section.validation.check_config"
<div class="config-invalid"> )}
<span class="text"> </mwc-button>
${this.hass.localize( </div>
"ui.panel.config.server_control.section.validation.invalid" <div id="configLog" class="validate-log">
)} ${this._validateLog}
</span> </div>
<mwc-button raised @click=${this._validateConfig}> `}
${this.hass.localize( </div>
"ui.panel.config.server_control.section.validation.check_config" </ha-card>
)} `
</mwc-button> : ""}
</div>
<div id="configLog" class="validate-log">
${this._validateLog}
</div>
`}
</div>
</ha-card>`
: ""}
<ha-card <ha-card
header=${this.hass.localize( class="server-management-card ${classMap({
"ui.panel.config.server_control.section.server_management.heading" "no-advanced": !this.showAdvanced,
)} })}"
> header=${this.hass.localize(
<div class="card-content"> "ui.panel.config.server_control.section.server_management.heading"
${this.hass.localize(
"ui.panel.config.server_control.section.server_management.introduction"
)} )}
</div> >
<div class="card-actions warning"> <div class="card-content">
<ha-call-service-button ${this.hass.localize(
class="warning" "ui.panel.config.server_control.section.server_management.introduction"
.hass=${this.hass}
domain="homeassistant"
service="restart"
.confirmation=${this.hass.localize(
"ui.panel.config.server_control.section.server_management.confirm_restart"
)} )}
>${this.hass.localize( </div>
"ui.panel.config.server_control.section.server_management.restart" <div
)} class="server-management-container layout horizontal center-center warning"
</ha-call-service-button> >
<ha-call-service-button <ha-call-service-button
class="warning" raised
.hass=${this.hass} class="warning"
domain="homeassistant" service="restart"
service="stop" domain="homeassistant"
confirmation=${this.hass.localize( .hass=${this.hass}
"ui.panel.config.server_control.section.server_management.confirm_stop" .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.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"
)} )}
> >
<div class="card-content"> ${this.hass.localize(
${this.hass.localize( "ui.panel.config.server_control.section.server_management.restart"
"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"
)}
</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-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>
<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-config-section> </ha-config-section>
</hass-tabs-subpage> </hass-tabs-subpage>
`; `;
@@ -246,10 +270,48 @@ export class HaConfigServerControl extends LitElement {
return [ return [
haStyle, haStyle,
css` css`
.validate-container { .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 {
height: 140px; height: 140px;
} }
.server-management-container ha-call-service-button {
padding-right: 16px;
}
.validate-result { .validate-result {
color: var(--success-color); color: var(--success-color);
font-weight: 500; font-weight: 500;
@@ -274,10 +336,50 @@ export class HaConfigServerControl extends LitElement {
direction: ltr; direction: ltr;
} }
ha-config-section { .warning {
padding-bottom: 24px; --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;
} }
`, `,
]; ];
} }
} }
declare global {
interface HTMLElementTagNameMap {
"ha-config-server-control": HaConfigServerControl;
}
}

View File

@@ -866,38 +866,37 @@
}, },
"reloading": { "reloading": {
"heading": "YAML configuration reloading", "heading": "YAML configuration reloading",
"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.", "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.",
"reload": "Reload {domain}", "core": "location & customizations",
"core": "Reload location & customizations", "group": "groups, group entities, and notify services",
"group": "Reload groups, group entities, and notify services", "automation": "automations",
"automation": "Reload automations", "script": "scripts",
"script": "Reload scripts", "scene": "scenes",
"scene": "Reload scenes", "person": "persons",
"person": "Reload persons", "zone": "zones",
"zone": "Reload zones", "input_boolean": "input booleans",
"input_boolean": "Reload input booleans", "input_text": "input texts",
"input_text": "Reload input texts", "input_number": "input numbers",
"input_number": "Reload input numbers", "input_datetime": "input date times",
"input_datetime": "Reload input date times", "input_select": "input selects",
"input_select": "Reload input selects", "template": "template entities",
"template": "Reload template entities", "universal": "universal media player entities",
"universal": "Reload universal media player entities", "rest": "rest entities and notify services",
"rest": "Reload rest entities and notify services", "command_line": "command line entities",
"command_line": "Reload command line entities", "filter": "filter entities",
"filter": "Reload filter entities", "statistics": "statistics entities",
"statistics": "Reload statistics entities", "generic": "generic IP camera entities",
"generic": "Reload generic IP camera entities", "generic_thermostat": "generic thermostat entities",
"generic_thermostat": "Reload generic thermostat entities", "homekit": "HomeKit",
"homekit": "Reload HomeKit", "min_max": "min/max entities",
"min_max": "Reload min/max entities", "history_stats": "history stats entities",
"history_stats": "Reload history stats entities", "trend": "trend entities",
"trend": "Reload trend entities", "ping": "ping binary sensor entities",
"ping": "Reload ping binary sensor entities", "filesize": "file size entities",
"filesize": "Reload file size entities", "telegram": "telegram notify services",
"telegram": "Reload telegram notify services", "smtp": "smtp notify services",
"smtp": "Reload smtp notify services", "mqtt": "mqtt entities",
"mqtt": "Reload mqtt entities", "rpi_gpio": "Raspberry Pi GPIO entities"
"rpi_gpio": "Reload Raspberry Pi GPIO entities"
}, },
"server_management": { "server_management": {
"heading": "Server management", "heading": "Server management",
@@ -1322,6 +1321,8 @@
"description_login": "Logged in as {email}", "description_login": "Logged in as {email}",
"description_not_login": "Not logged in", "description_not_login": "Not logged in",
"description_features": "Control away from home, integrate with Alexa and Google Assistant.", "description_features": "Control away from home, integrate with Alexa and Google Assistant.",
"enabled": "Enabled",
"disabled": "Disabled",
"login": { "login": {
"title": "Cloud 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.", "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.",