Fix UI issues found in testing round 1 (#14002)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Will Sun 2021-01-15 12:37:40 +08:00 committed by GitHub
parent 74d055b26b
commit ff3abf047a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 119 additions and 56 deletions

View File

@ -93,8 +93,7 @@
<button id="scan-btn" [clrLoading]="scanBtnState" type="button" class="btn btn-secondary scan-btn"
[disabled]="!(canScanNow() && selectedRowHasVul() && hasEnabledScanner && hasScanImagePermission )" (click)="scanNow()">
<clr-icon shape="shield-check" size="16"></clr-icon>&nbsp;
<span *ngIf="projectScanner">{{'VULNERABILITY.SCAN_BY' | translate: {scanner: getScannerInfo()} }}</span>
<span *ngIf="!projectScanner">{{'VULNERABILITY.NO_SCANNER' | translate}}</span>
<span>{{'VULNERABILITY.SCAN_NOW' | translate}}</span>
</button>
<clr-dropdown class="btn btn-link" *ngIf="!depth">

View File

@ -382,7 +382,6 @@ clr-datagrid {
}
.scan-btn{
margin-top: -.3rem;
text-transform: none;
}
.eslip {

View File

@ -151,7 +151,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
hasDeleteImagePermission: boolean;
hasScanImagePermission: boolean;
hasEnabledScanner: boolean;
projectScanner: ScannerVo;
scanBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
onSendingScanCommand: boolean;
@ -918,7 +917,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
} else {
this.scanBtnState = ClrLoadingState.ERROR;
}
this.projectScanner = response;
}, error => {
this.scanBtnState = ClrLoadingState.ERROR;
});
@ -1043,15 +1041,4 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
});
}
}
getScannerInfo(): string {
if (this.projectScanner) {
if (this.projectScanner.name && this.projectScanner.version) {
return `${this.projectScanner.name}@${this.projectScanner.version}`;
}
if (this.projectScanner.name && !this.projectScanner.version) {
return `${this.projectScanner.name}`;
}
}
return "";
}
}

View File

@ -11,10 +11,9 @@
<clr-dg-action-bar>
<div class="clr-row center">
<div class="ml-05">
<button id="scan-btn" (click)="scanNow()" type="button" class="btn btn-secondary text-transform-none" [clrLoading]="scanBtnState" [disabled]="!(hasEnabledScanner && hasScanningPermission && !onSendingScanCommand)">
<button id="scan-btn" (click)="scanNow()" type="button" class="btn btn-secondary" [clrLoading]="scanBtnState" [disabled]="!(hasEnabledScanner && hasScanningPermission && !onSendingScanCommand)">
<clr-icon shape="shield-check" size="16"></clr-icon>&nbsp;
<span *ngIf="projectScanner">{{'VULNERABILITY.SCAN_BY' | translate: {scanner: getScannerInfo(projectScanner)} }}</span>
<span *ngIf="!projectScanner">{{'VULNERABILITY.NO_SCANNER' | translate}}</span>
<span>{{'VULNERABILITY.SCAN_NOW' | translate}}</span>
</button>
</div>
<div class="ml-1">

View File

@ -52,6 +52,3 @@
.report {
text-align: left;
}
.text-transform-none {
text-transform: none;
}

View File

