11import { HomeAssistant } from "../ha-types" ;
22import { html , LitElement } from "../lit-element" ;
33import { IEntityConfig , IAttribute } from "../types" ;
4+ import { logError } from "../utils" ;
45
56const replaceKeywordsWithData = ( data : IMap < string > , text ?: string ) =>
67 text && text . replace ( / \{ ( [ a - z 0 - 9 _ ] + ) \} / g, ( match , keyword ) => data [ keyword ] !== undefined ? data [ keyword ] : match ) ;
78
9+ /**
10+ * Attribute name to icon map
11+ */
812const nameToIconMap : IMap < string > = {
913 "open_issues" : "mdi:alert-circle-outline" ,
1014 "open_pull_requests" : "mdi:source-pull" ,
@@ -17,13 +21,69 @@ const nameToIconMap: IMap<string> = {
1721 "views_unique" : "mdi:eye-check" ,
1822}
1923
20- const getStats = ( attrib : IAttribute [ ] , data : IMap < string > ) : IStat [ ] =>
21- attrib . map ( a => {
24+ /**
25+ * Attribute name to url path map
26+ */
27+ const nameToUrlPathMap : IMap < string > = {
28+ "open_issues" : "issues" ,
29+ "open_pull_requests" : "pulls" ,
30+ "stargazers" : "stargazers" ,
31+ "forks" : "network/members" ,
32+ "latest_release_tag" : "releases" ,
33+ "clones" : "graphs/traffic" ,
34+ "clones_unique" : "graphs/traffic" ,
35+ "views" : "graphs/traffic" ,
36+ "views_unique" : "graphs/traffic" ,
37+ "home" : ""
38+ }
39+
40+ /**
41+ * Creates action for clickable elements
42+ */
43+ const getAction = ( attributeName : string , url : boolean | string | undefined , data : IMap < string > ) : Function | undefined => {
44+ switch ( typeof url ) {
45+ case "boolean" :
46+ if ( ! url ) {
47+ return undefined ;
48+ }
49+
50+ if ( ! data [ "path" ] ) {
51+ logError ( `Cannot build url - entity path attribute is missing` ) ;
52+ return undefined ;
53+ }
54+
55+ if ( ! nameToUrlPathMap [ attributeName ] === undefined ) {
56+ logError ( `Sorry url cannot be built for "${ attributeName } "` ) ;
57+ return undefined ;
58+ }
59+
60+ return ( ) => window . open ( `https://github.com/${ data [ "path" ] } /${ nameToUrlPathMap [ attributeName ] } ` ) ;
61+ case "string" :
62+ return ( ) => window . open ( replaceKeywordsWithData ( data , url ) ) ;
63+ case "undefined" :
64+ // we don't do anything
65+ break ;
66+ default :
67+ logError ( "Unsupported url type: " + typeof url ) ;
68+ }
69+
70+ return undefined ;
71+ }
72+
73+ /**
74+ * Gets list of attributes data to render
75+ */
76+ const getAttributesViewData = ( config : IEntityConfig , data : IMap < string > ) : IAttributeViewData [ ] =>
77+ ( config . attributes || [ ] ) . map ( a => {
2278 return {
2379 value : data [ a . name ] ,
2480 icon : a . icon || nameToIconMap [ a . name ] ,
2581 label : a . label && replaceKeywordsWithData ( data , a . label ) ,
26- url : a . url && replaceKeywordsWithData ( data , a . url ) ,
82+ action : getAction (
83+ a . name ,
84+ // if attrib url property is missing use the entity-level setting
85+ a . url !== undefined ? a . url : config . attribute_urls ,
86+ data ) ,
2787 }
2888 } ) ;
2989
@@ -37,14 +97,19 @@ export class GithubEntity extends LitElement {
3797
3898 private secondaryInfo : string = < any > null ;
3999
40- private stats : IStat [ ] = [ ] ;
100+ private attributesData : IAttributeViewData [ ] = [ ] ;
101+
102+ private action : Function | undefined ;
103+
104+ private url : string | boolean | undefined ;
41105
42106 static get properties ( ) {
43107 return {
44108 icon : { type : String } ,
45109 name : { type : String } ,
46110 secondaryInfo : { type : String } ,
47111 stats : { type : Array } ,
112+ action : { type : Function } ,
48113 } ;
49114 }
50115
@@ -68,24 +133,33 @@ export class GithubEntity extends LitElement {
68133 this . secondaryInfo = replaceKeywordsWithData ( entityData . attributes , this . config . secondary_info ) as string ;
69134 }
70135
71- const newStats = getStats ( this . config . attributes || [ ] , entityData . attributes ) ;
136+ const newStats = getAttributesViewData ( this . config , entityData . attributes ) ;
72137 // check to avoid unnecessary re-rendering
73- if ( JSON . stringify ( newStats ) != JSON . stringify ( this . stats ) ) {
74- this . stats = newStats ;
138+ if ( JSON . stringify ( newStats ) != JSON . stringify ( this . attributesData ) ) {
139+ this . attributesData = newStats ;
140+ }
141+
142+ // check whether we need to update the action
143+ if ( this . url != this . config . url ) {
144+ this . url = this . config . url ;
145+ this . action = getAction ( "home" , this . url , entityData . attributes ) ;
75146 }
76147 }
77148
78149 setConfig ( config : IEntityConfig ) {
79150 const oldConfig = JSON . stringify ( this . config ) ;
80151 const newConfig = JSON . stringify ( config ) ;
81152
82- if ( oldConfig != newConfig ) {
83- this . config = config ;
84-
85- this . name = config . name || config . entity_id ;
86- config . icon && ( this . icon = config . icon ) ;
87- config . secondary_info && ( this . secondaryInfo = config . secondary_info ) ;
153+ if ( oldConfig == newConfig ) {
154+ return ;
88155 }
156+
157+ // we cannot just assign the config because it is immutable and we want to change it
158+ this . config = JSON . parse ( newConfig ) ;
159+
160+ this . name = config . name || config . entity_id ;
161+ config . icon && ( this . icon = config . icon ) ;
162+ config . secondary_info && ( this . secondaryInfo = config . secondary_info ) ;
89163 }
90164
91165 createRenderRoot ( ) {
@@ -98,11 +172,11 @@ export class GithubEntity extends LitElement {
98172 < div class ="icon ">
99173 < ha-icon icon ="${ this . icon } "> </ ha-icon >
100174 </ div >
101- < div class ="name truncate ">
175+ < div class ="name truncate ${ this . action ? " clickable" : "" } " @click =" ${ this . action } ">
102176 ${ this . name }
103177 ${ this . secondaryInfo && html `< div class ="secondary "> ${ this . secondaryInfo } </ div > ` }
104178 </ div >
105- ${ this . stats . map ( s => html `< div class ="state "> < ha-icon icon ="${ s . icon } " style ="color: var(--primary-color) "> </ ha-icon > < div > ${ s . value } </ div > </ div > ` ) }
179+ ${ this . attributesData . map ( s => html `< div class ="state ${ s . action ? " clickable" : "" } " @click =" ${ s . action } "> < ha-icon icon ="${ s . icon } " style ="color: var(--primary-color) "> </ ha-icon > < div > ${ s . value } </ div > </ div > ` ) }
106180 < div >
107181 ` ;
108182 }
@@ -112,9 +186,9 @@ interface IMap<T> {
112186 [ key : string ] : T
113187}
114188
115- interface IStat {
189+ interface IAttributeViewData {
116190 value : string ,
117191 icon ?: string ,
118192 label ?: string ,
119- url ?: string ,
193+ action ?: Function ,
120194}
0 commit comments