diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts index 48ac4317e57..4ad82d599d3 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts @@ -182,6 +182,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { onSbomArtifactsLength: number = 0; stopBtnState: ClrLoadingState = ClrLoadingState.DEFAULT; updateArtifactSub: Subscription; + updateArtifactSbomSub: Subscription; hiddenArray: boolean[] = getHiddenArrayFromLocalStorage( PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT, @@ -255,6 +256,20 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { } ); } + if (!this.updateArtifactSbomSub) { + this.updateArtifactSbomSub = this.eventService.subscribe( + HarborEvent.UPDATE_SBOM_INFO, + (artifact: Artifact) => { + if (this.artifactList && this.artifactList.length) { + this.artifactList.forEach(item => { + if (item.digest === artifact.digest) { + this.updateArtifact(artifact, item); + } + }); + } + } + ); + } if (!this.deleteAccessorySub) { this.deleteAccessorySub = this.eventService.subscribe( HarborEvent.DELETE_ACCESSORY, @@ -984,22 +999,28 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { } this.refresh(); } + + updateArtifact(from: Artifact, to: Artifact) { + if (from.scan_overview) { + to.scan_overview = from.scan_overview; + } + if (from.sbom_overview) { + to.sbom_overview = from.sbom_overview; + } + if (from.sbom_overview.sbom_digest) { + to.sbomDigest = from.sbom_overview.sbom_digest; + } + if (from.accessories !== undefined && from.accessories.length > 0) { + to.accessories = from.accessories; + } + } + // when finished, remove it from selectedRow scanFinished(artifact: Artifact) { if (this.selectedRow && this.selectedRow.length) { for (let i = 0; i < this.selectedRow.length; i++) { if (artifact.digest === this.selectedRow[i].digest) { - if (artifact.sbom_overview) { - this.selectedRow[i].sbom_overview = - artifact.sbom_overview; - } - if (artifact.sbom_overview.sbom_digest) { - this.selectedRow[i].sbomDigest = - artifact.sbom_overview.sbom_digest; - } - if (artifact.accessories !== undefined) { - this.selectedRow[i].accessories = artifact.accessories; - } + this.updateArtifact(artifact, this.selectedRow[i]); this.selectedRow.splice(i, 1); break; } diff --git a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.spec.ts b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.spec.ts index 28dbbc6fb4e..34c17cf3510 100644 --- a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.spec.ts +++ b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.spec.ts @@ -173,19 +173,22 @@ describe('ResultSbomComponent (inline template)', () => { }); it('should show summary bar chart if status is COMPLETED', () => { + component.sbomOverview = { ...mockedSbomOverview }; component.sbomOverview.scan_status = SBOM_SCAN_STATUS.SUCCESS; + component.sbomOverview.sbom_digest = mockedSbomDigest; component.artifactDigest = mockedSbomDigest; component.sbomDigest = mockedSbomDigest; component.accessories = mockedAccessories; fixture.whenStable().then(() => { + fixture.detectChanges(); const el: HTMLElement = fixture.nativeElement.querySelector('.tip-block'); expect(el).not.toBeNull(); - const textContent = el.textContent; + const textContent = el?.textContent; expect(component.sbomOverview.scan_status).toBe( SBOM_SCAN_STATUS.SUCCESS ); - expect(textContent).toBe('SBOM Detail'); + expect(textContent?.trim()).toBe('SBOM.Details'); }); }); it('Test ResultSbomComponent getScanner', () => { diff --git a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.ts b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.ts index 61c70743fac..15f0c5c358e 100644 --- a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-scan.component.ts @@ -221,6 +221,7 @@ export class ResultSbomComponent implements OnInit, OnDestroy { repositoryName: dbEncodeURIComponent(this.repoName), reference: this.artifactDigest, withSbomOverview: true, + withAccessory: true, XAcceptVulnerabilities: DEFAULT_SUPPORTED_MIME_TYPES, }) .subscribe( diff --git a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.html b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.html index 957146acb24..8f35d8b89cd 100644 --- a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.html +++ b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.html @@ -1,10 +1,10 @@ -
+
{{ 'SBOM.Details' | translate }}
+ class="tip-wrapper bar-block-none shadow-none width-120"> {{ 'SBOM.NO_SBOM' | translate }}
- {{ 'SBOM.COMPLETED,' | translate }} + class="tip-wrapper width-120"> + {{ 'SBOM.COMPLETED' | translate }}
div{ diff --git a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.ts b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.ts index 72a51e3f40a..e19a4dc6635 100644 --- a/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/sbom-scanning/sbom-tip-histogram/sbom-tip-histogram.component.ts @@ -79,11 +79,11 @@ export class SbomTipHistogramComponent { } showSbomDetailLink(): boolean { - return this.sbomDigest && this.getSbomAccessories.length > 0; + return this.sbomDigest && this.getSbomAccessories().length > 0; } showNoSbom(): boolean { - return !this.sbomDigest && this.getSbomAccessories.length === 0; + return !this.sbomDigest && this.getSbomAccessories().length === 0; } isThemeLight() {