11import * as React from "react" ;
22import * as Sarif from "sarif" ;
33import * as Keys from "./result-keys" ;
4- import { info , listUnordered } from "./octicons" ;
54import {
65 className ,
76 ResultTableProps ,
8- selectableZebraStripe ,
97 jumpToLocation ,
108} from "./result-table-utils" ;
119import { onNavigation } from "./ResultsApp" ;
@@ -19,11 +17,9 @@ import { parseSarifLocation, isNoLocation } from "../../common/sarif-utils";
1917import { ScrollIntoViewHelper } from "./scroll-into-view-helper" ;
2018import { sendTelemetry } from "../common/telemetry" ;
2119import { AlertTableHeader } from "./AlertTableHeader" ;
22- import { SarifMessageWithLocations } from "./locations/SarifMessageWithLocations" ;
23- import { SarifLocation } from "./locations/SarifLocation" ;
24- import { EmptyQueryResultsMessage } from "./EmptyQueryResultsMessage" ;
25- import TextButton from "../common/TextButton" ;
26- import { AlertTableDropdownIndicatorCell } from "./AlertTableDropdownIndicatorCell" ;
20+ import { AlertTableNoResults } from "./AlertTableNoResults" ;
21+ import { AlertTableTruncatedMessage } from "./AlertTableTruncatedMessage" ;
22+ import { AlertTableResultRow } from "./AlertTableResultRow" ;
2723
2824type AlertTableProps = ResultTableProps & {
2925 resultSet : InterpretedResultSet < SarifInterpretationData > ;
@@ -70,263 +66,50 @@ export class AlertTable extends React.Component<
7066 e . preventDefault ( ) ;
7167 }
7268
73- renderNoResults ( ) : JSX . Element {
74- if ( this . props . nonemptyRawResults ) {
75- return (
76- < span >
77- No Alerts. See{ " " }
78- < TextButton onClick = { this . props . showRawResults } >
79- raw results
80- </ TextButton >
81- .
82- </ span >
83- ) ;
84- } else {
85- return < EmptyQueryResultsMessage /> ;
86- }
87- }
88-
8969 render ( ) : JSX . Element {
9070 const { databaseUri, resultSet } = this . props ;
9171
92- const rows : JSX . Element [ ] = [ ] ;
9372 const { numTruncatedResults, sourceLocationPrefix } =
9473 resultSet . interpretation ;
9574
9675 const updateSelectionCallback = (
9776 resultKey : Keys . PathNode | Keys . Result | undefined ,
9877 ) => {
99- return ( ) => {
100- this . setState ( ( previousState ) => ( {
101- ...previousState ,
102- selectedItem : resultKey ,
103- } ) ) ;
104- sendTelemetry ( "local-results-alert-table-path-selected" ) ;
105- } ;
106- } ;
107-
108- const toggler : ( keys : Keys . ResultKey [ ] ) => ( e : React . MouseEvent ) => void = (
109- indices ,
110- ) => {
111- return ( e ) => this . toggle ( e , indices ) ;
78+ this . setState ( ( previousState ) => ( {
79+ ...previousState ,
80+ selectedItem : resultKey ,
81+ } ) ) ;
82+ sendTelemetry ( "local-results-alert-table-path-selected" ) ;
11283 } ;
11384
11485 if ( ! resultSet . interpretation . data . runs ?. [ 0 ] ?. results ?. length ) {
115- return this . renderNoResults ( ) ;
116- }
117-
118- resultSet . interpretation . data . runs [ 0 ] . results . forEach (
119- ( result , resultIndex ) => {
120- const resultKey : Keys . Result = { resultIndex } ;
121- const text = result . message . text || "[no text]" ;
122- const msg =
123- result . relatedLocations === undefined ? (
124- < span key = "0" > { text } </ span >
125- ) : (
126- < SarifMessageWithLocations
127- msg = { text }
128- relatedLocations = { result . relatedLocations }
129- sourceLocationPrefix = { sourceLocationPrefix }
130- databaseUri = { databaseUri }
131- onClick = { updateSelectionCallback ( resultKey ) }
132- />
133- ) ;
134-
135- const currentResultExpanded = this . state . expanded . has (
136- Keys . keyToString ( resultKey ) ,
137- ) ;
138- const location = result . locations !== undefined &&
139- result . locations . length > 0 && (
140- < SarifLocation
141- loc = { result . locations [ 0 ] }
142- sourceLocationPrefix = { sourceLocationPrefix }
143- databaseUri = { databaseUri }
144- onClick = { updateSelectionCallback ( resultKey ) }
145- />
146- ) ;
147- const locationCells = (
148- < td className = "vscode-codeql__location-cell" > { location } </ td >
149- ) ;
150-
151- const selectedItem = this . state . selectedItem ;
152- const resultRowIsSelected =
153- selectedItem ?. resultIndex === resultIndex &&
154- selectedItem . pathIndex === undefined ;
155-
156- if ( result . codeFlows === undefined ) {
157- rows . push (
158- < tr
159- ref = { this . scroller . ref ( resultRowIsSelected ) }
160- key = { resultIndex }
161- { ...selectableZebraStripe ( resultRowIsSelected , resultIndex ) }
162- >
163- < td className = "vscode-codeql__icon-cell" > { info } </ td >
164- < td colSpan = { 3 } > { msg } </ td >
165- { locationCells }
166- </ tr > ,
167- ) ;
168- } else {
169- const paths : Sarif . ThreadFlow [ ] = Keys . getAllPaths ( result ) ;
170-
171- const indices =
172- paths . length === 1
173- ? [ resultKey , { ...resultKey , pathIndex : 0 } ]
174- : /* if there's exactly one path, auto-expand
175- * the path when expanding the result */
176- [ resultKey ] ;
177-
178- rows . push (
179- < tr
180- ref = { this . scroller . ref ( resultRowIsSelected ) }
181- { ...selectableZebraStripe ( resultRowIsSelected , resultIndex ) }
182- key = { resultIndex }
183- >
184- < AlertTableDropdownIndicatorCell
185- expanded = { currentResultExpanded }
186- onClick = { toggler ( indices ) }
187- />
188- < td className = "vscode-codeql__icon-cell" > { listUnordered } </ td >
189- < td colSpan = { 2 } > { msg } </ td >
190- { locationCells }
191- </ tr > ,
192- ) ;
193-
194- paths . forEach ( ( path , pathIndex ) => {
195- const pathKey = { resultIndex, pathIndex } ;
196- const currentPathExpanded = this . state . expanded . has (
197- Keys . keyToString ( pathKey ) ,
198- ) ;
199- if ( currentResultExpanded ) {
200- const isPathSpecificallySelected = Keys . equalsNotUndefined (
201- pathKey ,
202- selectedItem ,
203- ) ;
204- rows . push (
205- < tr
206- ref = { this . scroller . ref ( isPathSpecificallySelected ) }
207- { ...selectableZebraStripe (
208- isPathSpecificallySelected ,
209- resultIndex ,
210- ) }
211- key = { `${ resultIndex } -${ pathIndex } ` }
212- >
213- < td className = "vscode-codeql__icon-cell" >
214- < span className = "vscode-codeql__vertical-rule" > </ span >
215- </ td >
216- < AlertTableDropdownIndicatorCell
217- expanded = { currentPathExpanded }
218- onClick = { toggler ( [ pathKey ] ) }
219- />
220- < td className = "vscode-codeql__text-center" colSpan = { 3 } >
221- Path
222- </ td >
223- </ tr > ,
224- ) ;
225- }
226-
227- if ( currentResultExpanded && currentPathExpanded ) {
228- const pathNodes = path . locations ;
229- for (
230- let pathNodeIndex = 0 ;
231- pathNodeIndex < pathNodes . length ;
232- ++ pathNodeIndex
233- ) {
234- const pathNodeKey : Keys . PathNode = {
235- ...pathKey ,
236- pathNodeIndex,
237- } ;
238- const step = pathNodes [ pathNodeIndex ] ;
239- const msg =
240- step . location !== undefined &&
241- step . location . message !== undefined ? (
242- < SarifLocation
243- text = { step . location . message . text }
244- loc = { step . location }
245- sourceLocationPrefix = { sourceLocationPrefix }
246- databaseUri = { databaseUri }
247- onClick = { updateSelectionCallback ( pathNodeKey ) }
248- />
249- ) : (
250- "[no location]"
251- ) ;
252- const additionalMsg =
253- step . location !== undefined ? (
254- < SarifLocation
255- loc = { step . location }
256- sourceLocationPrefix = { sourceLocationPrefix }
257- databaseUri = { databaseUri }
258- onClick = { updateSelectionCallback ( pathNodeKey ) }
259- />
260- ) : (
261- ""
262- ) ;
263- const isSelected = Keys . equalsNotUndefined (
264- this . state . selectedItem ,
265- pathNodeKey ,
266- ) ;
267- const stepIndex = pathNodeIndex + 1 ; // Convert to 1-based
268- const zebraIndex = resultIndex + stepIndex ;
269- rows . push (
270- < tr
271- ref = { this . scroller . ref ( isSelected ) }
272- className = {
273- isSelected
274- ? "vscode-codeql__selected-path-node"
275- : undefined
276- }
277- key = { `${ resultIndex } -${ pathIndex } -${ pathNodeIndex } ` }
278- >
279- < td className = "vscode-codeql__icon-cell" >
280- < span className = "vscode-codeql__vertical-rule" > </ span >
281- </ td >
282- < td className = "vscode-codeql__icon-cell" >
283- < span className = "vscode-codeql__vertical-rule" > </ span >
284- </ td >
285- < td
286- { ...selectableZebraStripe (
287- isSelected ,
288- zebraIndex ,
289- "vscode-codeql__path-index-cell" ,
290- ) }
291- >
292- { stepIndex }
293- </ td >
294- < td { ...selectableZebraStripe ( isSelected , zebraIndex ) } >
295- { msg } { " " }
296- </ td >
297- < td
298- { ...selectableZebraStripe (
299- isSelected ,
300- zebraIndex ,
301- "vscode-codeql__location-cell" ,
302- ) }
303- >
304- { additionalMsg }
305- </ td >
306- </ tr > ,
307- ) ;
308- }
309- }
310- } ) ;
311- }
312- } ,
313- ) ;
314-
315- if ( numTruncatedResults > 0 ) {
316- rows . push (
317- < tr key = "truncatd-message" >
318- < td colSpan = { 5 } style = { { textAlign : "center" , fontStyle : "italic" } } >
319- Too many results to show at once. { numTruncatedResults } result(s)
320- omitted.
321- </ td >
322- </ tr > ,
323- ) ;
86+ return < AlertTableNoResults { ...this . props } /> ;
32487 }
32588
32689 return (
32790 < table className = { className } >
32891 < AlertTableHeader sortState = { resultSet . interpretation . data . sortState } />
329- < tbody > { rows } </ tbody >
92+ < tbody >
93+ { resultSet . interpretation . data . runs [ 0 ] . results . map (
94+ ( result , resultIndex ) => (
95+ < AlertTableResultRow
96+ key = { resultIndex }
97+ result = { result }
98+ resultIndex = { resultIndex }
99+ expanded = { this . state . expanded }
100+ selectedItem = { this . state . selectedItem }
101+ databaseUri = { databaseUri }
102+ sourceLocationPrefix = { sourceLocationPrefix }
103+ updateSelectionCallback = { updateSelectionCallback }
104+ toggleExpanded = { this . toggle . bind ( this ) }
105+ scroller = { this . scroller }
106+ />
107+ ) ,
108+ ) }
109+ < AlertTableTruncatedMessage
110+ numTruncatedResults = { numTruncatedResults }
111+ />
112+ </ tbody >
330113 </ table >
331114 ) ;
332115 }
0 commit comments