11import { Element } from '@core/element'
2- import { html , css } from 'lit'
2+ import { html , css , nothing } from 'lit'
33import { customElement } from 'lit/decorators.js'
44import { consume } from '@lit/context'
55import type { CommandLog } from '@devtools/hook/types'
@@ -10,13 +10,17 @@ import '~icons/mdi/pencil.js'
1010import '~icons/mdi/family-tree.js'
1111import '~icons/mdi/alert.js'
1212import '~icons/mdi/document.js'
13+ import '~icons/mdi/arrow-right.js'
1314
14- const ICON_CLASS = 'w-[20px] h-[20px] m-1 mr-2 shrink-0'
15+ type ActionEntry = TraceMutation | CommandLog
1516
17+ const ONE_MINUTE = 1000 * 60
18+ const ICON_CLASS = 'w-[20px] h-[20px] m-1 mr-2 shrink-0 block'
1619const SOURCE_COMPONENT = 'wdio-devtools-actions'
20+
1721@customElement ( SOURCE_COMPONENT )
1822export class DevtoolsActions extends Element {
19- #entries: ( TraceMutation | CommandLog ) [ ] = [ ]
23+ #entries: ActionEntry [ ] = [ ]
2024 #activeEntry?: number
2125 #highlightedMutation?: number
2226
@@ -28,6 +32,10 @@ export class DevtoolsActions extends Element {
2832 }
2933 ` ]
3034
35+ get mutationEntries ( ) {
36+ return this . #entries. filter ( ( entry ) => ! ( 'command' in entry ) ) as TraceMutation [ ]
37+ }
38+
3139 @consume ( { context } )
3240 data : TraceLog = { } as TraceLog
3341
@@ -45,22 +53,42 @@ export class DevtoolsActions extends Element {
4553 return this . #entries. map ( ( entry , i ) => {
4654 if ( 'command' in entry ) {
4755 return html `
48- < button @click ="${ ( ) => this . #highlightLine( entry . callSource ) } "> ${ entry . command } </ button >
56+ < button class ="flex px-2 items-center " @click ="${ ( ) => this . #highlightLine( entry . callSource ) } ">
57+ < icon-mdi-arrow-right class ="${ ICON_CLASS } "> </ icon-mdi-arrow-right >
58+ ${ this . #renderTime( entry ) }
59+ < code class ="text-sm flex-wrap text-left break-all "> ${ entry . command } (${ entry . args . map ( ( arg ) => JSON . stringify ( arg , null , 2 ) ) . join ( ', ' ) } )</ code >
60+ </ button >
4961 `
5062 }
5163
5264 return html `
5365 < button
5466 @mousemove ="${ ( ) => this . #showMutationTarget( i ) } "
55- @click ="${ ( ) => this . #selectMutation( i ) } "
56- class ="flex items-center justify-center text-sm w-full px-4 hover:bg-toolbarHoverBackground ${ this . #activeEntry === i ? 'bg-toolbarHoverBackground' : '' } "
67+ @click ="${ ( ) => this . #selectMutation( this . mutationEntries . indexOf ( entry ) , i ) } "
68+ class ="flex items-center justify-center text-sm w-full px-2 hover:bg-toolbarHoverBackground ${ this . #activeEntry === i ? 'bg-toolbarHoverBackground' : '' } "
5769 >
5870 ${ this . #getMutationLabel( entry ) }
5971 </ button >
6072 `
6173 } )
6274 }
6375
76+ #renderTime ( entry : ActionEntry ) {
77+ const diff = entry . timestamp - this . data . mutations [ 0 ] . timestamp
78+ let diffLabel = `${ diff } ms`
79+ if ( diff > 1000 ) {
80+ diffLabel = `${ ( diff / 1000 ) . toFixed ( 2 ) } s`
81+ }
82+ if ( diff > ONE_MINUTE ) {
83+ const minutes = Math . floor ( diff / 1000 / 60 )
84+ diffLabel = `${ minutes } m ${ Math . floor ( ( diff - minutes * ONE_MINUTE ) / 1000 ) } s`
85+ }
86+
87+ return html `
88+ < span class ="text-xs text-gray-500 shrink-0 pr-2 text-debugTokenExpressionName "> ${ diffLabel } </ span >
89+ `
90+ }
91+
6492 #getMutationLabel( mutation : TraceMutation ) {
6593 if ( mutation . type === 'attributes' ) {
6694 return this . #getAttributeMutationLabel( mutation )
@@ -73,35 +101,53 @@ export class DevtoolsActions extends Element {
73101 #getAttributeMutationLabel( mutation : TraceMutation ) {
74102 return html `
75103 < icon-mdi-pencil class ="${ ICON_CLASS } "> </ icon-mdi-pencil >
76- < span class ="flex-grow "> ${ mutation . target } attribute "< code > ${ mutation . attributeName } </ code > " changed</ span >
104+ ${ this . #renderTime( mutation ) }
105+ < span class ="flex-grow text-left "> element attribute "< code > ${ mutation . attributeName } </ code > " changed</ span >
77106 `
78107 }
79108
80109 #getChildListMutationLabel( mutation : TraceMutation ) {
81110 if ( mutation . addedNodes . length === 1 && ( mutation . addedNodes [ 0 ] as any ) . type === 'html' ) {
82111 return html `
83112 < icon-mdi-document class ="${ ICON_CLASS } "> </ icon-mdi-document >
84- < span class ="flex-grow "> Document loaded</ span >
113+ ${ this . #renderTime( mutation ) }
114+ < span class ="flex-grow text-left "> Document loaded</ span >
85115 `
86116 }
87117 return html `
88118 < icon-mdi-family-tree class ="${ ICON_CLASS } "> </ icon-mdi-family-tree >
89- < span class ="flex-grow "> ${ mutation . target } child list changed</ span >
119+ ${ this . #renderTime( mutation ) }
120+ < span class ="flex-grow text-left ">
121+ ${ this . #renderNodeAmount( mutation . addedNodes , 'added' ) }
122+ ${ mutation . addedNodes . length && mutation . removedNodes . length
123+ ? ' and '
124+ : nothing }
125+ ${ this . #renderNodeAmount( mutation . removedNodes , 'removed' ) }
126+ </ span >
90127 `
91128 }
92129
130+ #renderNodeAmount ( nodes : ( string | SimplifiedVNode ) [ ] , operationType : 'added' | 'removed' ) {
131+ if ( ! nodes . length ) {
132+ return nothing
133+ }
134+ let nodeLabel = 'node'
135+ if ( nodes . length > 1 ) {
136+ nodeLabel = 'nodes'
137+ }
138+ return html `${ nodes . length } ${ nodeLabel } ${ operationType } `
139+ }
140+
93141 #highlightLine( callSource : string ) {
94142 const event = new CustomEvent ( 'app-source-highlight' , {
95143 detail : callSource
96144 } )
97145 window . dispatchEvent ( event )
98146 }
99147
100- #selectMutation( i : number ) {
101- this . #activeEntry = i
102- const event = new CustomEvent ( 'app-mutation-select' , {
103- detail : this . #entries[ this . #activeEntry]
104- } )
148+ #selectMutation( detail : number , listIndex : number ) {
149+ this . #activeEntry = listIndex
150+ const event = new CustomEvent ( 'app-mutation-select' , { detail } )
105151 window . dispatchEvent ( event )
106152 this . requestUpdate ( )
107153 }
0 commit comments