diff --git a/gallery/src/demos/demo-integration-card.ts b/gallery/src/demos/demo-integration-card.ts
index 966978ffd1..e8c1694700 100644
--- a/gallery/src/demos/demo-integration-card.ts
+++ b/gallery/src/demos/demo-integration-card.ts
@@ -44,9 +44,10 @@ const createConfigEntry = (
const createManifest = (
isCustom: boolean,
- isCloud: boolean
+ isCloud: boolean,
+ name = "ESPHome"
): IntegrationManifest => ({
- name: "ESPHome",
+ name,
domain: "esphome",
is_built_in: !isCustom,
config_flow: false,
@@ -103,7 +104,7 @@ const configFlows: DataEntryFlowProgressExtended[] = [
},
},
step_id: "discovery_confirm",
- localized_title: "Roku: Living room Roku",
+ localized_title: "Living room Roku",
},
{
flow_id: "adbb401329d8439ebb78ef29837826a8",
@@ -234,7 +235,8 @@ export class DemoIntegrationCard extends LitElement {
.flow=${flow}
.manifest=${createManifest(
this.isCustomIntegration,
- this.isCloud
+ this.isCloud,
+ flow.handler === "roku" ? "Roku" : "Philips Hue"
)}
>
`
diff --git a/src/panels/config/integrations/ha-config-integrations-common.ts b/src/panels/config/integrations/ha-config-integrations-common.ts
deleted file mode 100644
index f7e1117ceb..0000000000
--- a/src/panels/config/integrations/ha-config-integrations-common.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { mdiPackageVariant, mdiCloud } from "@mdi/js";
-import "@polymer/paper-tooltip/paper-tooltip";
-import { css, html } from "lit-element";
-import { IntegrationManifest } from "../../../data/integration";
-import { HomeAssistant } from "../../../types";
-
-export const haConfigIntegrationsStyles = css`
- .banner {
- background-color: var(--state-color);
- color: var(--text-on-state-color);
- text-align: center;
- padding: 8px;
- }
- .icons {
- position: absolute;
- top: 0px;
- right: 16px;
- color: var(--text-on-state-color, var(--secondary-text-color));
- background-color: var(--state-color, #e0e0e0);
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- padding: 1px 4px 2px;
- }
- .icons ha-svg-icon {
- width: 20px;
- height: 20px;
- }
- paper-tooltip {
- white-space: nowrap;
- }
-`;
-
-export const haConfigIntegrationRenderIcons = (
- hass: HomeAssistant,
- manifest?: IntegrationManifest
-) => {
- const icons: [string, string][] = [];
-
- if (manifest) {
- if (!manifest.is_built_in) {
- icons.push([
- mdiPackageVariant,
- hass.localize(
- "ui.panel.config.integrations.config_entry.provided_by_custom_integration"
- ),
- ]);
- }
-
- if (manifest.iot_class && manifest.iot_class.startsWith("cloud_")) {
- icons.push([
- mdiCloud,
- hass.localize(
- "ui.panel.config.integrations.config_entry.depends_on_cloud"
- ),
- ]);
- }
- }
-
- return icons.length === 0
- ? ""
- : html`
-
- ${icons.map(
- ([icon, description]) => html`
-
-
- ${description}
-
- `
- )}
-
- `;
-};
diff --git a/src/panels/config/integrations/ha-ignored-config-entry-card.ts b/src/panels/config/integrations/ha-ignored-config-entry-card.ts
index e4332bd65e..cbd6c476b7 100644
--- a/src/panels/config/integrations/ha-ignored-config-entry-card.ts
+++ b/src/panels/config/integrations/ha-ignored-config-entry-card.ts
@@ -31,6 +31,7 @@ export class HaIgnoredConfigEntryCard extends LitElement {
"ui.panel.config.integrations.ignore.ignored"
)}
.domain=${this.entry.domain}
+ .localizedDomainName=${this.entry.localized_domain_name}
.label=${this.entry.title === "Ignored"
? // In 2020.2 we added support for entry.title. All ignored entries before
// that have title "Ignored" so we fallback to localized domain name.
@@ -38,7 +39,6 @@ export class HaIgnoredConfigEntryCard extends LitElement {
: this.entry.title}
>
-
- ${this.banner}
-
-
- ${haConfigIntegrationRenderIcons(this.hass, this.manifest)}
-
-

-
-
${this.label}
-
+
+
`;
}
- private _onImageLoad(ev) {
- ev.target.style.visibility = "initial";
- }
-
- private _onImageError(ev) {
- ev.target.style.visibility = "hidden";
- }
-
- static get styles(): CSSResult[] {
- return [
- haConfigIntegrationsStyles,
- css`
- ha-card {
- display: flex;
- flex-direction: column;
- height: 100%;
- --ha-card-border-color: var(--state-color);
- --mdc-theme-primary: var(--state-color);
- }
- .content {
- position: relative;
- flex: 1;
- }
- .image {
- height: 60px;
- margin-top: 16px;
- display: flex;
- align-items: center;
- justify-content: space-around;
- }
- img {
- max-width: 90%;
- max-height: 100%;
- }
- h2 {
- text-align: center;
- margin: 16px 8px 0;
- }
- .attention {
- --state-color: var(--error-color);
- --text-on-state-color: var(--text-primary-color);
- }
- .discovered {
- --state-color: var(--primary-color);
- --text-on-state-color: var(--text-primary-color);
- }
- .actions {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 8px 6px 0;
- height: 48px;
- }
- `,
- ];
- }
+ static styles = css`
+ ha-card {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ --ha-card-border-color: var(--state-color);
+ --mdc-theme-primary: var(--state-color);
+ }
+ .filler {
+ flex: 1;
+ }
+ .attention {
+ --state-color: var(--error-color);
+ --text-on-state-color: var(--text-primary-color);
+ }
+ .discovered {
+ --state-color: var(--primary-color);
+ --text-on-state-color: var(--text-primary-color);
+ }
+ .actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 6px 0;
+ height: 48px;
+ }
+ `;
}
declare global {
diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts
index 786b394e7e..5aaf0d31c4 100644
--- a/src/panels/config/integrations/ha-integration-card.ts
+++ b/src/panels/config/integrations/ha-integration-card.ts
@@ -31,7 +31,7 @@ import {
} from "../../../data/config_entries";
import type { DeviceRegistryEntry } from "../../../data/device_registry";
import type { EntityRegistryEntry } from "../../../data/entity_registry";
-import { domainToName, IntegrationManifest } from "../../../data/integration";
+import type { IntegrationManifest } from "../../../data/integration";
import { showConfigEntrySystemOptionsDialog } from "../../../dialogs/config-entry-system-options/show-dialog-config-entry-system-options";
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
import {
@@ -40,13 +40,9 @@ import {
showPromptDialog,
} from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
-import { HomeAssistant } from "../../../types";
-import { brandsUrl } from "../../../util/brands-url";
-import { ConfigEntryExtended } from "./ha-config-integrations";
-import {
- haConfigIntegrationRenderIcons,
- haConfigIntegrationsStyles,
-} from "./ha-config-integrations-common";
+import type { HomeAssistant } from "../../../types";
+import type { ConfigEntryExtended } from "./ha-config-integrations";
+import "./ha-integration-header";
const ERROR_STATES: ConfigEntry["state"][] = [
"migration_error",
@@ -92,18 +88,6 @@ export class HaIntegrationCard extends LitElement {
);
}
- let primary: string;
- let secondary: string | undefined;
-
- if (item) {
- primary = item.title || item.localized_domain_name || this.domain;
- if (primary !== item.localized_domain_name) {
- secondary = item.localized_domain_name;
- }
- } else {
- primary = domainToName(this.hass.localize, this.domain, this.manifest);
- }
-
const hasItem = item !== undefined;
return html`
@@ -120,38 +104,32 @@ export class HaIntegrationCard extends LitElement {
})}"
.configEntry=${item}
>
- ${this.disabled
- ? html`
-
- ${this.hass.localize(
- "ui.panel.config.integrations.config_entry.disable.disabled"
- )}
-
- `
- : ""}
- ${this.items.length > 1
- ? html`
-
-
-
- `
- : ""}
-
+
+ ${this.items.length > 1
+ ? html`
+
+
+
+ `
+ : ""}
+
+
${item
? this._renderSingleEntry(item)
: this._renderGroupedIntegration()}
@@ -441,14 +419,6 @@ export class HaIntegrationCard extends LitElement {
);
}
- private _onImageLoad(ev) {
- ev.target.style.visibility = "initial";
- }
-
- private _onImageError(ev) {
- ev.target.style.visibility = "hidden";
- }
-
private _showOptions(ev) {
showOptionsFlowDialog(this, ev.target.closest("ha-card").configEntry);
}
@@ -605,7 +575,6 @@ export class HaIntegrationCard extends LitElement {
static get styles(): CSSResult[] {
return [
haStyle,
- haConfigIntegrationsStyles,
css`
ha-card {
display: flex;
@@ -627,7 +596,7 @@ export class HaIntegrationCard extends LitElement {
--state-message-color: var(--primary-text-color);
}
:host(.highlight) ha-card {
- --state-color: var(--accent-color);
+ --state-color: var(--primary-color);
--text-on-state-color: var(--text-primary-color);
}
@@ -645,36 +614,6 @@ export class HaIntegrationCard extends LitElement {
height: 0px;
}
- .header {
- display: flex;
- position: relative;
- align-items: center;
- padding: 16px 8px 8px 16px;
- }
- .header img {
- margin-right: 16px;
- width: 40px;
- height: 40px;
- }
- .header .info div,
- paper-item-body {
- word-wrap: break-word;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .primary {
- font-size: 16px;
- font-weight: 400;
- color: var(--primary-text-color);
- }
- .secondary {
- font-size: 14px;
- color: var(--secondary-text-color);
- }
-
.message {
font-weight: bold;
padding-bottom: 16px;
@@ -724,6 +663,14 @@ export class HaIntegrationCard extends LitElement {
cursor: pointer;
min-height: 35px;
}
+ paper-item-body {
+ word-wrap: break-word;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
mwc-list-item ha-svg-icon {
color: var(--secondary-text-color);
}
diff --git a/src/panels/config/integrations/ha-integration-header.ts b/src/panels/config/integrations/ha-integration-header.ts
new file mode 100644
index 0000000000..fefebd5f65
--- /dev/null
+++ b/src/panels/config/integrations/ha-integration-header.ts
@@ -0,0 +1,174 @@
+import { mdiPackageVariant, mdiCloud } from "@mdi/js";
+import "@polymer/paper-tooltip/paper-tooltip";
+import {
+ css,
+ html,
+ customElement,
+ property,
+ LitElement,
+ TemplateResult,
+} from "lit-element";
+import { domainToName, IntegrationManifest } from "../../../data/integration";
+import { HomeAssistant } from "../../../types";
+import { brandsUrl } from "../../../util/brands-url";
+
+@customElement("ha-integration-header")
+export class HaIntegrationHeader extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property() public banner!: string;
+
+ @property() public localizedDomainName?: string;
+
+ @property() public domain!: string;
+
+ @property() public label!: string;
+
+ @property() public manifest?: IntegrationManifest;
+
+ protected render(): TemplateResult {
+ let primary: string;
+ let secondary: string | undefined;
+
+ const domainName =
+ this.localizedDomainName ||
+ domainToName(this.hass.localize, this.domain, this.manifest);
+
+ if (this.label) {
+ primary = this.label;
+ secondary = primary === domainName ? undefined : domainName;
+ } else {
+ primary = domainName;
+ }
+
+ const icons: [string, string][] = [];
+
+ if (this.manifest) {
+ if (!this.manifest.is_built_in) {
+ icons.push([
+ mdiPackageVariant,
+ this.hass.localize(
+ "ui.panel.config.integrations.config_entry.provided_by_custom_integration"
+ ),
+ ]);
+ }
+
+ if (
+ this.manifest.iot_class &&
+ this.manifest.iot_class.startsWith("cloud_")
+ ) {
+ icons.push([
+ mdiCloud,
+ this.hass.localize(
+ "ui.panel.config.integrations.config_entry.depends_on_cloud"
+ ),
+ ]);
+ }
+ }
+
+ return html`
+ ${!this.banner
+ ? ""
+ : html`
+ ${this.banner}
+
`}
+
+
+ `;
+ }
+
+ private _onImageLoad(ev) {
+ ev.target.style.visibility = "initial";
+ }
+
+ private _onImageError(ev) {
+ ev.target.style.visibility = "hidden";
+ }
+
+ static styles = css`
+ .banner {
+ background-color: var(--state-color);
+ color: var(--text-on-state-color);
+ text-align: center;
+ padding: 8px;
+ }
+ .header {
+ display: flex;
+ position: relative;
+ align-items: center;
+ padding: 16px 8px 8px 16px;
+ }
+ .header img {
+ margin-right: 16px;
+ width: 40px;
+ height: 40px;
+ }
+ .header .info div {
+ word-wrap: break-word;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ .primary {
+ font-size: 16px;
+ font-weight: 400;
+ color: var(--primary-text-color);
+ }
+ .secondary {
+ font-size: 14px;
+ color: var(--secondary-text-color);
+ }
+ .icons {
+ position: absolute;
+ top: 0px;
+ right: 16px;
+ color: var(--text-on-state-color, var(--secondary-text-color));
+ background-color: var(--state-color, #e0e0e0);
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ padding: 1px 4px 2px;
+ }
+ .icons ha-svg-icon {
+ width: 20px;
+ height: 20px;
+ }
+ paper-tooltip {
+ white-space: nowrap;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-integration-header": HaIntegrationHeader;
+ }
+}