import { ComponentDetails } from 'jfrog-client-js' ; import Set from 'typescript-collections/dist/lib/Set' ; import * as vscode from 'vscode' ; import { ScanLogicManager } from '../../scanLogic/scanLogicManager' ; import { GeneralInfo } from '../../types/generalInfo' ; import { ILicenseKey } from '../../types/licenseKey' ; import { INodeInfo } from '../../types/nodeInfo' ; import { Scope } from '../../types/scope' ; import { Severity , SeverityUtils } from '../../types/severity' ; import { MavenUtils } from '../../utils/mavenUtils' ; import { ScanCancellationError , ScanUtils } from '../../utils/scanUtils' ; import { TreesManager } from '../treesManager' ; import { RootNode } from './dependenciesRoot/rootTree' ; import { DependenciesTreesFactory } from './dependenciesTreeFactory' ; import { DependenciesTreeNode } from './dependenciesTreeNode' ; export class DependenciesTreeDataProvider implements vscode . TreeDataProvider < DependenciesTreeNode > { private _filterLicenses : Set < ILicenseKey > = new Set ( ) ; private _filterScopes : Set < Scope > = new Set ( scope => scope . label ) ; private _filteredDependenciesTree : DependenciesTreeNode | undefined ; protected _dependenciesTree ! : DependenciesTreeNode ; private _scanInProgress : boolean = false ; constructor ( protected _workspaceFolders , protected _treesManager , private _scanLogicManager ) { } public get dependenciesTree ( ) { return this . _dependenciesTree ; } public async stateChange ( onChangeFire ) { if ( ! this . dependenciesTree ) { this . refresh ( false , onChangeFire ) ; return ; } onChangeFire ( ) ; } public async refresh ( quickScan , onChangeFire ) { if ( this . _scanInProgress ) { if ( ! quickScan ) { vscode . window . showInformationMessage ( 'Previous scan still running...' ) ; } return ; } this . _scanInProgress = true ; ScanUtils . setScanInProgress ( true ) ; this . _treesManager . logManager . logMessage ( 'Starting ' + ( quickScan ? 'quick' : 'slow' ) + ' scan' , 'INFO' ) ; this . repopulateTree ( quickScan , onChangeFire ) . then ( ( ) => { vscode . commands . executeCommand ( 'jfrog.xray.focus' ) ; this . _treesManager . logManager . setSuccess ( ) ; } ) . catch ( error => { this . clearTree ( ) ; if ( error instanceof ScanCancellationError ) { vscode . window . showInformationMessage ( error . message ) ; } else { this . _treesManager . logManager . logError ( error , ! quickScan ) ; } } ) . finally ( ( ) => { this . _scanInProgress = false ; ScanUtils . setScanInProgress ( false ) ; } ) ; } public getTreeItem ( element ) { element . command = { command : 'jfrog.xray.focus' , title : '' , arguments : [ element ] } ; let topSeverity = element . topSeverity ; element . iconPath = SeverityUtils . getIcon ( topSeverity ? topSeverity : Severity . Normal ) ; return element ; } public getChildren ( element ? ) { if ( ! this . dependenciesTree ) { return Promise . resolve ( [ ] ) ; } if ( element ) { return Promise . resolve ( element . children ) ; } let rootChildren = this . _filteredDependenciesTree ? this . _filteredDependenciesTree . children : this . dependenciesTree . children ; return Promise . resolve ( rootChildren . length === 1 ? rootChildren [ 0 ] . children : rootChildren ) ; } public getParent ( element ) { return Promise . resolve ( element . parent ) ; } public applyFilters ( filteredDependenciesTree , onChangeFire ) { this . _filteredDependenciesTree = filteredDependenciesTree ; onChangeFire ( ) ; } public removeNode ( node , onChangeFire ) { let nodeIndex = node . parent ?. children . indexOf ( node ) ; if ( nodeIndex === undefined || nodeIndex < 0 ) { return ; } node . parent ?. children . splice ( nodeIndex , 1 ) ; this . refresh ( true , onChangeFire ) ; } public addXrayInfoToTree ( root ) { root . children . forEach ( child => { let generalInfo = child . generalInfo ; let scanCacheObject = this . _treesManager . scanCacheManager . getNodeInfo ( generalInfo . getComponentId ( ) ) ; if ( scanCacheObject ) { child . topSeverity = scanCacheObject . top_severity ; scanCacheObject . issues . forEach ( issue => child . issues . add ( issue ) ) ; scanCacheObject . licenses . forEach ( license => child . licenses . add ( license ) ) ; this . filterLicenses . union ( child . licenses ) ; generalInfo . scopes . map ( scope => this . filterScopes . add ( new Scope ( scope ) ) ) ; } this . addXrayInfoToTree ( child ) ; } ) ; } private async repopulateTree ( quickScan , onChangeFire ) { await ScanUtils . scanWithProgress ( async ( progress , checkCanceled ) => { this . clearTree ( ) ; let workspaceRoot = < DependenciesTreeNode > this . dependenciesTree ; let componentsToScan = new Set ( ) ; await DependenciesTreesFactory . createDependenciesTrees ( this . _workspaceFolders , componentsToScan , this . _treesManager , workspaceRoot , quickScan ) ; await this . _scanLogicManager . scanAndCache ( progress , componentsToScan , checkCanceled ) ; for ( let node of workspaceRoot . children ) { this . addXrayInfoToTree ( node ) ; if ( node instanceof RootNode ) { node . setUpgradableDependencies ( this . _treesManager . scanCacheManager ) ; } node . issues = node . processTreeIssues ( ) ; } onChangeFire ( ) ; } , 'Scanning project dependencies ' ) ; } private clearTree ( ) { this . _filteredDependenciesTree = undefined ; let generalInfo = new GeneralInfo ( '' , '' , [ ] , '' , '' ) ; this . _dependenciesTree = new DependenciesTreeNode ( generalInfo , vscode . TreeItemCollapsibleState . Expanded ) ; } public get filterLicenses ( ) : Set < ILicenseKey > { return this . _filterLicenses ; } public get filterScopes ( ) : Set < Scope > { return this . _filterScopes ; } public getDependenciesTreeNode ( pkgType , path ? ) { if ( ! ( this . dependenciesTree instanceof DependenciesTreeNode ) ) { return undefined ; } if ( pkgType === 'maven' ) { return MavenUtils . pathToNode . get ( path || '' ) ; } let root = this . _filteredDependenciesTree || this . dependenciesTree ; for ( let dependenciesTree of root . children ) { let generalInfo = dependenciesTree . generalInfo ; if ( generalInfo . pkgType === pkgType && ( ! path || generalInfo . path === path ) ) { return dependenciesTree ; } } return undefined ; } }