Fix UI issues with label target 2.0.1

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
AllForNothing 2020-06-08 13:42:38 +08:00
parent c261555b59
commit a773115cc3
44 changed files with 258 additions and 254 deletions

View File

@ -80,28 +80,22 @@
</clr-vertical-nav-group-children>
</clr-vertical-nav-group>
</div>
<div>
<ng-container *ngFor="let theme of themeArray;let i=index">
<ng-container *ngIf="theme.showStyle === styleMode">
<div class="mb-1">
<ng-container *ngFor="let theme of themeArray;let i=index">
<ng-container *ngIf="theme.showStyle === styleMode">
<a clrVerticalNavLink (click)="themeChanged(theme)">
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='DARK'" shape="sun" class="is-solid"></clr-icon>
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='LIGHT'" shape="moon" class="is-solid"></clr-icon>
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='DARK'" shape="sun"
class="is-solid"></clr-icon>
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='LIGHT'" shape="moon"
class="is-solid"></clr-icon>
{{ theme.text | translate }}
</a>
</ng-container>
</ng-container>
<clr-vertical-nav-group routerLinkActive="active">
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.API_EXPLORER' | translate}}
<a routerLink="#" hidden aria-hidden="true"></a>
<clr-vertical-nav-group-children *clrIfExpanded="true">
<a class="font-size-13" clrVerticalNavLink target="_blank" routerLink="/devcenter-api-2.0"
routerLinkActive="active">
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.HARBOR_API_MANAGEMENT' | translate}}
</a>
</clr-vertical-nav-group-children>
</clr-vertical-nav-group>
</ng-container>
</ng-container>
<a clrVerticalNavLink routerLinkActive="active" target="_blank" routerLink="/devcenter-api-2.0">
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.HARBOR_API_MANAGEMENT' | translate}}
</a>
</div>
</clr-vertical-nav>
<hbr-operation-model *ngIf="isUserExisting"></hbr-operation-model>

View File

@ -1,25 +1,3 @@
.info-tips-icon {
color: grey;
}
.info-tips-icon:hover {
color: #007CBB;
}
clr-icon {
color: grey;
margin-top: -3px;
}
clr-icon:hover {
color: #007CBB;
}
.clr-validate-icon {
color: red;
}
.config-title {
display: inline-block;
}

View File

@ -4,18 +4,10 @@
display: flex;
justify-content: flex-end;
}
.refresh-btn {
cursor: pointer;
margin-top: 7px;
}
.clr-icon {
color: #0079b8;
margin-top: 0;
}
.color-b {
color: #bbb;
}
.margin-left-5 {
margin-left: 5px;
}

View File

@ -1,6 +1,7 @@
.value-container {
::ng-deep pre {
min-height: fit-content;
max-height: none !important;
}
}
@ -19,4 +20,4 @@
pre {
max-height: max-content;
padding-left: 21px;
}
}

View File

