Home Assistant Cloud
diff --git a/src/panels/config/dashboard/ha-config-dashboard.ts b/src/panels/config/dashboard/ha-config-dashboard.ts
index 27bdca32a7..39fd28c5be 100644
--- a/src/panels/config/dashboard/ha-config-dashboard.ts
+++ b/src/panels/config/dashboard/ha-config-dashboard.ts
@@ -15,6 +15,7 @@ import { HomeAssistant } from "../../../types";
import "../ha-config-section";
import { configSections } from "../ha-panel-config";
import "./ha-config-navigation";
+import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor";
@customElement("ha-config-dashboard")
class HaConfigDashboard extends LitElement {
@@ -27,74 +28,11 @@ class HaConfigDashboard extends LitElement {
@property() public cloudStatus?: CloudStatus;
+ @property() public supervisorUpdates?: SupervisorAvailableUpdates[] | null;
+
@property() public showAdvanced!: boolean;
protected render(): TemplateResult {
- const content = html`
- ${this.hass.localize("ui.panel.config.header")}
-
-
- ${this.hass.localize("ui.panel.config.introduction")}
-
-
- ${isComponentLoaded(this.hass, "hassio")
- ? html``
- : ""}
- ${this.cloudStatus && isComponentLoaded(this.hass, "cloud")
- ? html`
-
-
-
- `
- : ""}
- ${Object.values(configSections).map(
- (section) => html`
-
-
-
- `
- )}
- ${!this.showAdvanced
- ? html`
-
- `
- : ""}
- `;
-
- if (!this.narrow && this.hass.dockedSidebar !== "always_hidden") {
- return content;
- }
-
return html`
@@ -103,10 +41,72 @@ class HaConfigDashboard extends LitElement {
.hass=${this.hass}
.narrow=${this.narrow}
>
+ ${this.hass.localize("panel.config")}
- ${content}
+
+ ${isComponentLoaded(this.hass, "hassio") &&
+ this.supervisorUpdates === undefined
+ ? html``
+ : html`${this.supervisorUpdates !== null
+ ? html`
+
+ `
+ : ""}
+
+ ${this.narrow && this.supervisorUpdates !== null
+ ? html`
+ ${this.hass.localize("panel.config")}
+
`
+ : ""}
+ ${this.cloudStatus && isComponentLoaded(this.hass, "cloud")
+ ? html`
+
+ `
+ : ""}
+
+
+ ${!this.showAdvanced
+ ? html`
+
+ `
+ : ""}`}
+
`;
}
@@ -116,16 +116,16 @@ class HaConfigDashboard extends LitElement {
haStyle,
css`
app-header {
- --app-header-background-color: var(--primary-background-color);
+ border-bottom: var(--app-header-border-bottom);
+ --header-height: 55px;
}
ha-card:last-child {
margin-bottom: 24px;
}
ha-config-section {
- margin-top: -12px;
- }
- :host([narrow]) ha-config-section {
- margin-top: -20px;
+ margin: auto;
+ margin-top: -32px;
+ max-width: 600px;
}
ha-card {
overflow: hidden;
@@ -134,6 +134,11 @@ class HaConfigDashboard extends LitElement {
text-decoration: none;
color: var(--primary-text-color);
}
+ .title {
+ font-size: 16px;
+ padding: 16px;
+ padding-bottom: 0;
+ }
.promo-advanced {
text-align: center;
color: var(--secondary-text-color);
@@ -142,8 +147,13 @@ class HaConfigDashboard extends LitElement {
.promo-advanced a {
color: var(--secondary-text-color);
}
- .intro {
- margin-bottom: 24px;
+ :host([narrow]) ha-card {
+ background-color: var(--primary-background-color);
+ box-shadow: unset;
+ }
+
+ :host([narrow]) ha-config-section {
+ margin-top: -42px;
}
`,
];
diff --git a/src/panels/config/dashboard/ha-config-updates.ts b/src/panels/config/dashboard/ha-config-updates.ts
index 313e0e34f5..e5cb58ebc9 100644
--- a/src/panels/config/dashboard/ha-config-updates.ts
+++ b/src/panels/config/dashboard/ha-config-updates.ts
@@ -2,23 +2,13 @@ import "@material/mwc-button/mwc-button";
import { mdiPackageVariant } from "@mdi/js";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-item/paper-item-body";
-import {
- css,
- CSSResultGroup,
- html,
- LitElement,
- PropertyValues,
- TemplateResult,
-} from "lit";
+import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-alert";
import "../../../components/ha-logo-svg";
import "../../../components/ha-svg-icon";
-import { extractApiErrorMessage } from "../../../data/hassio/common";
-import {
- fetchSupervisorAvailableUpdates,
- SupervisorAvailableUpdates,
-} from "../../../data/supervisor/supervisor";
+import { SupervisorAvailableUpdates } from "../../../data/supervisor/supervisor";
+import { buttonLinkStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
export const SUPERVISOR_UPDATE_NAMES = {
@@ -31,88 +21,117 @@ export const SUPERVISOR_UPDATE_NAMES = {
class HaConfigUpdates extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
- @state() private _supervisorUpdates?: SupervisorAvailableUpdates[];
+ @property({ type: Boolean }) public narrow!: boolean;
- @state() private _error?: string;
+ @property({ attribute: false })
+ public supervisorUpdates?: SupervisorAvailableUpdates[] | null;
- protected firstUpdated(changedProps: PropertyValues): void {
- super.firstUpdated(changedProps);
- this._loadSupervisorUpdates();
- }
+ @state() private _showAll = false;
protected render(): TemplateResult {
+ if (!this.supervisorUpdates) {
+ return html``;
+ }
+
+ const updates =
+ this._showAll || this.supervisorUpdates.length <= 3
+ ? this.supervisorUpdates
+ : this.supervisorUpdates.slice(0, 2);
+
return html`
- ${this._error
- ? html`
- ${this._error}
- `
- : ""}
- ${this._supervisorUpdates?.map(
+
+ ${this.hass.localize("ui.panel.config.updates.title", {
+ count: this.supervisorUpdates.length,
+ })}
+
+ ${updates.map(
(update) => html`
-
-
+
+
${update.update_type === "addon"
? update.icon
? html`
`
: html``
: html``}
- ${this.hass.localize("ui.panel.config.updates.version_available", {
- version_available: update.version_latest,
- })}
-
+
+ ${update.update_type === "addon"
+ ? update.name
+ : SUPERVISOR_UPDATE_NAMES[update.update_type!]}
+
+ ${this.hass.localize(
+ "ui.panel.config.updates.version_available",
+ {
+ version_available: update.version_latest,
+ }
+ )}
+
+
+
-
+
`
)}
+ ${!this._showAll && !this.narrow ? html`
` : ""}
+ ${!this._showAll && this.supervisorUpdates.length >= 4
+ ? html`
+
+ `
+ : ""}
`;
}
- private async _loadSupervisorUpdates(): Promise
{
- try {
- this._supervisorUpdates = await fetchSupervisorAvailableUpdates(
- this.hass
- );
- } catch (err) {
- this._error = extractApiErrorMessage(err);
- }
+ private _showAllClicked() {
+ this._showAll = true;
}
- static get styles(): CSSResultGroup {
- return css`
- a {
- text-decoration: none;
- color: var(--primary-text-color);
- }
- .icon {
- display: inline-flex;
- height: 100%;
- align-items: center;
- }
- img,
- ha-svg-icon,
- ha-logo-svg {
- --mdc-icon-size: 32px;
- max-height: 32px;
- width: 32px;
- }
- ha-logo-svg {
- color: var(--secondary-text-color);
- }
- `;
+ static get styles(): CSSResultGroup[] {
+ return [
+ buttonLinkStyle,
+ css`
+ .title {
+ font-size: 16px;
+ padding: 16px;
+ padding-bottom: 0;
+ }
+ a {
+ text-decoration: none;
+ color: var(--primary-text-color);
+ }
+ .icon {
+ display: inline-flex;
+ height: 100%;
+ align-items: center;
+ }
+ img,
+ ha-svg-icon,
+ ha-logo-svg {
+ --mdc-icon-size: 32px;
+ max-height: 32px;
+ width: 32px;
+ }
+ ha-logo-svg {
+ color: var(--secondary-text-color);
+ }
+ button.show-all {
+ color: var(--primary-color);
+ text-decoration: none;
+ margin: 8px 16px;
+ }
+ .divider::before {
+ content: " ";
+ display: block;
+ height: 1px;
+ background-color: var(--divider-color);
+ }
+ `,
+ ];
}
}
diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts
index 9b4de45b9b..5bc90abded 100644
--- a/src/panels/config/devices/ha-config-device-page.ts
+++ b/src/panels/config/devices/ha-config-device-page.ts
@@ -218,7 +218,7 @@ export class HaConfigDevicePage extends LitElement {
${
diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts
index c8f12b685f..b29d070131 100644
--- a/src/panels/config/devices/ha-config-devices-dashboard.ts
+++ b/src/panels/config/devices/ha-config-devices-dashboard.ts
@@ -375,7 +375,7 @@ export class HaConfigDeviceDashboard extends LitElement {
.backPath=${this._searchParms.has("historyBack")
? undefined
: "/config"}
- .tabs=${configSections.integrations}
+ .tabs=${configSections.devices}
.route=${this.route}
.activeFilters=${activeFilters}
.numHidden=${this._numHiddenDevices}
diff --git a/src/panels/config/energy/ha-config-energy.ts b/src/panels/config/energy/ha-config-energy.ts
index b93c93c749..970573cbe3 100644
--- a/src/panels/config/energy/ha-config-energy.ts
+++ b/src/panels/config/energy/ha-config-energy.ts
@@ -1,3 +1,4 @@
+import "../../../layouts/hass-error-screen";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import {
@@ -9,11 +10,10 @@ import {
getEnergyPreferences,
} from "../../../data/energy";
import "../../../layouts/hass-loading-screen";
-import "../../../layouts/hass-tabs-subpage";
+import "../../../layouts/hass-subpage";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant, Route } from "../../../types";
import "../../../components/ha-alert";
-import { configSections } from "../ha-panel-config";
import "./components/ha-energy-device-settings";
import "./components/ha-energy-grid-settings";
import "./components/ha-energy-solar-settings";
@@ -68,14 +68,13 @@ class HaConfigEnergy extends LitElement {
}
return html`
-
${this.hass.localize("ui.panel.config.energy.new_device_info")}
@@ -113,7 +112,7 @@ class HaConfigEnergy extends LitElement {
@value-changed=${this._prefsChanged}
>
-
+
`;
}
diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts
index 6f9569e6cf..c1b5073c6a 100644
--- a/src/panels/config/entities/ha-config-entities.ts
+++ b/src/panels/config/entities/ha-config-entities.ts
@@ -478,7 +478,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
? undefined
: "/config"}
.route=${this.route}
- .tabs=${configSections.integrations}
+ .tabs=${configSections.devices}
.columns=${this._columns(
this.narrow,
this.hass.language,
diff --git a/src/panels/config/ha-config-section.ts b/src/panels/config/ha-config-section.ts
index 01211a9b7a..16dc7bc389 100644
--- a/src/panels/config/ha-config-section.ts
+++ b/src/panels/config/ha-config-section.ts
@@ -8,11 +8,15 @@ export class HaConfigSection extends LitElement {
@property({ type: Boolean }) public vertical = false;
+ @property({ type: Boolean, attribute: "full-width" })
+ public fullWidth = false;
+
protected render() {
return html`
@@ -111,6 +115,14 @@ export class HaConfigSection extends LitElement {
margin-right: 0;
max-width: 500px;
}
+
+ .full-width {
+ padding: 0;
+ }
+
+ .full-width .layout {
+ flex-direction: column;
+ }
`;
}
}
diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts
index 043f9d84ec..30abfa3b6d 100644
--- a/src/panels/config/ha-panel-config.ts
+++ b/src/panels/config/ha-panel-config.ts
@@ -1,6 +1,7 @@
import {
mdiAccount,
mdiBadgeAccountHorizontal,
+ mdiCog,
mdiDevices,
mdiHomeAssistant,
mdiInformation,
@@ -27,6 +28,10 @@ import { customElement, property, state } from "lit/decorators";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { listenMediaQuery } from "../../common/dom/media_query";
import { CloudStatus, fetchCloudStatus } from "../../data/cloud";
+import {
+ fetchSupervisorAvailableUpdates,
+ SupervisorAvailableUpdates,
+} from "../../data/supervisor/supervisor";
import "../../layouts/hass-loading-screen";
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
@@ -40,7 +45,82 @@ declare global {
}
export const configSections: { [name: string]: PageNavigation[] } = {
- integrations: [
+ dashboard: [
+ {
+ path: "/config/integrations",
+ name: "Devices & Services",
+ description: "Integrations, devices, entities and areas",
+ iconPath: mdiDevices,
+ iconColor: "#2D338F",
+ core: true,
+ },
+ {
+ path: "/config/automation",
+ name: "Automations",
+ description: "Automations, bludprints, scenes and scripts",
+ iconPath: mdiRobot,
+ iconColor: "#518C43",
+ components: ["automation", "blueprint", "scene", "script"],
+ },
+ {
+ path: "/config/helpers",
+ name: "Helpers",
+ description: "Elements that help build automations",
+ iconPath: mdiTools,
+ iconColor: "#4D2EA4",
+ core: true,
+ },
+ {
+ path: "/hassio",
+ name: "Add-ons & Backups",
+ description: "Create backups, check logs or reboot your system",
+ iconPath: mdiHomeAssistant,
+ iconColor: "#4084CD",
+ component: "hassio",
+ },
+ {
+ path: "/config/lovelace/dashboards",
+ name: "Dashboards",
+ description: "Create customized sets of cards to control your home",
+ iconPath: mdiViewDashboard,
+ iconColor: "#B1345C",
+ component: "lovelace",
+ },
+ {
+ path: "/config/energy",
+ name: "Energy",
+ description: "Monitor your energy production and consumption",
+ iconPath: mdiLightningBolt,
+ iconColor: "#F1C447",
+ component: "energy",
+ },
+ {
+ path: "/config/tags",
+ name: "Tags",
+ description:
+ "Trigger automations when a NFC tag, QR code, etc. is scanned",
+ iconPath: mdiNfcVariant,
+ iconColor: "#616161",
+ component: "tag",
+ },
+ {
+ path: "/config/person",
+ name: "People & Zones",
+ description: "Manage the people and zones that Home Assistant tracks",
+ iconPath: mdiAccount,
+ iconColor: "#E48629",
+ components: ["person", "zone", "users"],
+ },
+ {
+ path: "/config/core",
+ name: "Settings",
+ description: "Basic settings, server controls, logs and info",
+ iconPath: mdiCog,
+ iconColor: "#4A5963",
+ core: true,
+ },
+ ],
+ devices: [
{
component: "integrations",
path: "/config/integrations",
@@ -74,7 +154,7 @@ export const configSections: { [name: string]: PageNavigation[] } = {
core: true,
},
],
- automation: [
+ automations: [
{
component: "blueprint",
path: "/config/blueprint",
@@ -114,7 +194,7 @@ export const configSections: { [name: string]: PageNavigation[] } = {
core: true,
},
],
- experiences: [
+ tags: [
{
component: "tag",
path: "/config/tags",
@@ -122,6 +202,8 @@ export const configSections: { [name: string]: PageNavigation[] } = {
iconPath: mdiNfcVariant,
iconColor: "#616161",
},
+ ],
+ energy: [
{
component: "energy",
path: "/config/energy",
@@ -335,6 +417,8 @@ class HaPanelConfig extends HassRouterPage {
@state() private _cloudStatus?: CloudStatus;
+ @state() private _supervisorUpdates?: SupervisorAvailableUpdates[] | null;
+
private _listeners: Array<() => void> = [];
public connectedCallback() {
@@ -364,6 +448,11 @@ class HaPanelConfig extends HassRouterPage {
if (isComponentLoaded(this.hass, "cloud")) {
this._updateCloudStatus();
}
+ if (isComponentLoaded(this.hass, "hassio")) {
+ this._loadSupervisorUpdates();
+ } else {
+ this._supervisorUpdates = null;
+ }
this.addEventListener("ha-refresh-cloud-status", () =>
this._updateCloudStatus()
);
@@ -394,6 +483,7 @@ class HaPanelConfig extends HassRouterPage {
isWide,
narrow: this.narrow,
cloudStatus: this._cloudStatus,
+ supervisorUpdates: this._supervisorUpdates,
});
} else {
el.route = this.routeTail;
@@ -402,6 +492,7 @@ class HaPanelConfig extends HassRouterPage {
el.isWide = isWide;
el.narrow = this.narrow;
el.cloudStatus = this._cloudStatus;
+ el.supervisorUpdates = this._supervisorUpdates;
}
}
@@ -419,6 +510,16 @@ class HaPanelConfig extends HassRouterPage {
setTimeout(() => this._updateCloudStatus(), 5000);
}
}
+
+ private async _loadSupervisorUpdates(): Promise {
+ try {
+ this._supervisorUpdates = await fetchSupervisorAvailableUpdates(
+ this.hass
+ );
+ } catch (err) {
+ this._supervisorUpdates = null;
+ }
+ }
}
declare global {
diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts
index a3dbdff879..a4d43cd7f4 100644
--- a/src/panels/config/integrations/ha-config-integrations.ts
+++ b/src/panels/config/integrations/ha-config-integrations.ts
@@ -319,7 +319,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
- .tabs=${configSections.integrations}
+ .tabs=${configSections.devices}
>
${this.narrow
? html`
diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts
index 039611f15a..53310c5e8c 100644
--- a/src/panels/config/scene/ha-scene-dashboard.ts
+++ b/src/panels/config/scene/ha-scene-dashboard.ts
@@ -147,7 +147,7 @@ class HaSceneDashboard extends LitElement {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
- .tabs=${configSections.automation}
+ .tabs=${configSections.automations}
.columns=${this._columns(this.hass.language)}
id="entity_id"
.data=${this._scenes(this.scenes, this._filteredScenes)}
diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts
index 308db8a732..0b09c7239d 100644
--- a/src/panels/config/scene/ha-scene-editor.ts
+++ b/src/panels/config/scene/ha-scene-editor.ts
@@ -202,7 +202,7 @@ export class HaSceneEditor extends SubscribeMixin(
.narrow=${this.narrow}
.route=${this.route}
.backCallback=${this._backTapped}
- .tabs=${configSections.automation}
+ .tabs=${configSections.automations}
>
${this.narrow
? html` ${title}
diff --git a/src/panels/config/tags/ha-config-tags.ts b/src/panels/config/tags/ha-config-tags.ts
index d0c6b780c0..a8c138ae23 100644
--- a/src/panels/config/tags/ha-config-tags.ts
+++ b/src/panels/config/tags/ha-config-tags.ts
@@ -180,7 +180,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
.narrow=${this.narrow}
back-path="/config"
.route=${this.route}
- .tabs=${configSections.experiences}
+ .tabs=${configSections.tags}
.columns=${this._columns(
this.narrow,
this._canWriteTags,
diff --git a/src/translations/en.json b/src/translations/en.json
index f288340b02..3c4ff69a96 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -915,7 +915,6 @@
},
"config": {
"header": "Configure Home Assistant",
- "introduction": "In this view it is possible to configure your components and Home Assistant. Not everything is possible to configure from the UI yet, but we're working on it.",
"advanced_mode": {
"hint_enable": "Missing config options? Enable advanced mode on",
"link_profile_page": "your profile page"
@@ -927,9 +926,11 @@
"learn_more": "Learn more"
},
"updates": {
+ "title": "{count} {count, plural,\n one {update}\n other {updates}\n}",
"unable_to_fetch": "Unable to fetch available updates",
"version_available": "Version {version_available} is available",
- "review": "review"
+ "show_all_updates": "Show all updates",
+ "show": "show"
},
"areas": {
"caption": "Areas",
@@ -4165,7 +4166,7 @@
"save": "[%key:ui::common::save%]",
"close": "[%key:ui::common::close%]",
"menu": "[%key:ui::common::menu%]",
- "review": "[%key:ui::panel::config::updates::review%]",
+ "show": "[%key:ui::panel::config::updates::show%]",
"show_more": "Show more information about this",
"update_available": "{count, plural,\n one {Update}\n other {{count} updates}\n} pending",
"update": "Update",