Merge pull request #10842 from jwangyangls/fix-artifact-function-detail

Fix some detail function
This commit is contained in:
Wenkai Yin(尹文开) 2020-02-26 13:30:39 +08:00 committed by GitHub
commit 0cda58b1b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 105 additions and 154 deletions

View File

@ -71,7 +71,7 @@
[(clrDgSelected)]="selectedRow">
<clr-dg-action-bar>
<button [clrLoading]="scanBtnState" type="button" class="btn btn-secondary scan-btn"
[disabled]="!(canScanNow() && selectedRow.length==1 && hasEnabledScanner && !referArtifactArray.length)" (click)="scanNow()">
[disabled]="!(canScanNow() && selectedRow.length==1 && hasEnabledScanner && !depth)" (click)="scanNow()">
<clr-icon shape="shield-check" size="16"></clr-icon>&nbsp;{{'VULNERABILITY.SCAN_NOW' | translate}}
</button>
@ -82,11 +82,11 @@
</span>
<clr-dropdown-menu class="action-dropdown" clrPosition="bottom-left" *clrIfOpen>
<div class="action-dropdown-item" aria-label="copy digest" clrDropdownItem
[clrDisabled]="!(selectedRow.length==1&& !referArtifactArray.length)" (click)="showDigestId()">
[clrDisabled]="!(selectedRow.length==1&& !depth)" (click)="showDigestId()">
{{'REPOSITORY.COPY_DIGEST_ID' | translate}}</div>
<clr-dropdown *ngIf="!withAdmiral">
<button class="action-dropdown-item" clrDropdownTrigger
[disabled]="!(selectedRow.length==1)||!hasAddLabelImagePermission ||referArtifactArray.length"
[disabled]="!(selectedRow.length==1)||!hasAddLabelImagePermission ||depth"
(click)="addLabels()">
{{'REPOSITORY.ADD_LABELS' | translate}}
</button>
@ -116,10 +116,10 @@
</clr-dropdown-menu>
</clr-dropdown>
<div class="action-dropdown-item" aria-label="retag" *ngIf="!withAdmiral"
[clrDisabled]="!(selectedRow.length===1)|| !hasRetagImagePermission||referArtifactArray.length" (click)="retag()"
[clrDisabled]="!(selectedRow.length===1)|| !hasRetagImagePermission||depth" (click)="retag()"
clrDropdownItem>{{'REPOSITORY.RETAG' | translate}}</div>
<div class="action-dropdown-item" clrDropdownItem *ngIf="hasDeleteImagePermission"
(click)="deleteArtifact()" id="artifact-list-delete" [clrDisabled]="!hasDeleteImagePermission||!selectedRow.length || referArtifactArray.length">
(click)="deleteArtifact()" id="artifact-list-delete" [clrDisabled]="!hasDeleteImagePermission||!selectedRow.length || depth">
{{'REPOSITORY.DELETE' | translate}}</div>
</clr-dropdown-menu>
</clr-dropdown>
@ -128,14 +128,12 @@
<clr-dg-column class="flex-max-width" [clrDgField]="'q'">{{'REPOSITORY.ARTIFACTS_COUNT' | translate}}
</clr-dg-column>
<clr-dg-column *ngIf="referArtifactArray.length">{{'REPOSITORY.PLATFORM' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="depth">{{'REPOSITORY.PLATFORM' | translate}}</clr-dg-column>
<clr-dg-column class="w-rem-4">{{'REPOSITORY.TAGS_COUNT' | translate}}</clr-dg-column>
<clr-dg-column >{{'REPOSITORY.SIZE' | translate}}</clr-dg-column>
<!-- <clr-dg-column>{{'REPOSITORY.PULL_COMMAND' | translate}}</clr-dg-column> -->
<clr-dg-column>{{'REPOSITORY.VULNERABILITY' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="withNotary">{{'REPOSITORY.SIGNED' | translate}}</clr-dg-column>
<!-- <clr-dg-column>{{'REPOSITORY.AUTHOR' | translate}}</clr-dg-column> -->
<clr-dg-column>{{'ARTIFACT.ANNOTATION' | translate}}</clr-dg-column>
<clr-dg-column *ngIf="!withAdmiral">{{'REPOSITORY.LABELS' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="pushComparator">{{'REPOSITORY.PUSH_TIME' | translate}}</clr-dg-column>
<clr-dg-column [clrDgSortBy]="pullComparator">{{'REPOSITORY.PULL_TIME' | translate}}</clr-dg-column>
@ -166,7 +164,7 @@
</span>
</div>
</clr-dg-cell>
<clr-dg-cell *ngIf="referArtifactArray.length">
<clr-dg-cell *ngIf="depth">
<div class="cell">
{{artifact.extra_attrs?.os}}/{{artifact.extra_attrs?.architecture}}
</div>
@ -243,11 +241,27 @@
</a>
</div>
</clr-dg-cell>
<!-- <clr-dg-cell class="truncated" title="{{artifact.author}}">
<div class="cell">
{{artifact.author}}
<clr-dg-cell>
<div class="cell" *ngIf="artifact.annotationsArray?.length">
<div class="bar-state">
<span class="label not-scan">{{artifact.annotationsArray[0]}}</span>
</div>
<div class="signpost-item" [hidden]="artifact.annotationsArray?.length<=1">
<div class="trigger-item">
<clr-signpost>
<button class="btn btn-link" clrSignpostTrigger>...</button>
<clr-signpost-content [clrPosition]="'left-top'" *clrIfOpen>
<div>
<div *ngFor="let attr of artifact.annotationsArray" class="bar-state">
<span class="label not-scan">{{attr}}</span>
</div>
</div>
</clr-signpost-content>
</clr-signpost>
</div>
</div>
</div>
</clr-dg-cell> -->
</clr-dg-cell>
<clr-dg-cell *ngIf="!withAdmiral">
<div class="cell">
<hbr-label-piece *ngIf="artifact.labels?.length" [label]="artifact.labels[0]" [labelWidth]="90">

View File

@ -22,7 +22,7 @@ import {
UserPermissionService,
USERSTATICPERMISSION
} from "../../../../../../lib/services";
import { Artifact, Reference } from "../../../artifact/artifact";
import { ArtifactFront as Artifact } from "../../../artifact/artifact";
import { IServiceConfig, SERVICE_CONFIG } from "../../../../../../lib/entities/service.config";
import { SharedModule } from "../../../../../../lib/utils/shared/shared.module";
import { LabelPieceComponent } from "../../../../../../lib/components/label-piece/label-piece.component";
@ -82,21 +82,19 @@ describe("ArtifactListTabComponent (inline template)", () => {
{
"id": 1,
type: 'image',
repository: "goharbor/harbor-portal",
tags: [{
id: '1',
id: 1,
name: 'tag1',
artifact_id: 1,
upload_time: '2020-01-06T09:40:08.036866579Z',
artifact_id: 1
},
{
id: '2',
id: 2,
name: 'tag2',
artifact_id: 2,
pull_time: '2020-01-06T09:40:08.036866579Z',
push_time: '2020-01-06T09:40:08.036866579Z',
},],
references: [new Reference(1), new Reference(2)],
}],
references: [],
media_type: 'string',
"digest": "sha256:4875cda368906fd670c9629b5e416ab3d6c0292015f3c3f12ef37dc9a32fc8d4",
"size": 20372934,
@ -141,22 +139,20 @@ describe("ArtifactListTabComponent (inline template)", () => {
{
"id": 1,
type: 'image',
repository: "goharbor/harbor-portal",
tags: [{
id: '1',
id: 1,
name: 'tag1',
artifact_id: 1,
upload_time: '2020-01-06T09:40:08.036866579Z',
artifact_id: 1
},
{
id: '2',
id: 2,
name: 'tag2',
artifact_id: 2,
pull_time: '2020-01-06T09:40:08.036866579Z',
push_time: '2020-01-06T09:40:08.036866579Z',
}
],
references: [new Reference(1), new Reference(2)],
references: [],
media_type: 'string',
"digest": "sha256:3e33e3e3",
"size": 20372934,

View File

@ -61,7 +61,7 @@ import {
} from "../../../../../../lib/entities/shared.const";
import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate";
import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils";
import { Artifact } from "../../../artifact/artifact";
import { ArtifactFront as Artifact } from "../../../artifact/artifact";
import { Project } from "../../../../project";
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
export interface LabelState {
@ -82,7 +82,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
projectName: string;
@Input() memberRoleID: number;
@Input() repoName: string;
referArtifactArray: string[] = [];
@Input() isEmbedded: boolean;
@Input() hasSignedIn: boolean;
@Input() isGuest: boolean;
@ -373,6 +372,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
this.loading = false;
})).subscribe(artifacts => {
this.artifactList = artifacts;
this.getArtifactAnnotationsArray(this.artifactList);
}, error => {
this.errorHandlerService.error(error);
});
@ -391,6 +391,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
}
}
this.artifactList = res.body;
this.getArtifactAnnotationsArray(this.artifactList);
}, error => {
// error
this.errorHandlerService.error(error);
@ -401,7 +402,21 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
refresh() {
this.doSearchArtifactNames("");
}
getArtifactAnnotationsArray(artifactList: Artifact[]) {
artifactList.forEach(artifact => {
artifact.annotationsArray = [];
if (artifact.annotations) {
for (const key in artifact.annotations) {
if (artifact.annotations.hasOwnProperty(key)) {
const annotation = artifact.annotations[key];
artifact.annotationsArray.push(`${key} : ${annotation}`);
}
}
// todo : cannot support Object.entries
// artifact.annotationsArray = Object.entries(artifact.annotations).map(item => `${item[0]} : ${item[1]}`);
}
});
}
getAllLabels(): void {
forkJoin(this.labelService.getGLabels(), this.labelService.getPLabels(this.projectId)).subscribe(results => {
results.forEach(labels => {

View File

@ -85,7 +85,8 @@ describe('ArtifactListComponent (inline template)', () => {
}
];
let newRepositoryService = {
updateRepository: () => of(null)
updateRepository: () => of(null),
getRepository: () => of({description: ''})
};
let mockRepo: Repository = {
metadata: { xTotalCount: 2 },

View File

@ -118,12 +118,14 @@ export class ArtifactListComponent implements OnInit {
}
retrieve(state?: State) {
this.repositoryService.getRepositories(this.projectId, this.repoName)
let params: NewRepositoryService.GetRepositoryParams = {
projectName: this.projectName,
repositoryName: this.repoName
};
this.newRepositoryService.getRepository(params)
.subscribe(response => {
if (response.metadata.xTotalCount > 0) {
this.orgImageInfo = response.data[0].description;
this.imageInfo = response.data[0].description;
}
this.orgImageInfo = response.description;
this.imageInfo = response.description;
}, error => this.errorHandler.error(error));
this.systemInfoService.getSystemInfo()
.subscribe(systemInfo => this.systemInfo = systemInfo, error => this.errorHandler.error(error));

View File

@ -1,5 +1,5 @@
<ng-container *ngIf="hasCommonProperties()">
<h4 class="margin-bottom-075">{{'ARTIFACT.COMMON_PROPERTIES' | translate}}</h4>
<h4 class="margin-bottom-075">{{'ARTIFACT.EXTRA_PROPERTIES' | translate}}</h4>
<clr-stack-view>
<clr-stack-block [clrSbExpanded] = "true">
<clr-stack-label>{{'ARTIFACT.COMMON_ALL' | translate}}</clr-stack-label>

View File

@ -33,30 +33,7 @@ export class ArtifactCommonPropertiesComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges) {
if (changes && changes["artifactDetails"]) {
if (this.artifactDetails) {
if (this.artifactDetails.type) {
this.commonProperties[Types.TYPE] = this.artifactDetails.type;
}
if (this.artifactDetails.media_type) {
this.commonProperties[Types.MEDIA_TYPE] = this.artifactDetails.media_type;
}
if (this.artifactDetails.manifest_media_type) {
this.commonProperties[Types.MANIFEST_MEDIA_TYPE] = this.artifactDetails.manifest_media_type;
}
if (this.artifactDetails.digest) {
this.commonProperties[Types.DIGEST] = this.artifactDetails.digest;
}
if (this.artifactDetails.size) {
this.commonProperties[Types.SIZE] = formatSize(this.artifactDetails.size.toString());
}
if (this.artifactDetails.push_time) {
this.commonProperties[Types.PUSH_TIME] = new DatePipe(this.translate.currentLang)
.transform(this.artifactDetails.push_time, 'short');
}
if (this.artifactDetails.pull_time) {
this.commonProperties[Types.PULL_TIME] = new DatePipe(this.translate.currentLang)
.transform(this.artifactDetails.pull_time, 'short');
}
Object.assign(this.commonProperties, this.artifactDetails.extra_attrs, this.artifactDetails.annotations);
Object.assign(this.commonProperties, this.artifactDetails.extra_attrs);
for (let name in this.commonProperties) {
if (this.commonProperties.hasOwnProperty(name)) {
if (this.commonProperties[name] && this.commonProperties[name] instanceof Object) {

View File

@ -18,7 +18,7 @@
</div>
</div>
<ng-container *ngIf="!loading">
<!-- common properties -->
<!-- Extra Attributes -->
<artifact-common-properties [artifactDetails]="artifact"></artifact-common-properties>
<!-- tags -->

View File

@ -7,17 +7,19 @@
<button type="button" class="btn btn-secondary" [disabled]="!(selectedRow.length>=1)" (click)="removeTag()">
<clr-icon shape="trash" size="16"></clr-icon>&nbsp;{{'TAG.REMOVE_TAG' | translate}}
</button>
<form #labelForm="ngForm" [hidden]="!newTagformShow" class="label-form stack-block-label">
<form #tagForm="ngForm" [hidden]="!newTagformShow" class="label-form stack-block-label">
<section>
<label>
<label for="name">{{'TAG.NAME' | translate}}</label>
<label class="clr-control-container" [class.clr-error]="isTagNameExist">
<label class="clr-control-container" [class.clr-error]="isTagNameExist || name.hasError('pattern')">
<input clrInput type="text" id="name" name="name" required size="20" autocomplete="off"
[(ngModel)]="newTagName.name" #name="ngModel" (keyup)="existValid(newTagName.name)">
[(ngModel)]="newTagName.name" #name="ngModel" pattern="^[\w][\w.-]{0,127}$" (keyup)="existValid(newTagName.name)">
<clr-control-error class="position-ab" *ngIf="isTagNameExist">
{{'LABEL.NAME_ALREADY_EXISTS' | translate }}
</clr-control-error>
<clr-control-error class="position-ab" *ngIf="name.hasError('pattern')">
{{'RETAG.TIP_TAG' | translate }}
</clr-control-error>
</label>
</label>
<label>
@ -25,7 +27,7 @@
'BUTTON.CANCEL' | translate }}
</button>
<button type="submit" class="btn btn-sm btn-primary" (click)="saveAddTag()"
[disabled]="isTagNameExist || !newTagName.name">{{
[disabled]="isTagNameExist || !newTagName.name ||tagForm.invalid">{{
'BUTTON.OK' | translate }}
</button>
</label>

View File

@ -15,7 +15,7 @@ import { ErrorHandler } from "../../../../../lib/utils/error-handler";
import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from "../../../../../lib/entities/shared.const";
import { operateChanges, OperateInfo, OperationState } from "../../../../../lib/components/operation/operate";
import { errorHandler } from "../../../../../lib/utils/shared/shared.utils";
import { Artifact } from "../artifact";
import { ArtifactFront as Artifact } from "../artifact";
class InitTag {
name = "";

View File

@ -9,7 +9,7 @@ import {
HTTP_GET_OPTIONS,
HTTP_JSON_OPTIONS
} from "../../../../lib/utils/utils";
import { Artifact } from "./artifact";
import { ArtifactFront as Artifact } from "./artifact";
/**

View File

@ -1,59 +1,6 @@
import { Label, Tag } from "../../../../lib/services";
import { Artifact } from "../../../../../ng-swagger-gen/models/artifact";
export interface ArtifactFront extends Artifact {
annotationsArray?: string[];
}
export class Artifact {
id: number;
type: string;
repository: string;
tags: Tag[];
media_type: string;
digest: string;
size: number;
upload_time?: string;
// labels: string[];
extra_attrs?: Map<string, string>;
addition_links?: Map<string, string>;
references: Reference[];
scan_overview: any;
labels: Label[];
push_time: string;
pull_time: string;
isOpen?: boolean; // front
referenceIndexOpenState?: boolean; // front
referenceDigestOpenState?: boolean; // front
hasReferenceArtifactList?: Artifact[] = []; // front
noReferenceArtifactList?: Artifact[] = []; // front
constructor(digestName, hasReference?) {
this.id = 1;
this.type = 'type';
this.size = 1111111111;
this.upload_time = '2020-01-06T09:40:08.036866579Z';
this.digest = digestName;
this.tags = [
{
id: '1',
artifact_id: 1,
name: 'tag1',
upload_time: '2020-01-06T09:40:08.036866579Z'
},
{
id: '2',
artifact_id: 2,
name: 'tag2',
upload_time: '2020-01-06T09:40:08.036866579Z',
},
];
// tslint:disable-next-line: no-use-before-declare
// this.references = [];
this.references = hasReference ? [new Reference(1), new Reference(2)] : [];
}
}
export class Reference {
child_id: number;
child_digest: string;
parent_id: number;
platform?: any; // json
constructor(artifact_id) {
this.child_id = artifact_id;
}
}

View File

@ -139,10 +139,6 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
this.projectName = pro.name;
}
this.hasSignedIn = this.session.getCurrentUser() !== null;
// Get system info for tag views
this.getSystemInfo();
this.isCardView = this.mode === "admiral";
@ -227,7 +223,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
this.operationService.publishInfo(operMessage);
return this.newRepoService
.deleteRepository({
repositoryName: repo.name,
repositoryName: repo.name.split('/')[1],
projectName: this.projectName
})
.pipe(map(

View File

@ -11,14 +11,9 @@ import { ScannerVo, ScanningResultService, VulnerabilitySummary } from "../../..
import { ArtifactDefaultService } from "../artifact/artifact.service";
import { ErrorHandler } from "../../../../lib/utils/error-handler";
import { ChannelService } from "../../../../lib/services/channel.service";
import {
clone,
CURRENT_BASE_HREF,
DEFAULT_SUPPORTED_MIME_TYPE,
VULNERABILITY_SCAN_STATUS
} from "../../../../lib/utils/utils";
import { Artifact } from "../artifact/artifact";
import { clone, CURRENT_BASE_HREF, DEFAULT_SUPPORTED_MIME_TYPE, VULNERABILITY_SCAN_STATUS } from "../../../../lib/utils/utils";
import { ArtifactFront as Artifact } from "../artifact/artifact";
import { NativeReportSummary } from '../../../../../ng-swagger-gen/models/native-report-summary';
const STATE_CHECK_INTERVAL: number = 3000; // 3s
const RETRY_TIMES: number = 3;
@ -186,7 +181,7 @@ export class ResultBarChartComponent implements OnInit, OnDestroy {
});
}
copyValue(newVal: VulnerabilitySummary): void {
copyValue(newVal: NativeReportSummary): void {
if (!this.summary || !newVal || !newVal.scan_status) { return; }
this.summary = clone(newVal);
}

View File

@ -996,8 +996,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"COMMON_PROPERTIES": "Common Properties",
"COMMON_ALL": "Common properties across all digest"
"ANNOTATION": "Annotation",
"EXTRA_PROPERTIES": "Extra Attributes",
"COMMON_ALL": "Extra Attributes across all digest"
},
"TAG": {
"CREATION_TIME_PREFIX": "Create on",

View File

@ -995,8 +995,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"COMMON_PROPERTIES": "Common Properties",
"COMMON_ALL": "Common properties across all digest"
"ANNOTATION": "Annotation",
"EXTRA_PROPERTIES": "Extra Attributes",
"COMMON_ALL": "Extra Attributes across all digest"
},
"TAG": {
"CREATION_TIME_PREFIX": "Create on",

View File

@ -968,8 +968,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"COMMON_PROPERTIES": "Common Properties",
"COMMON_ALL": "Common properties across all digest"
"ANNOTATION": "Annotation",
"EXTRA_PROPERTIES": "Extra Attributes",
"COMMON_ALL": "Extra Attributes across all digest"
},
"TAG": {
"CREATION_TIME_PREFIX": "Créer le",

View File

@ -991,8 +991,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"COMMON_PROPERTIES": "Common Properties",
"COMMON_ALL": "Common properties across all digest"
"ANNOTATION": "Annotation",
"EXTRA_PROPERTIES": "Extra Attributes",
"COMMON_ALL": "Extra Attributes across all digest"
},
"TAG": {
"CREATION_TIME_PREFIX": "Criado em",

View File

@ -995,8 +995,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "Additions",
"COMMON_PROPERTIES": "Common Properties",
"COMMON_ALL": "Common properties across all digest"
"ANNOTATION": "Annotation",
"EXTRA_PROPERTIES": "Extra Attributes",
"COMMON_ALL": "Extra Attributes across all digest"
},
"TAG": {
"CREATION_TIME_PREFIX": "Oluştur",

View File

@ -995,8 +995,9 @@
"ARTIFACT": {
"FILTER_FOR_ARTIFACTS": "Filter Artifacts",
"ADDITIONS": "其他",
"COMMON_PROPERTIES": "属性",
"COMMON_ALL": "公共属性"
"ANNOTATION": "注解",
"EXTRA_PROPERTIES": "额外属性",
"COMMON_ALL": "额外属性"
},
"TAG": {
"CREATION_TIME_PREFIX": "创建时间:",

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { Subject } from "rxjs";
import { Artifact } from "../../app/project/repository/artifact/artifact";
import { ArtifactFront as Artifact } from "../../app/project/repository/artifact/artifact";
@Injectable()
export class ChannelService {