mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
[Fixed] Fix bug for 2.0 and add case for trivy
Signed-off-by: Yogi_Wang <yawang@vmware.com> 1.add case for trivy 2.vunerbility refresh bug 3.scan mutiple artifact 4.fix global search bug 5.disable delete tag btn when remove immutable tag 6.cancel selectRow when add label or remove label;fix #11195 7.fix cron tootip
This commit is contained in:
parent
d05817c8a2
commit
cba4490a5a
@ -91,7 +91,7 @@
|
||||
[(clrDgSelected)]="selectedRow">
|
||||
<clr-dg-action-bar>
|
||||
<button [clrLoading]="scanBtnState" type="button" class="btn btn-secondary scan-btn"
|
||||
[disabled]="!(canScanNow() && selectedRowHasVul() && selectedRow.length==1 && hasEnabledScanner && hasScanImagePermission )" (click)="scanNow()">
|
||||
[disabled]="!(canScanNow() && selectedRowHasVul() && hasEnabledScanner && hasScanImagePermission )" (click)="scanNow()">
|
||||
<clr-icon shape="shield-check" size="16"></clr-icon> {{'VULNERABILITY.SCAN_NOW' | translate}}
|
||||
</button>
|
||||
|
||||
@ -110,7 +110,7 @@
|
||||
(click)="addLabels()">
|
||||
{{'REPOSITORY.ADD_LABELS' | translate}}
|
||||
</button>
|
||||
<clr-dropdown-menu>
|
||||
<clr-dropdown-menu [hidden]="!selectedRow.length">
|
||||
<div class="filter-grid">
|
||||
<label
|
||||
class="dropdown-header">{{'REPOSITORY.ADD_LABEL_TO_IMAGE' | translate}}</label>
|
||||
@ -208,17 +208,17 @@
|
||||
<tr>
|
||||
<th class="left tag-header-color">
|
||||
{{'REPOSITORY.TAGS_COUNT' | translate | uppercase}}</th>
|
||||
<th class="left tag-header-color">
|
||||
{{'REPOSITORY.PUSH_TIME' | translate | uppercase}}</th>
|
||||
<th class="left tag-header-color">
|
||||
{{'REPOSITORY.PULL_TIME' | translate | uppercase}}</th>
|
||||
<th class="left tag-header-color">
|
||||
{{'REPOSITORY.PUSH_TIME' | translate | uppercase}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="tag-tbody">
|
||||
<tr class="tag-tr" *ngFor="let tag of artifact.tags">
|
||||
<td class="left tag-body-color">{{tag.name}}</td>
|
||||
<td class="left tag-body-color">{{tag.pull_time === availableTime ? '':(tag.pull_time | date: 'short')}}</td>
|
||||
<td class="left tag-body-color">{{tag.push_time | date: 'short'}}</td>
|
||||
<td class="left tag-body-color">{{tag.pull_time | date: 'short'}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -162,6 +162,10 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
openSelectFilterPiece = false;
|
||||
// could Pagination filter
|
||||
filters: string[];
|
||||
|
||||
scanFiinishArtifactLength: number = 0;
|
||||
onScanArtifactsLength: number = 0;
|
||||
|
||||
constructor(
|
||||
private errorHandlerService: ErrorHandler,
|
||||
private userPermissionService: UserPermissionService,
|
||||
@ -731,6 +735,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
forkJoin(...this.deleteArtifactobservableLists).subscribe((deleteResult) => {
|
||||
let deleteSuccessList = [];
|
||||
let deleteErrorList = [];
|
||||
this.deleteArtifactobservableLists = [];
|
||||
deleteResult.forEach(result => {
|
||||
if (!result) {
|
||||
// delete success
|
||||
@ -739,9 +744,9 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
deleteErrorList.push(result);
|
||||
}
|
||||
});
|
||||
this.selectedRow = [];
|
||||
if (deleteSuccessList.length === deleteResult.length) {
|
||||
// all is success
|
||||
this.selectedRow = [];
|
||||
let st: ClrDatagridStateInterface = { page: {from: 0, to: this.pageSize - 1, size: this.pageSize} };
|
||||
this.clrLoad(st);
|
||||
} else if (deleteErrorList.length === deleteResult.length) {
|
||||
@ -752,7 +757,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
// some artifact delete success but it has error delete things
|
||||
this.errorHandlerService.error(deleteErrorList[deleteErrorList.length - 1].error);
|
||||
// if delete one success refresh list
|
||||
this.selectedRow = [];
|
||||
let st: ClrDatagridStateInterface = { page: {from: 0, to: this.pageSize - 1, size: this.pageSize} };
|
||||
this.clrLoad(st);
|
||||
}
|
||||
@ -871,10 +875,16 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
// Trigger scan
|
||||
scanNow(): void {
|
||||
if (this.selectedRow && this.selectedRow.length === 1) {
|
||||
this.onSendingScanCommand = true;
|
||||
this.channel.publishScanEvent(this.repoName + "/" + this.selectedRow[0].digest);
|
||||
if (!this.selectedRow.length) {
|
||||
return;
|
||||
}
|
||||
this.scanFiinishArtifactLength = 0;
|
||||
this.onScanArtifactsLength = this.selectedRow.length;
|
||||
this.onSendingScanCommand = true;
|
||||
this.selectedRow.forEach((data: any) => {
|
||||
let digest = data.digest;
|
||||
this.channel.publishScanEvent(this.repoName + "/" + digest);
|
||||
});
|
||||
}
|
||||
selectedRowHasVul(): boolean {
|
||||
return !!(this.selectedRow
|
||||
@ -886,7 +896,11 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
return !!(artifact && artifact.addition_links && artifact.addition_links[ADDITIONS.VULNERABILITIES]);
|
||||
}
|
||||
submitFinish(e: boolean) {
|
||||
this.onSendingScanCommand = e;
|
||||
this.scanFiinishArtifactLength += 1;
|
||||
// all selected scan action has start
|
||||
if (this.scanFiinishArtifactLength === this.onScanArtifactsLength) {
|
||||
this.onSendingScanCommand = e;
|
||||
}
|
||||
}
|
||||
// pull command
|
||||
onCpError($event: any): void {
|
||||
|
@ -91,7 +91,10 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
||||
this.hasShowLoading = true;
|
||||
}
|
||||
this.additionsService.getDetailByLink(this.vulnerabilitiesLink.href)
|
||||
.pipe(finalize(() => this.loading = false))
|
||||
.pipe(finalize(() => {
|
||||
this.loading = false;
|
||||
this.hasShowLoading = false;
|
||||
}))
|
||||
.subscribe(
|
||||
res => {
|
||||
this.scan_overview = res;
|
||||
|
@ -22,7 +22,7 @@
|
||||
<artifact-common-properties [artifactDetails]="artifact"></artifact-common-properties>
|
||||
|
||||
<!-- tags -->
|
||||
<artifact-tag [artifactDetails]="artifact" [projectName]="projectName" [repositoryName]="repositoryName"
|
||||
<artifact-tag [artifactDetails]="artifact" [projectName]="projectName" [projectId]="projectId" [repositoryName]="repositoryName"
|
||||
(refreshArtifact)="refreshArtifact()"></artifact-tag>
|
||||
|
||||
<!-- Additions -->
|
||||
|
@ -4,7 +4,7 @@
|
||||
<button type="button" class="btn btn-secondary" (click)="addTag()">
|
||||
<clr-icon shape="plus" size="16"></clr-icon> {{'TAG.ADD_TAG' | translate}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" [disabled]="!(selectedRow.length>=1)" (click)="removeTag()">
|
||||
<button type="button" class="btn btn-secondary" [disabled]="!(selectedRow.length>=1&& !hasImmutableOnTag() && hasDeleteTagPermission)" (click)="removeTag()">
|
||||
<clr-icon shape="trash" size="16"></clr-icon> {{'TAG.REMOVE_TAG' | translate}}
|
||||
</button>
|
||||
<form #tagForm="ngForm" [hidden]="!newTagformShow" class="label-form stack-block-label">
|
||||
@ -46,7 +46,7 @@
|
||||
<span *ngIf="tag.immutable" class="label label-info ml-8">{{'REPOSITORY.IMMUTABLE' | translate}}</span>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell [ngSwitch]="tag.signature != null">
|
||||
<clr-dg-cell [ngSwitch]="tag.signed">
|
||||
<div class="cell">
|
||||
<clr-icon shape="check-circle" *ngSwitchCase="true" size="20" class="color-green"></clr-icon>
|
||||
<clr-icon shape="times-circle" *ngSwitchCase="false" size="16" class="color-red"></clr-icon>
|
||||
|
@ -10,6 +10,7 @@ import { ErrorHandler } from "../../../../../lib/utils/error-handler";
|
||||
import { ArtifactService } from '../../../../../../ng-swagger-gen/services/artifact.service';
|
||||
import { OperationService } from "../../../../../lib/components/operation/operation.service";
|
||||
import { CURRENT_BASE_HREF } from "../../../../../lib/utils/utils";
|
||||
import { USERSTATICPERMISSION, UserPermissionService, UserPermissionDefaultService } from '../../../../../lib/services';
|
||||
|
||||
|
||||
describe('ArtifactTagComponent', () => {
|
||||
@ -25,6 +26,11 @@ describe('ArtifactTagComponent', () => {
|
||||
const config: IServiceConfig = {
|
||||
repositoryBaseEndpoint: CURRENT_BASE_HREF + "/repositories/testing"
|
||||
};
|
||||
let userPermissionService;
|
||||
const permissions = [
|
||||
{ resource: USERSTATICPERMISSION.REPOSITORY_TAG.KEY, action: USERSTATICPERMISSION.REPOSITORY_TAG.VALUE.DELETE },
|
||||
];
|
||||
let mockHasDeleteImagePermission: boolean = true;
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
@ -41,6 +47,7 @@ describe('ArtifactTagComponent', () => {
|
||||
{ provide: SERVICE_CONFIG, useValue: config },
|
||||
{ provide: mockErrorHandler, useValue: ErrorHandler },
|
||||
{ provide: ArtifactService, useValue: mockArtifactService },
|
||||
{ provide: UserPermissionService, useClass: UserPermissionDefaultService },
|
||||
{ provide: OperationService },
|
||||
]
|
||||
})
|
||||
@ -50,6 +57,11 @@ describe('ArtifactTagComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ArtifactTagComponent);
|
||||
component = fixture.componentInstance;
|
||||
userPermissionService = fixture.debugElement.injector.get(UserPermissionService);
|
||||
spyOn(userPermissionService, "hasProjectPermissions")
|
||||
.withArgs(component.projectId, permissions)
|
||||
.and.returnValue(of([
|
||||
mockHasDeleteImagePermission]));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@ -17,7 +17,10 @@ import { errorHandler } from "../../../../../lib/utils/shared/shared.utils";
|
||||
import { ArtifactFront as Artifact } from "../artifact";
|
||||
import { ArtifactService } from '../../../../../../ng-swagger-gen/services/artifact.service';
|
||||
import { Tag } from '../../../../../../ng-swagger-gen/models/tag';
|
||||
import {
|
||||
|
||||
UserPermissionService, USERSTATICPERMISSION
|
||||
} from "../../../../../lib/services";
|
||||
class InitTag {
|
||||
name = "";
|
||||
}
|
||||
@ -30,6 +33,7 @@ class InitTag {
|
||||
export class ArtifactTagComponent implements OnInit {
|
||||
@Input() artifactDetails: Artifact;
|
||||
@Input() projectName: string;
|
||||
@Input() projectId: number;
|
||||
@Input() repositoryName: string;
|
||||
@Output() refreshArtifact = new EventEmitter();
|
||||
newTagName = new InitTag();
|
||||
@ -43,15 +47,25 @@ export class ArtifactTagComponent implements OnInit {
|
||||
availableTime = AVAILABLE_TIME;
|
||||
@ViewChild("confirmationDialog", { static: false })
|
||||
confirmationDialog: ConfirmationDialogComponent;
|
||||
hasDeleteTagPermission: boolean;
|
||||
constructor(
|
||||
private operationService: OperationService,
|
||||
private artifactService: ArtifactService,
|
||||
private translateService: TranslateService,
|
||||
private userPermissionService: UserPermissionService,
|
||||
private errorHandlerService: ErrorHandler
|
||||
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.getImagePermissionRule(this.projectId);
|
||||
}
|
||||
getImagePermissionRule(projectId: number): void {
|
||||
const permissions = [
|
||||
{ resource: USERSTATICPERMISSION.REPOSITORY_TAG.KEY, action: USERSTATICPERMISSION.REPOSITORY_TAG.VALUE.DELETE }
|
||||
];
|
||||
this.userPermissionService.hasProjectPermissions(this.projectId, permissions).subscribe((results: Array<boolean>) => {
|
||||
this.hasDeleteTagPermission = results[0];
|
||||
}, error => this.errorHandlerService.error(error));
|
||||
}
|
||||
|
||||
addTag() {
|
||||
@ -166,4 +180,8 @@ export class ArtifactTagComponent implements OnInit {
|
||||
this.openTag = !this.openTag;
|
||||
this.newTagformShow = false;
|
||||
}
|
||||
hasImmutableOnTag(): boolean {
|
||||
return this.selectedRow.some((artifact) => artifact.immutable);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,8 +68,9 @@ export class ListRepositoryROComponent implements OnInit, OnDestroy {
|
||||
|
||||
public gotoLink(projectId: number, repoName: string): void {
|
||||
this.searchTrigger.closeSearch(true);
|
||||
|
||||
let linkUrl = ['harbor', 'tags', projectId, repoName];
|
||||
let projectName = repoName.split('/')[0];
|
||||
let repositorieName = projectName ? repoName.split(`${projectName}/`)[1] : repoName;
|
||||
let linkUrl = ['harbor', 'projects', projectId, 'repositories', repositorieName ];
|
||||
this.router.navigate(linkUrl);
|
||||
}
|
||||
|
||||
|
@ -693,7 +693,7 @@
|
||||
"ADD_LABEL_TO_IMAGE": "Add labels to this image",
|
||||
"FILTER_BY_LABEL": "Filter images by label",
|
||||
"FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label",
|
||||
"ADD_LABELS": "Add labels",
|
||||
"ADD_LABELS": "Add Labels",
|
||||
"RETAG": "Copy",
|
||||
"ACTION": "ACTION",
|
||||
"DEPLOY": "DEPLOY",
|
||||
|
@ -694,7 +694,7 @@
|
||||
"ADD_LABEL_TO_IMAGE": "Add labels to this image",
|
||||
"FILTER_BY_LABEL": "Filter images by label",
|
||||
"FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label",
|
||||
"ADD_LABELS": "Add labels",
|
||||
"ADD_LABELS": "Add Labels",
|
||||
"RETAG": "Copy",
|
||||
"ACTION": "ACTION",
|
||||
"DEPLOY": "DEPLOY",
|
||||
|
@ -680,7 +680,7 @@
|
||||
"ADD_LABEL_TO_IMAGE": "Add labels to this image",
|
||||
"FILTER_BY_LABEL": "Filter images by label",
|
||||
"FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label",
|
||||
"ADD_LABELS": "Add labels",
|
||||
"ADD_LABELS": "Add Labels",
|
||||
"RETAG": "Copy",
|
||||
"ACTION": "ACTION",
|
||||
"DEPLOY": "DEPLOY",
|
||||
|
@ -693,7 +693,7 @@
|
||||
"ADD_LABEL_TO_IMAGE": "Adicionar labels a essa imagem",
|
||||
"FILTER_BY_LABEL": "Filtrar imagens por label",
|
||||
"FILTER_ARTIFACT_BY_LABEL": "Filter actifact by label",
|
||||
"ADD_LABELS": "Adicionar labels",
|
||||
"ADD_LABELS": "Adicionar Labels",
|
||||
"RETAG": "Copy",
|
||||
"ACTION": "AÇÃO",
|
||||
"DEPLOY": "DEPLOY",
|
||||
|
@ -2,29 +2,33 @@
|
||||
<div class="normal-wrapper">
|
||||
<span [style.width]="buttonMarginLeft" class="font-style">{{ labelCurrent | translate }}</span>
|
||||
<span>{{(originScheduleType ? 'SCHEDULE.'+ originScheduleType.toUpperCase(): "") | translate}}</span>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.HOURLY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.HOURLY_CRON' | translate}}</span>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.HOURLY" href="javascript:void(0)" role="tooltip"
|
||||
aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.HOURLY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.WEEKLY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.WEEKLY_CRON' | translate}}</span>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.WEEKLY" href="javascript:void(0)" role="tooltip"
|
||||
aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.WEEKLY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.DAILY" href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.DAILY_CRON' | translate}}</span>
|
||||
<a [hidden]="originScheduleType!==SCHEDULE_TYPE.DAILY" href="javascript:void(0)" role="tooltip" aria-haspopup="true"
|
||||
class="tooltip tooltip-top-right">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<span class="tooltip-content">{{'CONFIG.TOOLTIP.DAILY_CRON' | translate}}</span>
|
||||
</a>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }} :</span>
|
||||
<span [hidden]="originScheduleType!==SCHEDULE_TYPE.CUSTOM">{{ oriCron }}</span>
|
||||
</div>
|
||||
<button [style.margin-left]="buttonMarginLeft" [disabled]="disabled" class="btn btn-primary " (click)="editSchedule()" id="editSchedule">
|
||||
<button [style.margin-left]="buttonMarginLeft" [disabled]="disabled" class="btn btn-primary " (click)="editSchedule()"
|
||||
id="editSchedule">
|
||||
{{ "BUTTON.EDIT" | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="setting-wrapper flex-layout" *ngIf="isEditMode">
|
||||
<span [style.width]="buttonMarginLeft" class="font-style">{{ labelEdit | translate }}</span>
|
||||
<div class="select select-schedule clr-select-wrapper">
|
||||
<select name="selectPolicy" id="selectPolicy" [(ngModel)]="scheduleType">
|
||||
<select name="selectPolicy" id="selectPolicy" [(ngModel)]="scheduleType">
|
||||
<option [value]="SCHEDULE_TYPE.NONE">{{'SCHEDULE.NONE' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.HOURLY">{{'SCHEDULE.HOURLY' | translate}}</option>
|
||||
<option [value]="SCHEDULE_TYPE.DAILY">{{'SCHEDULE.DAILY' | translate}}</option>
|
||||
@ -34,27 +38,26 @@
|
||||
</div>
|
||||
<span class="required" [hidden]="scheduleType!==SCHEDULE_TYPE.CUSTOM">{{ "SCHEDULE.CRON" | translate }}</span>
|
||||
<div [hidden]="scheduleType!==SCHEDULE_TYPE.CUSTOM" class="cron-input">
|
||||
<label for="targetCron" aria-haspopup="true" role="tooltip" [class.invalid]="dateInvalid" class="tooltip tooltip-validation tooltip-md tooltip-top-left cron-label">
|
||||
<input type="text" (blur)="blurInvalid()" (input)="inputInvalid()" name=targetCron id="targetCron" #cronStringInput="ngModel" required class="clr-input form-control"
|
||||
[(ngModel)]="cronString">
|
||||
<span class="tooltip-content" *ngIf="dateInvalid">
|
||||
{{'TOOLTIP.CRON_REQUIRED' | translate }}
|
||||
</span>
|
||||
<label for="targetCron" aria-haspopup="true" role="tooltip" [class.clr-error]="dateInvalid"
|
||||
class="tooltip tooltip-validation tooltip-md tooltip-top-left cron-label">
|
||||
<input type="text" (blur)="blurInvalid()" (input)="inputInvalid()" name="targetCron" id="targetCron"
|
||||
#cronStringInput="ngModel" required class="clr-input form-control" [(ngModel)]="cronString">
|
||||
<clr-control-error *ngIf="dateInvalid">{{'TOOLTIP.CRON_REQUIRED' | translate}}</clr-control-error>
|
||||
</label>
|
||||
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-lg tooltip-right top-7 cron-tooltip">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<div class="tooltip-content table-box">
|
||||
<cron-tooltip></cron-tooltip>
|
||||
</div>
|
||||
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true"
|
||||
class="tooltip tooltip-lg tooltip-right top-7 cron-tooltip">
|
||||
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
|
||||
<div class="tooltip-content table-box">
|
||||
<cron-tooltip></cron-tooltip>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="confirm-button">
|
||||
<button [style.margin-left]="buttonMarginLeft" class="btn btn-primary "
|
||||
(click)="save()" id="config-save">
|
||||
{{ "BUTTON.SAVE" | translate }}
|
||||
<button [style.margin-left]="buttonMarginLeft" class="btn btn-primary " (click)="save()" id="config-save">
|
||||
{{ "BUTTON.SAVE" | translate }}
|
||||
</button>
|
||||
<button class="btn btn-primary " (click)="isEditMode=false">
|
||||
{{ "BUTTON.CANCEL" | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -47,6 +47,7 @@
|
||||
.cron-tooltip {
|
||||
color: gray;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
.table-box {
|
||||
width: 20rem;
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ Add Labels To Tag
|
||||
Retry Element Click xpath=//clr-dg-row[contains(.,'${tagName}')]//label
|
||||
Capture Page Screenshot add_${labelName}.png
|
||||
Retry Element Click xpath=//clr-dg-action-bar//clr-dropdown//span
|
||||
Retry Element Click xpath=//clr-dropdown-menu//clr-dropdown//button[contains(.,'Add labels')]
|
||||
Retry Element Click xpath=//clr-dropdown-menu//clr-dropdown//button[contains(.,'Add Labels')]
|
||||
Retry Element Click xpath=//clr-dropdown//div//label[contains(.,'${labelName}')]
|
||||
Retry Wait Until Page Contains Element xpath=//clr-dg-row//label[contains(.,'${labelName}')]
|
||||
|
||||
|
@ -76,6 +76,7 @@ Switch To Scanners Page
|
||||
|
||||
Should Display The Default Clair Scanner
|
||||
Retry Wait Until Page Contains Element //clr-datagrid//clr-dg-row//clr-dg-cell[contains(.,'Clair')]//span[contains(.,'Default')]
|
||||
|
||||
Clair Is Immutable Scanner
|
||||
Retry Element Click //clr-dg-row[contains(.,'Clair')]//clr-radio-wrapper/label
|
||||
Retry Double Keywords When Error Retry Element Click ${scanner_action_xpath} Retry Wait Until Page Contains Element ${delete_scanner_action_xpath}
|
||||
|
Loading…
Reference in New Issue
Block a user