1+ function arrayKey ( array ) {
2+ return array . join ( "," ) ;
3+ }
4+
15class AbstractResults extends React . Component {
6+ constructor ( props ) {
7+ super ( props ) ;
8+ this . state = { toggles : new Map ( ) , data : this . getData ( ) } ;
9+ this . toggleCallback = this . toggleCallback . bind ( this ) ;
10+ }
11+
212 render ( ) {
13+ if ( this . state . data . toggleLabels . size > 0 ) {
14+ this . initToggleStates ( this . state . data . toggleLabels ) ;
15+ return e (
16+ "div" ,
17+ { } ,
18+ e (
19+ "div" ,
20+ { className : "flex gap-2 rounded bg-slate-800" } ,
21+ this . getToggleControls ( this . state . data . toggleLabels ) ,
22+ ) ,
23+ this . getResultsTable ( this . state . data )
24+ )
25+ } else {
26+ return this . getResultsTable ( this . state . data ) ;
27+ }
28+ }
29+
30+ initToggleStates ( toggleLabels ) {
31+ let toggles = this . state . toggles ;
32+ toggles . clear ( ) ;
33+ toggleLabels . forEach ( function ( value , key ) {
34+ toggles . set ( key , value [ 0 ] ) ;
35+ } )
36+ }
37+
38+ getToggleControls ( toggleLabels ) {
39+ let toggleCallback = this . toggleCallback ;
40+ return toggleLabels . entries ( ) . map ( function ( entry ) {
41+ let [ name , values ] = entry ;
42+ return e (
43+ Toggle ,
44+ {
45+ label : name ,
46+ values : values ,
47+ callback : function ( selected ) {
48+ toggleCallback ( name , selected ) ;
49+ }
50+ }
51+ )
52+ } )
53+ }
54+
55+ toggleCallback ( name , selected ) {
56+ let data = this . state . data ;
57+ this . setState ( function ( prevState ) {
58+ let toggles = new Map ( prevState . toggles ) ;
59+ toggles . set ( name , selected ) ;
60+ return { data : data , toggles } ;
61+ } ) ;
62+ }
63+
64+ getResultsTable ( data ) {
365 return e (
466 "table" ,
567 { className : "table-auto text-white text-sm w-full" } ,
668 e (
769 "thead" ,
870 { } ,
9- this . renderHeader ( ) ,
71+ this . renderHeader ( data ) ,
1072 ) ,
1173 e (
1274 "tbody" ,
1375 { } ,
14- this . renderEntries ( )
76+ this . renderEntries ( data ) ,
1577 )
1678 )
1779 }
@@ -50,106 +112,142 @@ class AbstractResults extends React.Component {
50112 } ) ;
51113 }
52114
53- isLabelled ( ) {
54- return this . getResults ( ) . every ( function ( [ path , result ] ) {
55- return result . labels ;
56- } ) ;
57- }
58-
59- renderHeader ( ) {
115+ getData ( ) {
116+ let labels ;
60117 if ( this . isLabelled ( ) ) {
61- return e (
62- "tr" ,
63- { } ,
64- this . getLabels ( ) . map ( function ( label ) {
65- return e (
66- "th" ,
67- { className : "text-left p-1 uppercase" } ,
68- label
69- )
70- } ) ,
71- e (
72- "th" ,
73- { className : "text-right p-1 w-fit" } ,
74- )
75- )
76- } else {
77- return e (
78- "tr" ,
79- { } ,
80- e (
81- "th" ,
82- { className : "text-left p-1" } ,
83- "Filename"
84- ) ,
85- e (
86- "th" ,
87- { className : "text-right p-1 w-fit" } ,
88- )
89- )
118+ labels = this . getLabels ( ) ;
90119 }
91- }
92120
93- renderEntries ( ) {
94- AbstractResults . propTypes = {
95- app : PropTypes . object . isRequired ,
96- } ;
121+ let results = this . getResults ( ) ;
97122
98- let app = this . props . app ;
99- let labels ;
100- if ( this . isLabelled ( ) ) {
101- labels = this . getLabels ( ) ;
123+ let toggleLabels = new Map ( ) ;
124+ if ( labels !== undefined ) {
125+ labels . forEach ( function ( label ) {
126+ let values = results . map ( function ( [ path , entry ] ) {
127+ return entry . labels [ label ] ;
128+ } ) . filter ( function ( value ) {
129+ return value !== undefined ;
130+ } ) ;
131+
132+ let uniqueValues = [ ...new Set ( values ) ] ;
133+ if (
134+ uniqueValues . length == 2 &&
135+ uniqueValues . every ( value => values . filter ( v => v === value ) . length === results . length / 2 )
136+ ) {
137+ uniqueValues . sort ( ) ;
138+ toggleLabels . set ( label , uniqueValues ) ;
139+ }
140+ } ) ;
102141 }
103- let entries = this . getResults ( ) . map ( function ( [ path , entry ] ) {
104- let entryLabels ;
105- let key ;
142+
143+ let entries = new Map ( ) ;
144+ let entryLabelValues = [ ] ;
145+
146+ results . forEach ( function ( [ path , entry ] ) {
147+ let entryLabels = [ ] ;
148+ let entryToggleLabels = [ ] ;
106149 if ( labels !== undefined ) {
107- entryLabels = labels . map ( function ( label ) {
108- return entry . labels [ label ] || "" ;
150+ labels . forEach ( function ( label ) {
151+ if ( ! toggleLabels . has ( label ) ) {
152+ entryLabels . push ( entry . labels [ label ] || "" ) ;
153+ } else {
154+ entryToggleLabels . push ( entry . labels [ label ] ) ;
155+ }
109156 } ) ;
110- key = labels . join ( ) ;
111157 } else {
112158 entryLabels = [ path ] ;
113- key = path ;
114159 }
115160
116- return {
117- key : key ,
118- path : path ,
119- labels : entryLabels
120- } ;
161+ let key = arrayKey ( entryLabels ) ;
162+
163+ if ( ! entries . has ( key ) ) {
164+ entries . set ( key , new Map ( ) ) ;
165+ entryLabelValues . push ( entryLabels ) ;
166+ }
167+
168+ entries . get ( key ) . set ( arrayKey ( entryToggleLabels ) , path ) ;
121169 } ) ;
122170
123- entries = entries . sort ( function ( a , b ) {
171+ entryLabelValues = entryLabelValues . sort ( function ( aLabels , bLabels ) {
124172 // sort labels lexicographically, first element is the most important
125- for ( let i = 0 ; i < a . labels . length ; i ++ ) {
126- let comparison = a . labels [ i ] . localeCompare ( b . labels [ i ] ) ;
173+ for ( let i = 0 ; i < aLabels . length ; i ++ ) {
174+ let comparison = aLabels [ i ] . localeCompare ( bLabels [ i ] ) ;
127175 if ( comparison !== 0 ) {
128176 return comparison ;
129177 }
130178 }
131179 return 0 ;
132180 } ) ;
133181
134- return entries . map ( function ( entry ) {
182+ if ( labels === undefined ) {
183+ labels = [ "File" ] ;
184+ }
185+
186+ return {
187+ entryLabels : labels . filter ( ( label ) => toggleLabels . has ( label ) ) ,
188+ entryLabelValues : entryLabelValues ,
189+ toggleLabels : toggleLabels ,
190+ entries : entries ,
191+ }
192+ }
193+
194+ isLabelled ( ) {
195+ return this . getResults ( ) . every ( function ( [ path , result ] ) {
196+ return result . labels ;
197+ } ) ;
198+ }
199+
200+ renderHeader ( data ) {
201+ return e (
202+ "tr" ,
203+ { } ,
204+ data . entryLabels . map ( function ( label ) {
205+ return e (
206+ "th" ,
207+ { className : "text-left p-1 uppercase" } ,
208+ label
209+ )
210+ } ) ,
211+ e (
212+ "th" ,
213+ { className : "text-right p-1 w-fit" } ,
214+ )
215+ )
216+ }
217+
218+ renderEntries ( data ) {
219+ AbstractResults . propTypes = {
220+ app : PropTypes . object . isRequired ,
221+ } ;
222+
223+ let app = this . props . app ;
224+ let state = this . state ;
225+
226+ return data . entryLabelValues . map ( function ( entryLabels ) {
227+ let toggleLabels = Array . from ( data . toggleLabels . keys ( ) . map ( ( label ) => state . toggles . get ( label ) ) ) ;
228+ let entryPath = data . entries . get ( arrayKey ( entryLabels ) ) . get ( arrayKey ( toggleLabels ) ) ;
229+ console . log ( {
230+ toggleLabels,
231+ entryPath,
232+ entryLabels,
233+ } ) ;
234+
235+
135236 let actions = e (
136237 "td" ,
137238 { className : "p-1 text-right" } ,
138239 e (
139240 "div" ,
140241 { className : "inline-flex gap-1" , role : "group" } ,
141- e (
142- Toggle ,
143- ) ,
144242 e (
145243 ResultViewButton ,
146- { resultPath : entry . path , app : app }
244+ { resultPath : entryPath , app : app }
147245 ) ,
148246 e (
149247 Button ,
150248 {
151249 href : "#" ,
152- onClick : ( ) => app . showResultInfo ( path ) ,
250+ onClick : ( ) => app . showResultInfo ( entryPath ) ,
153251 iconName : "information-circle"
154252 }
155253 )
@@ -159,8 +257,8 @@ class AbstractResults extends React.Component {
159257 return [
160258 e (
161259 "tr" ,
162- { key : entry . key } ,
163- entry . labels . map ( function ( labelValue ) {
260+ { key : entryLabels . join ( "," ) } ,
261+ entryLabels . map ( function ( labelValue ) {
164262 return e (
165263 "td" ,
166264 { className : "p-1" } ,
0 commit comments