@@ -43,6 +43,7 @@ import {
4343} from "../../../data/blueprint" ;
4444import { showScriptEditor } from "../../../data/script" ;
4545import { findRelated } from "../../../data/search" ;
46+ import "../../../components/chips/ha-assist-chip" ;
4647import {
4748 showAlertDialog ,
4849 showConfirmationDialog ,
@@ -60,6 +61,7 @@ type BlueprintMetaDataPath = BlueprintMetaData & {
6061 error : boolean ;
6162 type : "automation" | "script" ;
6263 fullpath : string ;
64+ usageCount ?: number ;
6365} ;
6466
6567const createNewFunctions = {
@@ -128,14 +130,20 @@ class HaBlueprintOverview extends LitElement {
128130 } )
129131 private _filter = "" ;
130132
133+ @state ( ) private _usageCounts : Record < string , number > = { } ;
134+
135+ private _usageCountRequest = 0 ;
136+
131137 private _processedBlueprints = memoizeOne (
132138 (
133139 blueprints : Record < string , Blueprints > ,
134- localize : LocalizeFunc
140+ localize : LocalizeFunc ,
141+ usageCounts : Record < string , number >
135142 ) : BlueprintMetaDataPath [ ] => {
136143 const result : any [ ] = [ ] ;
137144 Object . entries ( blueprints ) . forEach ( ( [ type , typeBlueprints ] ) =>
138145 Object . entries ( typeBlueprints ) . forEach ( ( [ path , blueprint ] ) => {
146+ const fullpath = `${ type } /${ path } ` ;
139147 if ( "error" in blueprint ) {
140148 result . push ( {
141149 name : blueprint . error ,
@@ -145,7 +153,8 @@ class HaBlueprintOverview extends LitElement {
145153 ) ,
146154 error : true ,
147155 path,
148- fullpath : `${ type } /${ path } ` ,
156+ fullpath,
157+ usageCount : 0 ,
149158 } ) ;
150159 } else {
151160 result . push ( {
@@ -156,7 +165,8 @@ class HaBlueprintOverview extends LitElement {
156165 ) ,
157166 error : false ,
158167 path,
159- fullpath : `${ type } /${ path } ` ,
168+ fullpath,
169+ usageCount : usageCounts [ fullpath ] || 0 ,
160170 } ) ;
161171 }
162172 } )
@@ -189,6 +199,34 @@ class HaBlueprintOverview extends LitElement {
189199 filterable : true ,
190200 flex : 2 ,
191201 } ,
202+ usage_count : {
203+ title : localize (
204+ "ui.panel.config.blueprint.overview.headers.usage_count"
205+ ) ,
206+ sortable : true ,
207+ valueColumn : "usageCount" ,
208+ type : "numeric" ,
209+ minWidth : "100px" ,
210+ maxWidth : "120px" ,
211+ template : ( blueprint ) => {
212+ const count = blueprint . usageCount ?? 0 ;
213+ return html `
214+ < ha-assist-chip
215+ filled
216+ .active =${ count > 0 }
217+ label =${ String ( count ) }
218+ title=${ blueprint . error
219+ ? String ( count )
220+ : this . hass . localize (
221+ `ui.panel.config.blueprint.overview.view_${ blueprint . type } `
222+ ) }
223+ ?disabled=${ blueprint . error }
224+ data-fullpath=${ blueprint . fullpath }
225+ @click=${ this . _handleUsageClick }
226+ > </ ha-assist-chip >
227+ ` ;
228+ } ,
229+ } ,
192230 fullpath : {
193231 title : "fullpath" ,
194232 hidden : true ,
@@ -266,6 +304,7 @@ class HaBlueprintOverview extends LitElement {
266304
267305 protected firstUpdated ( changedProps : PropertyValues ) {
268306 super . firstUpdated ( changedProps ) ;
307+ this . _loadUsageCounts ( ) ;
269308 if ( this . route . path === "/import" ) {
270309 const url = extractSearchParam ( "blueprint_url" ) ;
271310 navigate ( "/config/blueprint/dashboard" , { replace : true } ) ;
@@ -275,6 +314,13 @@ class HaBlueprintOverview extends LitElement {
275314 }
276315 }
277316
317+ protected updated ( changedProps : PropertyValues ) {
318+ super . updated ( changedProps ) ;
319+ if ( changedProps . has ( "blueprints" ) ) {
320+ this . _loadUsageCounts ( ) ;
321+ }
322+ }
323+
278324 protected render ( ) : TemplateResult {
279325 return html `
280326 < hass-tabs-subpage-data-table
@@ -284,7 +330,11 @@ class HaBlueprintOverview extends LitElement {
284330 .route=${ this . route }
285331 .tabs=${ configSections . automations }
286332 .columns=${ this . _columns ( this . hass . localize ) }
287- .data=${ this . _processedBlueprints ( this . blueprints , this . hass . localize ) }
333+ .data=${ this . _processedBlueprints (
334+ this . blueprints ,
335+ this . hass . localize ,
336+ this . _usageCounts
337+ ) }
288338 id="fullpath"
289339 .noDataText=${ this . hass . localize (
290340 "ui.panel.config.blueprint.overview.no_blueprints"
@@ -380,10 +430,51 @@ class HaBlueprintOverview extends LitElement {
380430 fireEvent ( this , "reload-blueprints" ) ;
381431 }
382432
433+ private async _loadUsageCounts ( ) {
434+ if ( ! this . blueprints ) {
435+ return ;
436+ }
437+
438+ const request = ++ this . _usageCountRequest ;
439+ const usageCounts : Record < string , number > = { } ;
440+
441+ const blueprintList = this . _processedBlueprints (
442+ this . blueprints ,
443+ this . hass . localize ,
444+ { }
445+ ) ;
446+
447+ await Promise . all (
448+ blueprintList . map ( async ( blueprint ) => {
449+ if ( blueprint . error ) {
450+ usageCounts [ blueprint . fullpath ] = 0 ;
451+ return ;
452+ }
453+ try {
454+ const related = await findRelated (
455+ this . hass ,
456+ `${ blueprint . domain } _blueprint` ,
457+ blueprint . path
458+ ) ;
459+ const count =
460+ ( related . automation ?. length || 0 ) + ( related . script ?. length || 0 ) ;
461+ usageCounts [ blueprint . fullpath ] = count ;
462+ } catch ( _err ) {
463+ usageCounts [ blueprint . fullpath ] = 0 ;
464+ }
465+ } )
466+ ) ;
467+
468+ if ( request === this . _usageCountRequest ) {
469+ this . _usageCounts = usageCounts ;
470+ }
471+ }
472+
383473 private _handleRowClicked ( ev : HASSDomEvent < RowClickedEvent > ) {
384474 const blueprint = this . _processedBlueprints (
385475 this . blueprints ,
386- this . hass . localize
476+ this . hass . localize ,
477+ this . _usageCounts
387478 ) . find ( ( b ) => b . fullpath === ev . detail . id ) ! ;
388479 if ( blueprint . error ) {
389480 showAlertDialog ( this , {
@@ -397,6 +488,25 @@ class HaBlueprintOverview extends LitElement {
397488 this . _createNew ( blueprint ) ;
398489 }
399490
491+ private _handleUsageClick = ( ev : Event ) => {
492+ ev . stopPropagation ( ) ;
493+ ev . preventDefault ( ) ;
494+ const target = ev . currentTarget as HTMLElement | null ;
495+ const fullpath = target ?. dataset . fullpath ;
496+ if ( ! fullpath ) {
497+ return ;
498+ }
499+ const blueprint = this . _processedBlueprints (
500+ this . blueprints ,
501+ this . hass . localize ,
502+ this . _usageCounts
503+ ) . find ( ( item ) => item . fullpath === fullpath ) ;
504+ if ( ! blueprint || blueprint . error ) {
505+ return ;
506+ }
507+ this . _showUsed ( blueprint ) ;
508+ } ;
509+
400510 private _showUsed = ( blueprint : BlueprintMetaDataPath ) => {
401511 navigate (
402512 `/config/${ blueprint . domain } /dashboard?blueprint=${ encodeURIComponent (
0 commit comments