mirror of
https://github.com/goharbor/harbor.git
synced 2024-06-26 06:45:12 +02:00
Fix UI issues found in testing round 1 (#14002)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
74d055b26b
commit
ff3abf047a
|
@ -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>
|
||||
<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">
|
||||
|
|
|
@ -382,7 +382,6 @@ clr-datagrid {
|
|||
}
|
||||
.scan-btn{
|
||||
margin-top: -.3rem;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.eslip {
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
<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">
|
||||
|
|
|
@ -52,6 +52,3 @@
|
|||
.report {
|
||||
text-align: left;
|
||||
}
|
||||
.text-transform-none {
|
||||
text-transform: none;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -45,4 +45,7 @@
|
|||
}
|
||||
.mt-8px {
|
||||
margin-top: 8px !important;
|
||||
}
|
||||
}
|
||||
.showWarning {
|
||||
color: #b3a000;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -68,4 +68,7 @@
|
|||
}
|
||||
.mt-8px {
|
||||
margin-top: 8px !important;
|
||||
}
|
||||
}
|
||||
.showWarning {
|
||||
color: #b3a000;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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": "系统级机器人的最终名称由前缀和当前输入值组成"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user