@ -10,7 +10,14 @@
<section class="form-block">
<!-- name -->
<div class="clr-form-control">
<label for="name" class="clr-control-label required">{{'P2P_PROVIDER.NAME' | translate}}</label>
<label for="name" class="clr-control-label required">{{'P2P_PROVIDER.NAME' | translate}}
<clr-tooltip *ngIf="!isEditMode">
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{"SYSTEM_ROBOT.FINAL_PROJECT_NAME_TIP" | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</label>
<div class="clr-control-container" [class.clr-error]="((name.dirty || name.touched) && name.invalid) || isNameExisting">
<div class="clr-input-wrapper">
<input class="clr-input"
@ -58,6 +65,12 @@
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
</div>
</div>
<clr-control-helper *ngIf="isEditMode && systemRobot?.duration > 0 && !((expiration.dirty || expiration.touched) && expiration.invalid)|| isExpirationInvalid()">
<span [ngClass]="{showWarning: shouldShowWarning()}">
<clr-icon *ngIf="shouldShowWarning()" class="alert-icon" shape="exclamation-triangle"></clr-icon><span>{{'SYSTEM_ROBOT.EXPIRES_AT' | translate}}</span>:
<span>{{calculateExpiresAt() | date:'short'}}</span>
</span>
</clr-control-helper>
<clr-control-error *ngIf="((expiration.dirty || expiration.touched) && expiration.invalid)|| isExpirationInvalid()">
{{"SYSTEM_ROBOT.EXPIRATION_REQUIRED" | translate}}
</clr-control-error>

View File

@ -45,4 +45,7 @@
}
.mt-8px {
margin-top: 8px !important;
}
}
.showWarning {
color: #b3a000;
}

View File

@ -23,6 +23,7 @@ import { operateChanges, OperateInfo, OperationState } from "../../../../lib/com
import { errorHandler } from "../../../../lib/utils/shared/shared.utils";
import { Access } from "../../../../../ng-swagger-gen/models/access";
const MINI_SECONDS_ONE_DAY: number = 60 * 24 * 60 * 1000;
@Component({
selector: "add-robot",
templateUrl: "./add-robot.component.html",
@ -276,4 +277,14 @@ export class AddRobotComponent implements OnInit, OnDestroy {
});
return count;
}
calculateExpiresAt(): Date {
if (this.systemRobot && this.systemRobot.creation_time && this.systemRobot.duration > 0) {
return new Date(new Date(this.systemRobot.creation_time).getTime()
+ this.systemRobot.duration * MINI_SECONDS_ONE_DAY);
}
return null;
}
shouldShowWarning(): boolean {
return new Date() >= this.calculateExpiresAt();
}
}

View File