@ -20,8 +20,7 @@
.filter-divider {
display: inline-block;
height: 16px;
width: 2px;
background-color: #cccccc;
width: 1px;
padding-top: 12px;
padding-bottom: 12px;
position: relative;
@ -115,4 +114,4 @@ hbr-resource-label-signpost {
.version-position {
position: relative;
}
}

View File

@ -18,8 +18,7 @@ $size60:60px;
.filter-divider {
display: inline-block;
height: 16px;
width: 2px;
background-color: #ccc;
width: 1px;
padding-top: 12px;
padding-bottom: 12px;
position: relative;
@ -133,4 +132,4 @@ button {
.version-position {
position: relative;
}
}

View File

@ -200,6 +200,9 @@ export class ListProjectComponent implements OnDestroy {
observableLists.push(this.delOperate(data));
});
forkJoin(...observableLists).subscribe(item => {
this.translate.get("BATCH.DELETED_SUCCESS").subscribe(res => {
this.msgHandler.showSuccess(res);
});
let st: State = this.getStateAfterDeletion();
this.selectedRow = [];
if (!st) {
@ -208,6 +211,10 @@ export class ListProjectComponent implements OnDestroy {
this.clrLoad(st);
this.statisticHandler.refresh();
}
}, error => {
this.translate.get("BATCH.DELETED_FAILURE").subscribe(res => {
this.msgHandler.handleError(res);
});
});
}
}
@ -220,13 +227,10 @@ export class ListProjectComponent implements OnDestroy {
operMessage.state = OperationState.progressing;
operMessage.data.name = project.name;
this.operationService.publishInfo(operMessage);
return this.proService.deleteProject(project.project_id)
.pipe(map(
() => {
this.translate.get("BATCH.DELETED_SUCCESS").subscribe(res => {
operateChanges(operMessage, OperationState.success);
});
operateChanges(operMessage, OperationState.success);
}), catchError(
error => {
const message = errorHandler(error);

View File

@ -299,7 +299,7 @@
<div class="trigger-item">
<clr-signpost>
<button class="btn btn-link" clrSignpostTrigger>...</button>
<clr-signpost-content [clrPosition]="'left-top'" *clrIfOpen>
<clr-signpost-content [clrPosition]="'top-middle'" *clrIfOpen>
<div>
<hbr-label-piece *ngFor="let label of artifact.labels" [label]="label">
</hbr-label-piece>

View File

@ -56,8 +56,7 @@
.filter-divider {
display: inline-block;
height: 16px;
width: 2px;
background-color: #ccc;
width: 1px;
padding-top: 12px;
padding-bottom: 12px;
position: relative;

View File

@ -15,14 +15,10 @@
<clr-tooltip>
<div clrTooltipTrigger class="tip-block">
<div *ngIf="!isNone" class="circle-block">
<div class="black-point-container margin-left-10">
<div class="black-point"></div>
</div>
<div class="black-point-container margin-left-10"></div>
<span class="margin-left-10 font-weight-800 font-size-14">{{total}}</span>
<span class="margin-left-5 font-size-14">{{'SCANNER.TOTAL' | translate}}</span>
<div class="black-point-container margin-left-10">
<div class="black-point "></div>
</div>
<div class="black-point-container margin-left-10">-</div>
<span class="margin-left-10 font-weight-800 font-size-12">{{fixableCount}}</span>
<span class="margin-left-5 font-size-12">{{'SCANNER.FIXABLE' | translate}}</span>
</div>
@ -32,7 +28,7 @@
<div class="bar-tooltip-font-larger">
<div *ngIf="!isNone" class="level-border clr-display-inline-block margin-right-5">
<div [className]="getClass()">
<div class="inner">
<div class="inner" [ngClass]="{'is-white': !isThemeLight(), 'is-dark': isThemeLight()}">
{{vulnerabilitySummary?.severity | slice:0:1}}
</div>
</div>

View File

@ -1,5 +1,5 @@
$thirty-pixel: 30px;
$twenty-two-pixel: 22px;
$thirty-pixel: 26px;
$twenty-two-pixel: 18px;
.bar-wrapper {
width: 144px;
@ -235,11 +235,10 @@ hr {
height: $twenty-two-pixel;
width: $twenty-two-pixel;
line-height: $twenty-two-pixel;
font-size: 14px;
font-size: 12px;
font-weight: 600;
border-radius: 50%;
text-align: center;
background-color: #fff;
}
.level-critical {
@ -294,4 +293,10 @@ hr {
}
.margin-right-5 {
margin-right: 5px;
}
}
.is-white {
background-color: #fff;
}
.is-dark {
background-color: #000;
}

View File

@ -22,18 +22,7 @@
.font-size-54 {
font-size: 0.541667rem;
}
::ng-deep {
.normal-wrapper-box {
.normal-wrapper {
.font-style {
width: 150px !important;
}
}
.btn {
margin-left: 150px !important;
}
}
}
.flex-150 {
flex: 0 0 150px;
}

View File

@ -1,11 +1,11 @@
<div class="btn-group btn-tag-integration">
<div class="radio btn">
<input type="radio" name="btn-group-demo-radios" id="btn-retention">
<label class="p-0" for="btn-retention"><a class="nav-link" routerLink="tag-retention" routerLinkActive="active" >{{'TAG_RETENTION.TAG_RETENTION' | translate}}</a></label>
<label class="p-0" for="btn-retention"><a class="strategy-nav-link" routerLink="tag-retention" routerLinkActive="active" >{{'TAG_RETENTION.TAG_RETENTION' | translate}}</a></label>
</div>
<div class="radio btn">
<input type="radio" name="btn-group-demo-radios" id="btn-immutable">
<label class="p-0" for="btn-immutable"><a class="nav-link" routerLink="immutable-tag" routerLinkActive="active" >{{'PROJECT_DETAIL.IMMUTABLE_TAG' | translate}}</a></label>
<label class="p-0" for="btn-immutable"><a class="strategy-nav-link" routerLink="immutable-tag" routerLinkActive="active" >{{'PROJECT_DETAIL.IMMUTABLE_TAG' | translate}}</a></label>
</div>
</div>
<router-outlet></router-outlet>
<router-outlet></router-outlet>

View File

@ -1,17 +1,12 @@
.btn-tag-integration {
margin-top: 1.5rem;
margin-bottom: 1rem;
.nav-link {
.strategy-nav-link {
height: 100%;
width: 100%;
display: inline-block;
padding-left: 0.5rem;
padding-right: 0.5rem;
text-decoration: none;
color: #0077b8;
}
.active {
background: #0077b8;
color: #fff;
}
}

View File

@ -67,7 +67,7 @@
</div>
</div>
<div class="cron-selection">
<cron-selection [buttonMarginLeft]="'150px'" [disabled]="!(retention?.rules?.length > 0)" #cronScheduleComponent [labelCurrent]="label" [labelEdit]='label' [originCron]='originCron()' (inputvalue)="openConfirm($event)"></cron-selection>
<cron-selection [labelWidth]="'150px'" [disabled]="!(retention?.rules?.length > 0)" #cronScheduleComponent [labelCurrent]="label" [labelEdit]='label' [originCron]='originCron()' (inputvalue)="openConfirm($event)"></cron-selection>
</div>
<div class="clr-row pt-1">
<div class="clr-col-2 pt-2 flex-150"><label class="label-left font-size-54">{{'TAG_RETENTION.RETENTION_RUNS' | translate}}</label></div>

View File

@ -44,7 +44,7 @@
z-index: 999;
}
.cron-selection {
margin-top: 20px;
margin-top: 30px;
display: flex;
align-items: center;
}

View File

@ -82,7 +82,7 @@
<div class="trigger-item">
<clr-signpost>
<button class="btn btn-link ellipsis-btn font-size-20" clrSignpostTrigger>...</button>
<clr-signpost-content [clrPosition]="'left-top'" *clrIfOpen>
<clr-signpost-content [clrPosition]="'top-middle'" *clrIfOpen>
<div>
<div *ngFor="let e of w?.event_types" class="bar-state">
<span class="label not-scan">{{eventTypeToText(e)}}</span>

View File

@ -122,6 +122,32 @@ hbr-tag {
}
}
.filter-divider {
background-color: $filter-divider-bg-color ;
}
.selectBox {
background: $select-back-color !important;
color: $select-option-color !important;
}
.selectBox ul li:hover{
background-image: linear-gradient(180deg,$selectBox-option-hover-bg-color-start 0,$selectBox-option-hover-bg-color-end) !important;
}
.btn-tag-integration {
.active {
background: $btn-tag-integration-active-bg-color;
color: $btn-tag-integration-active-color;
}
}
hbr-result-tip-histogram {
.inner {
background-color: $hbr-result-tip-histogram-inner-bg-color;
}
}
// style of hbr-artifact-summary component
@mixin align-text-mixin($values...) {
@each $var in $values {
@ -136,6 +162,10 @@ hbr-tag {
padding: 2px 4px;
}
:not(pre) > code[class*="language-"], pre[class*="language-"] {
background-color: $color-yaml;
}
.md-div {
code:not([class*="language-"]) {
@extend %code-block;
@ -187,4 +217,4 @@ hbr-tag {
clr-header {
background-color: $header-color;
}
}

View File

@ -25,5 +25,12 @@ $color-f2: none;
$color-657b83: none;
$color-fdf6e3: none;
$header-color: hsl(198, 100%, 15%)!important;
$color-yaml: #253c46;
$filter-divider-bg-color: #495865;
$selectBox-option-hover-bg-color-start: #4aaed9;
$selectBox-option-hover-bg-color-end: #0077b8;
$btn-tag-integration-active-bg-color: #4aaed9;
$btn-tag-integration-active-color: #000;
$hbr-result-tip-histogram-inner-bg-color: #21333b;
@import "./common.scss";

View File

@ -27,5 +27,12 @@ $color-f2: #f2f2f2;
$color-657b83: #657b83;
$color-fdf6e3: #fdf6e3;
$header-color: rgb(0, 74, 112);
$color-yaml: none;
$filter-divider-bg-color: #ccc;
$selectBox-option-hover-bg-color-start: #f5f5f5;
$selectBox-option-hover-bg-color-end: #e8e8e8;
$btn-tag-integration-active-bg-color: #0077b8;
$btn-tag-integration-active-color: #fff;
$hbr-result-tip-histogram-inner-bg-color: #fff;
@import "./common.scss";

View File

@ -54,7 +54,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "Deleted successfully",
"DELETED_FAILURE": "Deleted failed",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "Switch successfully",
"SWITCH_FAILURE": "Switch failed",
"REPLICATE_SUCCESS": "Started successfully",
@ -238,7 +238,7 @@
"STORAGE_QUOTA": "Storage quota",
"COUNT_QUOTA_TIP": "Please enter an integer between '1' & '100,000,000', '-1' for unlimited.",
"STORAGE_QUOTA_TIP": "The upper limit of Storage Quota only takes integer values, capped at '1024TB'. Enter '-1' for unlimited quota",
"QUOTA_UNLIMIT_TIP": "For unlimited quota, please enter '-1'."
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'."
},
"PROJECT_DETAIL": {
"SUMMARY": "Summary",
@ -503,10 +503,10 @@
"ENDPOINTS": "Endpoints",
"FILTER_POLICIES_PLACEHOLDER": "Filter Rules",
"FILTER_EXECUTIONS_PLACEHOLDER": "Filter Executions",
"DELETION_TITLE": "Confirm Rules Deletion",
"DELETION_SUMMARY": "Do you want to delete rules {{param}}?",
"REPLICATION_TITLE": "Confirm Rules replication",
"REPLICATION_SUMMARY": "Do you want to replicate the Rules {{param}}?",
"DELETION_TITLE": "Confirm Replication Rule Deletion",
"DELETION_SUMMARY": "Do you want to delete replication rule {{param}}?",
"REPLICATION_TITLE": "Confirm Rule Replication",
"REPLICATION_SUMMARY": "Do you want to replicate the rule {{param}}?",
"DELETION_TITLE_FAILURE": "failed to delete Rule Deletion",
"DELETION_SUMMARY_FAILURE": "have pending/running/retrying status",
"REPLICATE_SUMMARY_FAILURE": "have pending/running status",
@ -1190,7 +1190,7 @@
},
"GC": {
"CURRENT_SCHEDULE": "Current Schedule",
"CURRENT_SCHEDULE": "Schedule to GC",
"GC_NOW": "GC NOW",
"JOB_HISTORY": "GC History",
"JOB_ID": "Job ID",
@ -1200,7 +1200,8 @@
"MSG_SCHEDULE_SET": "Garbage Collection schedule has been set",
"MSG_SCHEDULE_RESET": "Garbage Collection schedule has been reset",
"PARAMETERS": "Parameters",
"DELETE_UNTAGGED": "Delete Untagged Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG": {
"MSG_SUCCESS": "Copy artifact successfully",

View File

@ -54,7 +54,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "Deleted successfully",
"DELETED_FAILURE": "Deleted failed",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "Switch successfully",
"SWITCH_FAILURE": "Switch failed",
"REPLICATE_SUCCESS": "Started successfully",
@ -239,7 +239,7 @@
"STORAGE_QUOTA": "Storage quota",
"COUNT_QUOTA_TIP": "Please enter an integer between '1' & '100,000,000', '-1' for unlimited",
"STORAGE_QUOTA_TIP": "The upper limit of Storage Quota only takes integer values, capped at '1024TB'. Enter '-1' for unlimited quota",
"QUOTA_UNLIMIT_TIP": "For unlimited quota, please enter '-1'."
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'."
},
"PROJECT_DETAIL": {
"SUMMARY": "Summary",
@ -510,8 +510,8 @@
"DELETION_TITLE_FAILURE": "failed to delete Rule Deletion",
"DELETION_SUMMARY_FAILURE": "have pending/running/retrying status",
"REPLICATE_SUMMARY_FAILURE": "have pending/running status",
"REPLICATION_TITLE": "Confirm Rules replication",
"REPLICATION_SUMMARY": "Do you want to replicate the Rules {{param}}?",
"REPLICATION_TITLE": "Confirm Rule replication",
"REPLICATION_SUMMARY": "Do you want to replicate the Rule {{param}}?",
"FILTER_TARGETS_PLACEHOLDER": "Filtrar Endpoints",
"DELETION_TITLE_TARGET": "Confirmar Eliminación de Endpoint",
"DELETION_SUMMARY_TARGET": "¿Quiere eliminar el endpoint {{param}}?",
@ -1188,7 +1188,7 @@
},
"GC": {
"CURRENT_SCHEDULE": "Current Schedule",
"CURRENT_SCHEDULE": "Schedule to GC",
"GC_NOW": "GC NOW",
"JOB_HISTORY": "GC History",
"JOB_ID": "Job ID",
@ -1198,7 +1198,8 @@
"MSG_SCHEDULE_SET": "Garbage Collection schedule has been set",
"MSG_SCHEDULE_RESET": "Garbage Collection schedule has been reset",
"PARAMETERS": "Parameters",
"DELETE_UNTAGGED": "Delete Untagged Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG": {
"MSG_SUCCESS": "Copy artifact successfully",

View File

@ -51,7 +51,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "Deleted successfully",
"DELETED_FAILURE": "Deleted failed",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "Switch successfully",
"SWITCH_FAILURE": "Switch failed",
"REPLICATE_SUCCESS": "Started successfully",
@ -232,7 +232,7 @@
"STORAGE_QUOTA": "Storage quota",
"COUNT_QUOTA_TIP": "Please enter an integer between '1' & '100,000,000', '-1' for unlimited",
"STORAGE_QUOTA_TIP": "The upper limit of Storage Quota only takes integer values, capped at '1024TB'. Enter '-1' for unlimited quota",
"QUOTA_UNLIMIT_TIP": "For unlimited quota, please enter '-1'."
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'."
},
"PROJECT_DETAIL": {
"SUMMARY": "Summary",
@ -1158,7 +1158,7 @@
"NOSCHEDULE": "An error occurred in Get schedule"
},
"GC": {
"CURRENT_SCHEDULE": "Current Schedule",
"CURRENT_SCHEDULE": "Schedule to GC",
"GC_NOW": "GC NOW",
"JOB_HISTORY": "GC History",
"JOB_ID": "Job ID",
@ -1168,7 +1168,8 @@
"MSG_SCHEDULE_SET": "Garbage Collection schedule has been set",
"MSG_SCHEDULE_RESET": "Garbage Collection schedule has been reset",
"PARAMETERS": "Parameters",
"DELETE_UNTAGGED": "Delete Untagged Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG": {
"MSG_SUCCESS": "Copy artifact successfully",

View File

@ -54,7 +54,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "Removido com sucesso",
"DELETED_FAILURE": "Falha ao remover",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "Alterado com sucesso",
"SWITCH_FAILURE": "Falha ao alterar",
"REPLICATE_SUCCESS": "Iniciado com sucesso",
@ -236,7 +236,7 @@
"STORAGE_QUOTA": "Storage quota",
"COUNT_QUOTA_TIP": "Please enter an integer between '1' & '100,000,000', '-1' for unlimited",
"STORAGE_QUOTA_TIP": "The upper limit of Storage Quota only takes integer values, capped at '1024TB'. Enter '-1' for unlimited quota",
"QUOTA_UNLIMIT_TIP": "For unlimited quota, please enter '-1'."
"QUOTA_UNLIMIT_TIP": "For unlimited quota enter '-1'."
},
"PROJECT_DETAIL": {
"SUMMARY": "Summary",
@ -1182,7 +1182,7 @@
},
"GC": {
"CURRENT_SCHEDULE": "Agendamento atual",
"CURRENT_SCHEDULE": "Schedule to GC",
"ON": "em",
"AT": "em",
"GC_NOW": "GC AGORA",
@ -1196,7 +1196,8 @@
"MSG_SCHEDULE_SET": "Agendamento de Garbage Collection efetuado",
"MSG_SCHEDULE_RESET": "Agendamento de Garbage Collection foi redefinido",
"PARAMETERS": "Parameters",
"DELETE_UNTAGGED": "Delete Untagged Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG": {
"MSG_SUCCESS": "Copy artifact successfully",

View File

@ -54,7 +54,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "Başarı ile silindi.",
"DELETED_FAILURE": "Silme başarısız.",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "Değiştirme başarılı",
"SWITCH_FAILURE": "Değiştirme başarısız",
"REPLICATE_SUCCESS": "Başlatma başarılı.",
@ -1190,7 +1190,7 @@
},
"GC": {
"CURRENT_SCHEDULE": "Mevcut Program",
"CURRENT_SCHEDULE": "Schedule to GC",
"GC_NOW": "ŞİMDİ ÇT",
"JOB_HISTORY": "ÇT Geçmişi",
"JOB_ID": "İş ID",
@ -1200,7 +1200,8 @@
"MSG_SCHEDULE_SET": "Çöp Toplama programı belirlendi",
"MSG_SCHEDULE_RESET": "Çöp Toplama programı sıfırlandı",
"PARAMETERS": "Parameters",
"DELETE_UNTAGGED": "Delete Untagged Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG": {
"MSG_SUCCESS": "Copy artifact successfully",

View File

@ -54,7 +54,7 @@
},
"BATCH": {
"DELETED_SUCCESS": "删除成功",
"DELETED_FAILURE": "删除失败",
"DELETED_FAILURE": "删除失败或部分失败",
"SWITCH_SUCCESS": "切换成功",
"SWITCH_FAILURE": "切换失败",
"REPLICATE_SUCCESS": "开始成功",
@ -1197,7 +1197,8 @@
"MSG_SCHEDULE_SET": "垃圾回收定时任务设置成功",
"MSG_SCHEDULE_RESET": "垃圾回收定时任务已被重置",
"PARAMETERS": "参数",
"DELETE_UNTAGGED": "删除无 Tag 的 Artifacts"
"DELETE_UNTAGGED": "允许回收无 tag 的 artifacts",
"EXPLAIN": "垃圾回收是一个计算密集型操作,可能会影响仓库性能"
},
"RETAG": {
"MSG_SUCCESS": "Artifact 拷贝成功",

View File

@ -54,7 +54,7 @@
},
"BATCH":{
"DELETED_SUCCESS": "刪除成功",
"DELETED_FAILURE": "刪除失敗",
"DELETED_FAILURE": "Deleted failed or partly failed",
"SWITCH_SUCCESS": "切換成功",
"SWITCH_FAILURE": "切換失敗",
"REPLICATE_SUCCESS": "開始成功",
@ -1184,7 +1184,8 @@
"MSG_SCHEDULE_SET": "垃圾回收定時任務設置成功",
"MSG_SCHEDULE_RESET": "垃圾回收定時任務已被重置",
"PARAMETERS": "參數",
"DELETE_UNTAGGED": "刪除無Tag 的Artifacts"
"DELETE_UNTAGGED": "Allow garbage collection on untagged artifacts",
"EXPLAIN": "GC is a compute intensive operation that may impact registry performance"
},
"RETAG":{
"MSG_SUCCESS": "Artifact 拷貝成功",

View File

@ -1,15 +1,27 @@
<form class="clr-form clr-form-horizontal">
<clr-checkbox-container>
<clr-checkbox-wrapper>
<input type="checkbox" clrCheckbox name="delete_untagged" id="delete_untagged"
[(ngModel)]="shouldDeleteUntagged"/>
<label for="delete_untagged">{{'GC.DELETE_UNTAGGED' | translate}}</label>
</clr-checkbox-wrapper>
</clr-checkbox-container>
</form>
<div class="cron-selection">
<cron-selection [buttonMarginLeft]="'0'" [labelCurrent]="getLabelCurrent" #CronScheduleComponent [labelEdit]='getText'
<cron-selection [labelCurrent]="getLabelCurrent" #CronScheduleComponent [labelEdit]='getLabelCurrent'
[originCron]='originCron' (inputvalue)="scheduleGc($event)"></cron-selection>
<button class="btn btn-outline gc-start-btn" (click)="gcNow()"
</div>
<div class="clr-row">
<div class="clr-col-2 flex-200"></div>
<div class="clr-col">
<span class="explain">{{'GC.EXPLAIN' | translate}}</span>
</div>
</div>
<div class="clr-row">
<div class="clr-col-2 flex-200"></div>
<div class="clr-col">
<clr-toggle-container class="mt-05">
<clr-toggle-wrapper>
<input type="checkbox" clrToggle name="delete_untagged" id="delete_untagged"
[(ngModel)]="shouldDeleteUntagged"/>
<label class="font-weight-400" for="delete_untagged">{{'GC.DELETE_UNTAGGED' | translate}}</label>
</clr-toggle-wrapper>
</clr-toggle-container>
</div>
</div>
<div class="clr-row">
<button class="btn btn-primary gc-start-btn" (click)="gcNow()"
[disabled]="disableGC">{{'GC.GC_NOW' | translate}}</button>
</div>

View File

@ -1,15 +1,29 @@
.cron-selection {
padding-left: 0.25rem;
margin-top: 1rem;
display: flex;
align-items: center;
}
.gc-start-btn {
width:150px;
margin-top: 41px;
margin-left: 0.5rem;
margin-top: 35px;
}
.flex-200 {
flex: 0 0 200px;
max-width: 200px;
}
.mt-05 {
margin-top: 0.5rem;
}
.font-weight-400 {
font-weight: 400;
}
.explain {
font-weight: 100;
font-size: 10px;
}
.parameters {
font-size: 0.541667rem !important;
width: 200px !important;
font-weight: 400 !important;
}

View File

@ -29,8 +29,7 @@ export class GcComponent implements OnInit {
schedule: GCSchedule = {};
originCron: OriginCron;
disableGC: boolean = false;
getText = '';
getLabelCurrent = '';
getLabelCurrent = 'GC.CURRENT_SCHEDULE';
@Output() loadingGcStatus = new EventEmitter<boolean>();
@ViewChild(CronScheduleComponent, {static: false})
CronScheduleComponent: CronScheduleComponent;

View File

@ -117,9 +117,10 @@
<li *ngIf="systemWhitelist?.items?.length<1" class="none">{{'CVE_WHITELIST.NONE'|translate}}
</li>
<li *ngFor="let item of systemWhitelist?.items;let i = index;">
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
<clr-icon (click)="deleteItem(i)" class="float-lg-right margin-top-4"
shape="times-circle"></clr-icon>
<a href="javascript:void(0)" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</a>
<a class="float-lg-right" href="javascript:void(0)" (click)="deleteItem(i)">
<clr-icon shape="times-circle"></clr-icon>
</a>
</li>
</ul>
</div>

View File

@ -56,7 +56,6 @@
padding: 12px;
height: 224px;
width: 222px;
color: #0079bb;
overflow-y: auto;
li {
height: 24px;

View File

@ -6,14 +6,14 @@
<span>{{ updatedTimeStr }} </span>
</div>
<div class="button-group">
<cron-selection [buttonMarginLeft]="'200px'" [disabled]="!hasDefaultScanner" [labelCurrent]="getLabelCurrent" [labelEdit]='getLabelCurrent'
<cron-selection [disabled]="!hasDefaultScanner" [labelCurrent]="getLabelCurrent" [labelEdit]='getLabelCurrent'
[originCron]='originCron' (inputvalue)="saveSchedule($event)"></cron-selection>
</div>
</section>
<div class="clr-row">
<div class="clr-col-2 flex-200">
<div class="btn-scan-right btn-scan margin-top-16px">
<button id="scan-now" class="btn btn-outline btn-scan" (click)="scanNow()"
<button id="scan-now" class="btn btn-primary btn-scan" (click)="scanNow()"
[disabled]="!scanAvailable">
<span *ngIf="scanAvailable">{{ 'CONFIG.SCANNING.SCAN_NOW' | translate }}</span>
<span *ngIf="!scanAvailable">{{ 'CONFIG.SCANNING.SCAN' | translate }}</span>

View File

@ -14,13 +14,13 @@
<clr-select-container>
<label class="required">{{'DESTINATION.PROVIDER' | translate}}</label>
<select clrSelect name="adapter" id="adapter" (change)="adapterChange($event)" [(ngModel)]="target.type" [disabled]="testOngoing || editDisabled">
<option *ngFor="let adapter of adapterList" value="{{adapter}}">{{adapter}}</option>
<option *ngFor="let adapter of adapterList" value="{{adapter}}">{{getAdapterText(adapter)}}</option>
</select>
</clr-select-container>
<!-- Endpoint name -->
<clr-input-container>
<label class="required">{{ 'DESTINATION.NAME' | translate }}</label>
<input clrInput type="text" id="destination_name" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.name"
<input autocomplete="off" clrInput type="text" id="destination_name" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.name"
name="targetName" size="30" #targetName="ngModel" required>
<clr-control-error *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}

View File

@ -477,4 +477,8 @@ export class CreateEditEndpointComponent
}
return changes;
}
getAdapterText(adapter: string): string {
return this.endpointService.getAdapterText(adapter);
}
}

View File

@ -1,6 +1,5 @@
<div class="normal-wrapper-box flex-layout" *ngIf="!isEditMode">
<div class="normal-wrapper">
<span [style.width]="buttonMarginLeft" class="font-style">{{ labelCurrent | translate }}</span>
<div class="normal-wrapper-box" *ngIf="!isEditMode">
<span class="font-style" [style.width]="labelWidth">{{ 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">
@ -19,14 +18,13 @@
</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.EDIT" | translate }}
</button>
<button [disabled]="disabled" class="btn btn-link" (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="normal-wrapper-box" *ngIf="isEditMode">
<span class="font-style" [style.width]="labelWidth">{{ labelEdit | translate }}</span>
<div class="select select-schedule clr-select-wrapper">
<select name="selectPolicy" id="selectPolicy" [(ngModel)]="scheduleType">
<option [value]="SCHEDULE_TYPE.NONE">{{'SCHEDULE.NONE' | translate}}</option>
@ -41,7 +39,7 @@
<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">
#cronStringInput="ngModel" required class="clr-input form-control ml-1" [(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"
@ -52,12 +50,10 @@
</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>
<button class="btn btn-primary " (click)="isEditMode=false">
{{ "BUTTON.CANCEL" | translate }}
</button>
</div>
</div>
<button class="btn btn-link " (click)="save()" id="config-save">
{{ "BUTTON.SAVE" | translate }}
</button>
<button class="btn btn-link " (click)="isEditMode=false">
{{ "BUTTON.CANCEL" | translate }}
</button>
</div>

View File

@ -1,71 +1,20 @@
.flex-layout {
margin: 20px 0;
font-size: .541667rem;
.normal-wrapper-box {
display: flex;
align-items: center;
}
.normal-wrapper-box {
position: relative;
.normal-wrapper {
position: absolute;
width: 700px;
> span:not(:first-child) {
margin-right: 18px;
}
> a {
margin-left: -10px;
}
}
button {
margin: 35px 20px 0;
}
}
.setting-wrapper {
position: relative;
.confirm-button {
margin: 11px 0 0;
}
*:not(:first-child) {
margin-right: 18px;
}
.select-schedule {
display: inline-block;
width: 100px;
}
.cron-input {
position: absolute;
display: inline-block;
width: 270px;
}
.font-style {
display: inline-block;
color: #000;
font-size: .541667rem;
}
.cron-label {
width: 195px;
}
.cron-tooltip {
color: gray;
cursor: default;
position: absolute;
.table-box {
width: 20rem;
}
}
}
.font-style {
display: inline-block;
color: #000;
font-size: .541667rem;
}
span.required {
&:after {
content: '*';
font-size: .58479532rem;
line-height: .5rem;
color: #c92100;
margin-left: .25rem;
}
span.required {
&:after {
content: '*';
font-size: .58479532rem;
line-height: .5rem;
color: #c92100;
margin-left: .25rem;
}
}

View File

@ -28,7 +28,7 @@ export class CronScheduleComponent implements OnChanges {
@Input() labelEdit: string;
@Input() labelCurrent: string;
@Input() disabled: boolean;
@Input() buttonMarginLeft: string = '200px';
@Input() labelWidth: string = '200px';
dateInvalid: boolean;
originScheduleType: string;
oriCron: string;

View File

@ -33,7 +33,7 @@
<div *ngSwitchCase="'unknown' || ''"><clr-icon shape="exclamation-triangle" class="is-warning text-alignment" size="22"></clr-icon> Unknown</div>
</clr-dg-cell>
<clr-dg-cell class="flex-min-width">{{t.url}}</clr-dg-cell>
<clr-dg-cell>{{t.type}}</clr-dg-cell>
<clr-dg-cell>{{getAdapterText(t.type)}}</clr-dg-cell>
<clr-dg-cell>
{{!t.insecure}}
</clr-dg-cell>

View File

@ -234,4 +234,8 @@ export class EndpointComponent implements OnInit, OnDestroy {
}
}, duration);
}
getAdapterText(adapter: string): string {
return this.endpointService.getAdapterText(adapter);
}
}

View File

@ -6,8 +6,7 @@
.filter-divider {
display: inline-block;
height: 16px;
width: 2px;
background-color: #cccccc;
width: 1px;
padding-top: 12px;
padding-bottom: 12px;
position: relative;
@ -26,4 +25,4 @@
.filter-input {
padding-left: 15px;
}
}

View File

@ -121,16 +121,17 @@
<li *ngIf="systemWhitelist?.items?.length<1" class="none">{{'CVE_WHITELIST.NONE'|translate}}
</li>
<li *ngFor="let item of systemWhitelist?.items">
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
<a href="javascript:void(0)" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</a>
</li>
</ul>
<ul class="whitelist-window" *ngIf="!isUseSystemWhitelist()">
<li class="none" *ngIf="projectWhitelist?.items?.length<1">
{{'CVE_WHITELIST.NONE'|translate}}</li>
<li *ngFor="let item of projectWhitelist?.items;let i = index;">
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
<clr-icon (click)="deleteItem(i)" class="float-lg-right margin-top-4"
shape="times-circle"></clr-icon>
<a href="javascript:void(0)" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</a>
<a class="float-lg-right" href="javascript:void(0)" (click)="deleteItem(i)">
<clr-icon shape="times-circle"></clr-icon>
</a>
</li>
</ul>
</div>

View File

@ -16,7 +16,6 @@
padding: 12px;
height: 224px;
width: 270px;
color: #0079bb;
overflow-y: auto;
li {

View File

@ -12,6 +12,22 @@ import { RequestQueryParams } from "./RequestQueryParams";
import { Endpoint, ReplicationRule, PingEndpoint } from "./interface";
import { catchError, map } from "rxjs/operators";
const ADAPTERS_MAP = {
"ali-acr": "Alibaba ACR",
"aws-ecr": "Aws ECR",
"azure-acr": "Azure ACR",
"docker-hub": "Docker Hub",
"docker-registry": "Docker Registry",
"gitlab": "Gitlab",
"google-gcr": "Google GCR",
"harbor": "Harbor",
"helm-hub": "Helm Hub",
"huawei-SWR": "Huawei SWR",
"jfrog-artifactory": "jFrog Artifactory",
"quay-io": "Quay.io"
};
/**
* Define the service methods to handle the endpoint related things.
@ -125,6 +141,8 @@ export abstract class EndpointService {
abstract getEndpointWithReplicationRules(
endpointId: number | string
): Observable<any>;
abstract getAdapterText(adapter: string): string;
}
/**
@ -248,4 +266,11 @@ export class EndpointDefaultService extends EndpointService {
.pipe(map(response => response as ReplicationRule[])
, catchError(error => observableThrowError(error)));
}
getAdapterText(adapter: string): string {
if (ADAPTERS_MAP && ADAPTERS_MAP[adapter]) {
return ADAPTERS_MAP[adapter];
}
return adapter;
}
}