Integration Quality Scale indicator (#23015)

This commit is contained in:
Wendelin 2024-11-27 14:45:44 +01:00 committed by GitHub
parent f54bb20fef
commit bc195c61cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 118 additions and 44 deletions

View File

@ -38,7 +38,7 @@ export interface IntegrationManifest {
homekit?: { models: string[] }; homekit?: { models: string[] };
integration_type?: IntegrationType; integration_type?: IntegrationType;
loggers?: string[]; loggers?: string[];
quality_scale?: "gold" | "internal" | "platinum" | "silver"; quality_scale?: "bronze" | "gold" | "internal" | "platinum" | "silver";
iot_class: iot_class:
| "assumed_state" | "assumed_state"
| "cloud_polling" | "cloud_polling"

View File

@ -6,7 +6,6 @@ import {
mdiBug, mdiBug,
mdiBugPlay, mdiBugPlay,
mdiBugStop, mdiBugStop,
mdiCloud,
mdiCog, mdiCog,
mdiDelete, mdiDelete,
mdiDevices, mdiDevices,
@ -14,6 +13,7 @@ import {
mdiDownload, mdiDownload,
mdiFileCodeOutline, mdiFileCodeOutline,
mdiHandExtendedOutline, mdiHandExtendedOutline,
mdiMedal,
mdiOpenInNew, mdiOpenInNew,
mdiPackageVariant, mdiPackageVariant,
mdiPlayCircleOutline, mdiPlayCircleOutline,
@ -23,6 +23,8 @@ import {
mdiRenameBox, mdiRenameBox,
mdiShapeOutline, mdiShapeOutline,
mdiStopCircleOutline, mdiStopCircleOutline,
mdiTrophy,
mdiWeb,
mdiWrench, mdiWrench,
} from "@mdi/js"; } from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { UnsubscribeFunc } from "home-assistant-js-websocket";
@ -338,41 +340,72 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
${this._manifest?.version != null ${this._manifest?.version != null
? html`<div class="version">${this._manifest.version}</div>` ? html`<div class="version">${this._manifest.version}</div>`
: nothing} : nothing}
${this._manifest?.quality_scale &&
this._manifest?.quality_scale !== "internal"
? html`
<div class="quality-scale integration-info">
<ha-svg-icon
class=${`${this._manifest.quality_scale}-medal`}
.path=${this._manifest.quality_scale === "platinum"
? mdiTrophy
: mdiMedal}
></ha-svg-icon>
<span>
${this.hass.localize(
`ui.panel.config.integrations.config_entry.${this._manifest.quality_scale}_quality`,
{
quality_scale: html`
<a
href=${documentationUrl(
this.hass,
`/docs/quality_scale/#${this._manifest.quality_scale}-`
)}
rel="noopener noreferrer"
target="_blank"
>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.quality_scale"
)}
</a>
`,
}
)}
</span>
</div>
`
: nothing}
${this._manifest?.is_built_in === false ${this._manifest?.is_built_in === false
? html`<ha-alert alert-type="warning" ? html`<div class="integration-info warn">
><ha-svg-icon <ha-svg-icon
slot="icon" class="warning"
path=${mdiPackageVariant} path=${mdiPackageVariant}
></ha-svg-icon> ></ha-svg-icon>
${this.hass.localize( ${this.hass.localize(
"ui.panel.config.integrations.config_entry.custom_integration" "ui.panel.config.integrations.config_entry.custom_integration"
)}</ha-alert )}
>` </div>`
: ""} : nothing}
${this._manifest?.iot_class?.startsWith("cloud_") ${this._manifest?.iot_class?.startsWith("cloud_")
? html`<ha-alert ? html`<div class="integration-info">
><ha-svg-icon slot="icon" path=${mdiCloud}></ha-svg-icon <ha-svg-icon .path=${mdiWeb}></ha-svg-icon>
>${this.hass.localize( ${this.hass.localize(
"ui.panel.config.integrations.config_entry.depends_on_cloud" "ui.panel.config.integrations.config_entry.depends_on_cloud"
)}</ha-alert )}
>` </div>`
: ""} : nothing}
${normalEntries.length === 0 && ${normalEntries.length === 0 &&
this._manifest && this._manifest &&
!this._manifest.config_flow && !this._manifest.config_flow &&
this.hass.config.components.find( this.hass.config.components.find(
(comp) => comp.split(".")[0] === this.domain (comp) => comp.split(".")[0] === this.domain
) )
? html`<ha-alert alert-type="info" ? html`<div class="integration-info info">
><ha-svg-icon <ha-svg-icon path=${mdiFileCodeOutline}></ha-svg-icon
slot="icon"
path=${mdiFileCodeOutline}
></ha-svg-icon
>${this.hass.localize( >${this.hass.localize(
"ui.panel.config.integrations.config_entry.no_config_flow" "ui.panel.config.integrations.config_entry.no_config_flow"
)}</ha-alert )}
>` </div>`
: ""} : nothing}
</div> </div>
<div class="card-actions"> <div class="card-actions">
@ -398,7 +431,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<ha-icon-next slot="meta"></ha-icon-next> <ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item> </ha-list-item>
</a>` </a>`
: ""} : nothing}
${numberOfEntities > 0 ${numberOfEntities > 0
? html`<a ? html`<a
href=${`/config/entities?historyBack=1&domain=${this.domain}`} href=${`/config/entities?historyBack=1&domain=${this.domain}`}
@ -415,7 +448,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<ha-icon-next slot="meta"></ha-icon-next> <ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item> </ha-list-item>
</a>` </a>`
: ""} : nothing}
${this._manifest ${this._manifest
? html`<a ? html`<a
href=${this._manifest.is_built_in href=${this._manifest.is_built_in
@ -441,7 +474,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
></ha-svg-icon> ></ha-svg-icon>
</ha-list-item> </ha-list-item>
</a>` </a>`
: ""} : nothing}
${this._manifest && ${this._manifest &&
(this._manifest.is_built_in || this._manifest.issue_tracker) (this._manifest.is_built_in || this._manifest.issue_tracker)
? html`<a ? html`<a
@ -463,7 +496,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
></ha-svg-icon> ></ha-svg-icon>
</ha-list-item> </ha-list-item>
</a>` </a>`
: ""} : nothing}
${this._logInfo ${this._logInfo
? html`<ha-list-item ? html`<ha-list-item
@request-selected=${this._logInfo.level === @request-selected=${this._logInfo.level ===
@ -489,7 +522,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
: mdiBugPlay} : mdiBugPlay}
></ha-svg-icon> ></ha-svg-icon>
</ha-list-item>` </ha-list-item>`
: ""} : nothing}
</div> </div>
</ha-card> </ha-card>
</div> </div>
@ -517,7 +550,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
)} )}
</ha-md-list> </ha-md-list>
</ha-card>` </ha-card>`
: ""} : nothing}
${attentionFlows.length || attentionEntries.length ${attentionFlows.length || attentionEntries.length
? html`<ha-card> ? html`<ha-card>
<h1 class="card-header"> <h1 class="card-header">
@ -562,11 +595,11 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
role="separator" role="separator"
tabindex="-1" tabindex="-1"
></ha-md-divider>` ></ha-md-divider>`
: ""} ` : nothing} `
)} )}
</ha-md-list> </ha-md-list>
</ha-card>` </ha-card>`
: ""} : nothing}
<ha-card> <ha-card>
<h1 class="card-header"> <h1 class="card-header">
@ -602,7 +635,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
role="separator" role="separator"
tabindex="-1" tabindex="-1"
></ha-md-divider>` ></ha-md-divider>`
: ""} ` : nothing}`
)} )}
</ha-md-list> </ha-md-list>
<div class="card-actions"> <div class="card-actions">
@ -762,11 +795,11 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<div> <div>
${this.hass.localize(...stateText)}${stateTextExtra ${this.hass.localize(...stateText)}${stateTextExtra
? html`: ${stateTextExtra}` ? html`: ${stateTextExtra}`
: ""} : nothing}
</div> </div>
</div> </div>
` `
: ""} : nothing}
</div> </div>
${item.disabled_by === "user" ${item.disabled_by === "user"
? html`<ha-button unelevated slot="end" @click=${this._handleEnable}> ? html`<ha-button unelevated slot="end" @click=${this._handleEnable}>
@ -793,7 +826,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
)} )}
</ha-button> </ha-button>
` `
: ""} : nothing}
<ha-md-button-menu positioning="popover" slot="end"> <ha-md-button-menu positioning="popover" slot="end">
<ha-icon-button <ha-icon-button
slot="trigger" slot="trigger"
@ -815,7 +848,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<ha-icon-next slot="end"></ha-icon-next> <ha-icon-next slot="end"></ha-icon-next>
</ha-md-menu-item> </ha-md-menu-item>
` `
: ""} : nothing}
${item.disabled_by && services.length ${item.disabled_by && services.length
? html`<ha-md-menu-item ? html`<ha-md-menu-item
href=${services.length === 1 href=${services.length === 1
@ -832,7 +865,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
)} )}
<ha-icon-next slot="end"></ha-icon-next> <ha-icon-next slot="end"></ha-icon-next>
</ha-md-menu-item> ` </ha-md-menu-item> `
: ""} : nothing}
${item.disabled_by && entities.length ${item.disabled_by && entities.length
? html` ? html`
<ha-md-menu-item <ha-md-menu-item
@ -849,7 +882,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
<ha-icon-next slot="end"></ha-icon-next> <ha-icon-next slot="end"></ha-icon-next>
</ha-md-menu-item> </ha-md-menu-item>
` `
: ""} : nothing}
${!item.disabled_by && ${!item.disabled_by &&
RECOVERABLE_STATES.includes(item.state) && RECOVERABLE_STATES.includes(item.state) &&
item.supports_unload && item.supports_unload &&
@ -886,7 +919,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
)} )}
</ha-md-menu-item> </ha-md-menu-item>
` `
: ""} : nothing}
${!item.disabled_by && ${!item.disabled_by &&
item.supports_reconfigure && item.supports_reconfigure &&
item.source !== "system" item.source !== "system"
@ -1424,6 +1457,9 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
margin-top: 32px; margin-top: 32px;
margin-bottom: 32px; margin-bottom: 32px;
} }
.card-content {
padding: 16px 0 8px;
}
.column { .column {
width: 33%; width: 33%;
flex-grow: 1; flex-grow: 1;
@ -1471,12 +1507,45 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
max-width: 200px; max-width: 200px;
max-height: 100px; max-height: 100px;
} }
ha-alert {
display: block; @keyframes shimmer {
margin-top: 4px; 100% {
mask-position: left;
}
} }
ha-alert:first-of-type { .integration-info {
margin-top: 16px; display: flex;
align-items: center;
gap: 20px;
padding: 0 20px;
min-height: 48px;
}
.integration-info ha-svg-icon {
min-width: 24px;
color: var(--mdc-theme-text-icon-on-background);
}
.integration-info.warn ha-svg-icon {
color: var(--warning-color);
}
.integration-info.info ha-svg-icon {
color: var(--info-color);
}
.quality-scale ha-svg-icon {
mask: linear-gradient(-60deg, #000 30%, #0005, #000 70%) right/350%
100%;
animation: shimmer 2.5s infinite;
}
ha-svg-icon.bronze-medal {
color: #cd7f32;
}
ha-svg-icon.silver-medal {
color: silver;
}
ha-svg-icon.gold-medal {
color: gold;
}
ha-svg-icon.platinum-medal {
color: #d9d9d9;
} }
ha-md-list-item { ha-md-list-item {
position: relative; position: relative;

View File

@ -4520,7 +4520,12 @@
"failed_unload": "Failed to unload", "failed_unload": "Failed to unload",
"setup_in_progress": "Initializing" "setup_in_progress": "Initializing"
}, },
"open_configuration_url": "Visit device" "open_configuration_url": "Visit device",
"bronze_quality": "Bronze on our {quality_scale}",
"silver_quality": "Silver on our {quality_scale}",
"gold_quality": "Gold on our {quality_scale}",
"platinum_quality": "Platinum on our {quality_scale}",
"quality_scale": "quality scale"
}, },
"config_flow": { "config_flow": {
"success": "Success", "success": "Success",