@ -10,7 +10,14 @@
<section class="form-block">
<!-- name -->
<div class="clr-form-control">
<label for="name" class="clr-control-label required">{{'P2P_PROVIDER.NAME' | translate}}</label>
<label for="name" class="clr-control-label required">{{'P2P_PROVIDER.NAME' | translate}}
<clr-tooltip *ngIf="!isEditMode">
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{"SYSTEM_ROBOT.FINAL_SYSTEM_NAME_TIP" | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</label>
<div class="clr-control-container" [class.clr-error]="((name.dirty || name.touched) && name.invalid) || isNameExisting">
<div class="clr-input-wrapper">
<input class="clr-input input-width"
@ -41,26 +48,34 @@
</clr-tooltip-content>
</clr-tooltip>
</label>
<div class="clr-control-container input-width flex" [class.clr-error]="((expiration.dirty || expiration.touched) && expiration.invalid) || isExpirationInvalid()">
<div class="clr-select-wrapper">
<select [ngModelOptions]="{standalone: true}" (change)="changeExpirationType()" [(ngModel)]="expirationType" id="expiration-type" class="clr-select">
<option value="default">{{systemExpirationDays}} {{"SYSTEM_ROBOT.EXPIRATION_DEFAULT" | translate}}</option>
<option value="days">{{"SYSTEM_ROBOT.EXPIRATION_DAYS" | translate}}</option>
<option value="never">{{"SYSTEM_ROBOT.EXPIRATION_NEVER" | translate}}</option>
</select>
</div>
<div class="clr-input-wrapper">
<input (input)="inputExpiration()" [disabled]="loadingSystemConfig" class="clr-input expiration-width" name="expiration" type="text"
#expiration="ngModel"
autocomplete="off"
[(ngModel)]="systemRobot.duration" required
pattern="^[\-1-9]{1}[0-9]*$" id="robotTokenExpiration" size="20"/>
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!loadingSystemConfig"></span>
<clr-control-error *ngIf="((expiration.dirty || expiration.touched) && expiration.invalid)|| isExpirationInvalid()">
{{"SYSTEM_ROBOT.EXPIRATION_REQUIRED" | translate}}
</clr-control-error>
<div class="clr-control-container input-width" [class.clr-error]="((expiration.dirty || expiration.touched) && expiration.invalid) || isExpirationInvalid()">
<div class="flex">
<div class="clr-select-wrapper">
<select [ngModelOptions]="{standalone: true}" (change)="changeExpirationType()" [(ngModel)]="expirationType" id="expiration-type" class="clr-select">
<option *ngIf="!isEditMode" value="default">{{systemExpirationDays}} {{"SYSTEM_ROBOT.EXPIRATION_DEFAULT" | translate}}</option>
<option value="days">{{"SYSTEM_ROBOT.EXPIRATION_DAYS" | translate}}</option>
<option value="never">{{"SYSTEM_ROBOT.EXPIRATION_NEVER" | translate}}</option>
</select>
</div>
<div class="clr-input-wrapper">
<input (input)="inputExpiration()" [disabled]="loadingSystemConfig" class="clr-input expiration-width" name="expiration" type="text"
#expiration="ngModel"
autocomplete="off"
[(ngModel)]="systemRobot.duration" required
pattern="^[\-1-9]{1}[0-9]*$" id="robotTokenExpiration" size="20"/>
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
<span class="spinner spinner-inline" [hidden]="!loadingSystemConfig"></span>
<clr-control-error *ngIf="((expiration.dirty || expiration.touched) && expiration.invalid)|| isExpirationInvalid()">
{{"SYSTEM_ROBOT.EXPIRATION_REQUIRED" | translate}}
</clr-control-error>
</div>
</div>
<clr-control-helper *ngIf="isEditMode && systemRobot?.duration > 0 && !((expiration.dirty || expiration.touched) && expiration.invalid)|| isExpirationInvalid()">
<span [ngClass]="{showWarning: shouldShowWarning()}">
<clr-icon *ngIf="shouldShowWarning()" class="alert-icon" shape="exclamation-triangle"></clr-icon><span>{{'SYSTEM_ROBOT.EXPIRES_AT' | translate}}</span>:
<span>{{calculateExpiresAt() | date:'short'}}</span>
</span>
</clr-control-helper>
</div>
</div>
<!-- 3. description -->

View File

@ -68,4 +68,7 @@
}
.mt-8px {
margin-top: 8px !important;
}
}
.showWarning {
color: #b3a000;
}

View File

@ -28,7 +28,7 @@ import { operateChanges, OperateInfo, OperationState } from "../../../lib/compon
import { OperationService } from "../../../lib/components/operation/operation.service";
import { errorHandler } from "../../../lib/utils/shared/shared.utils";
const MINUETS_ONE_DAY: number = 60 * 24;
const MINI_SECONDS_ONE_DAY: number = 60 * 24 * 60 * 1000;
@Component({
selector: 'new-robot',
@ -436,4 +436,14 @@ export class NewRobotComponent implements OnInit, OnDestroy {
});
return count;
}
calculateExpiresAt(): Date {
if (this.systemRobot && this.systemRobot.creation_time && this.systemRobot.duration > 0) {
return new Date(new Date(this.systemRobot.creation_time).getTime()
+ this.systemRobot.duration * MINI_SECONDS_ONE_DAY);
}
return null;
}
shouldShowWarning(): boolean {
return new Date() >= this.calculateExpiresAt();
}
}

View File

@ -87,9 +87,12 @@
</clr-dropdown>
</div>
<span *ngIf="!r.permissionScope || !r.permissionScope?.coverAll">
<a href="javascript:void(0)" (click)="openProjectModal(getProjects(r), r.name)">
{{getProjects(r)?.length?getProjects(r)?.length:""}} {{'SYSTEM_ROBOT.COVERED_PROJECTS' | translate}}
<a *ngIf="getProjects(r)?.length" href="javascript:void(0)" (click)="openProjectModal(getProjects(r), r.name)">
{{getProjects(r)?.length}} {{'SYSTEM_ROBOT.COVERED_PROJECTS' | translate}}
</a>
<span *ngIf="!getProjects(r)?.length">
0 {{'SYSTEM_ROBOT.COVERED_PROJECTS' | translate}}
</span>
</span>
</clr-dg-cell>
<clr-dg-cell>{{r.creation_time | date: 'short'}}</clr-dg-cell>

View File

@ -1217,6 +1217,7 @@
"HOURLY": "Stündlich",
"CUSTOM": "Angepasst",
"MANUAL": "Manuell",
"SCHEDULE": "Geplant",
"CRON": "cron",
"ON": "am",
"AT": "um",
@ -1665,6 +1666,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1217,6 +1217,7 @@
"HOURLY": "Hourly",
"CUSTOM": "Custom",
"MANUAL": "Manual",
"SCHEDULE": "Scheduled",
"CRON": "cron",
"ON": "on",
"AT": "at",
@ -1665,6 +1666,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1215,6 +1215,7 @@
"HOURLY": "Hourly",
"CUSTOM": "Custom",
"MANUAL": "Manual",
"SCHEDULE": "Scheduled",
"CRON": "cron",
"ON": "on",
"AT": "at",
@ -1663,6 +1664,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1186,6 +1186,7 @@
"HOURLY": "Hourly",
"CUSTOM": "Custom",
"MANUAL": "Manual",
"SCHEDULE": "Scheduled",
"CRON": "cron",
"ON": "on",
"AT": "at",
@ -1633,6 +1634,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1209,6 +1209,7 @@
"HOURLY": "Hourly",
"CUSTOM": "Custom",
"MANUAL": "Manual",
"SCHEDULE": "Scheduled",
"CRON": "cron",
"ON": "on",
"AT": "at",
@ -1661,7 +1662,9 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1217,6 +1217,7 @@
"HOURLY": "Saatlik",
"CUSTOM": "Özel",
"MANUAL": "Manuel",
"SCHEDULE": "Scheduled",
"CRON": "cron",
"ON": "on",
"AT": "at",
@ -1665,6 +1666,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}

View File

@ -1215,6 +1215,7 @@
"CUSTOM": "自定义",
"CRON": "cron",
"MANUAL": "手动",
"SCHEDULE": "定时",
"ON": " ",
"AT": " ",
"NOSCHEDULE": "获取schedule时出现错误"
@ -1662,6 +1663,8 @@
"ARTIFACT_LABEL": "Artifact 标签",
"SCAN": "扫描",
"SCANNER_PULL": "扫描器拉取",
"SEARCH_BY_NAME": "按名称(不含前缀)搜索"
"SEARCH_BY_NAME": "按名称(不含前缀)搜索",
"FINAL_PROJECT_NAME_TIP": "项目级机器人的最终名称由前缀,项目名称,一个加号以及当前输入值组成",
"FINAL_SYSTEM_NAME_TIP": "系统级机器人的最终名称由前缀和当前输入值组成"
}
}

View File

@ -1203,6 +1203,7 @@
"CUSTOM": "自定義",
"CRON":"cron",
"MANUAL": "手動",
"SCHEDULE": "Scheduled",
"ON": " ",
"AT": " ",
"NOSCHEDULE": "獲取schedule時出現錯誤"
@ -1649,6 +1650,8 @@
"ARTIFACT_LABEL": "Artifact label",
"SCAN": "Scan",
"SCANNER_PULL": "Scanner Pull",
"SEARCH_BY_NAME": "Search by name(without prefix)"
"SEARCH_BY_NAME": "Search by name(without prefix)",
"FINAL_PROJECT_NAME_TIP": "The final project robot name consists of the prefix,the project name,a plus mark and the current input value",
"FINAL_SYSTEM_NAME_TIP": "The final system robot name consists of the prefix and the current input value"
}
}