mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-23 00:57:44 +01:00
Update for UX issues.
This commit is contained in:
parent
08d30777ad
commit
00bd8f3194
@ -33,9 +33,10 @@ func initRouters() {
|
||||
beego.Router("/", &controllers.IndexController{})
|
||||
beego.Router("/sign-in", &controllers.IndexController{})
|
||||
beego.Router("/sign-up", &controllers.IndexController{})
|
||||
beego.Router("/password-reset", &controllers.IndexController{})
|
||||
beego.Router("/reset_password", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/harbor", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/harbor/sign-in", &controllers.IndexController{})
|
||||
beego.Router("/harbor/sign-up", &controllers.IndexController{})
|
||||
beego.Router("/harbor/dashboard", &controllers.IndexController{})
|
||||
|
@ -1,6 +1,7 @@
|
||||
.inline-help-public {
|
||||
color: #CCCCCC;
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
letter-spacing: 0.01em;
|
||||
margin-top: 0;
|
||||
padding: 0 14px;
|
||||
|
@ -46,7 +46,11 @@ export class DestinationComponent implements OnInit {
|
||||
this.reload();
|
||||
},
|
||||
error => {
|
||||
this.messageHandlerService.handleError(error);
|
||||
if(error && error.status === 412) {
|
||||
this.messageHandlerService.showError('DESTINATION.FAILED_TO_DELETE_TARGET_IN_USED', '');
|
||||
} else {
|
||||
this.messageHandlerService.handleError(error);
|
||||
}
|
||||
console.log('Failed to delete target with ID:' + targetId + ', error:' + error);
|
||||
});
|
||||
}
|
||||
|
@ -19,12 +19,6 @@ export class ListJobComponent {
|
||||
|
||||
refresh(state: State) {
|
||||
if(this.jobs) {
|
||||
for(let i = 0; i < this.jobs.length; i++) {
|
||||
let j = this.jobs[i];
|
||||
if(j.status === 'retrying' || j.status === 'error') {
|
||||
this.messageHandlerService.showError('REPLICATION.FOUND_ERROR_IN_JOBS', '');
|
||||
}
|
||||
}
|
||||
this.paginate.emit(state);
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +126,18 @@ export class ReplicationComponent implements OnInit {
|
||||
|
||||
openModal(): void {
|
||||
console.log('Open modal to create policy.');
|
||||
this.createEditPolicyComponent.openCreateEditPolicy();
|
||||
this.createEditPolicyComponent.openCreateEditPolicy(true);
|
||||
}
|
||||
|
||||
openEditPolicy(policyId: number) {
|
||||
console.log('Open modal to edit policy ID:' + policyId);
|
||||
this.createEditPolicyComponent.openCreateEditPolicy(policyId);
|
||||
openEditPolicy(policy: Policy) {
|
||||
if(policy) {
|
||||
console.log('Open modal to edit policy ID:' + policy.id);
|
||||
let editable = true;
|
||||
if(policy.enabled === 1) {
|
||||
editable = false;
|
||||
}
|
||||
this.createEditPolicyComponent.openCreateEditPolicy(editable, policy.id);
|
||||
}
|
||||
}
|
||||
|
||||
fetchPolicyJobs(state?: State) {
|
||||
@ -148,6 +154,14 @@ export class ReplicationComponent implements OnInit {
|
||||
this.jobsTotalPage = Math.ceil(this.jobsTotalRecordCount / this.search.pageSize);
|
||||
this.changedJobs = response.json();
|
||||
this.jobs = this.changedJobs;
|
||||
for(let i = 0; i < this.jobs.length; i++) {
|
||||
let j = this.jobs[i];
|
||||
if(j.status == 'retrying' || j.status == 'error') {
|
||||
console.log('Error in jobs were found.')
|
||||
this.messageHandlerService.showError('REPLICATION.FOUND_ERROR_IN_JOBS', '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
error=>this.messageHandlerService.handleError(error)
|
||||
);
|
||||
|
@ -48,9 +48,15 @@ export class TotalReplicationComponent implements OnInit {
|
||||
this.retrievePolicies();
|
||||
}
|
||||
|
||||
openEditPolicy(policyId: number) {
|
||||
console.log('Open modal to edit policy ID:' + policyId);
|
||||
this.createEditPolicyComponent.openCreateEditPolicy(policyId);
|
||||
openEditPolicy(policy: Policy) {
|
||||
if(policy) {
|
||||
console.log('Open modal to edit policy ID:' + policy.id);
|
||||
let editable = true;
|
||||
if(policy.enabled === 1) {
|
||||
editable = false;
|
||||
}
|
||||
this.createEditPolicyComponent.openCreateEditPolicy(editable, policy.id);
|
||||
}
|
||||
}
|
||||
|
||||
selectPolicy(policy: Policy) {
|
||||
|
@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</clr-modal>
|
||||
|
||||
<h2 class="sub-header-title">{{repoName}} <span class="badge">{{tags ? tags.length : 0}}</span></h2>
|
||||
<h2 class="sub-header-title">{{repoName}}</h2>
|
||||
<clr-datagrid>
|
||||
<clr-dg-column>{{'REPOSITORY.TAG' | translate}}</clr-dg-column>
|
||||
<clr-dg-column>{{'REPOSITORY.PULL_COMMAND' | translate}}</clr-dg-column>
|
||||
|
@ -62,7 +62,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
||||
&& message.state === ConfirmationState.CONFIRMED) {
|
||||
let tag = message.data;
|
||||
if (tag) {
|
||||
if (tag.verified) {
|
||||
if (tag.signed) {
|
||||
return;
|
||||
} else {
|
||||
let tagName = tag.tag;
|
||||
@ -139,15 +139,17 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
||||
|
||||
deleteTag(tag: TagView) {
|
||||
if (tag) {
|
||||
let titleKey: string, summaryKey: string, content: string;
|
||||
let titleKey: string, summaryKey: string, content: string, confirmOnly: boolean;
|
||||
if (tag.signed) {
|
||||
titleKey = 'REPOSITORY.DELETION_TITLE_TAG_DENIED';
|
||||
summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG_DENIED';
|
||||
confirmOnly = true;
|
||||
content = 'notary -s https://' + this.registryUrl + ' -d ~/.docker/trust remove -p ' + this.registryUrl + '/' + this.repoName + ':' + tag.tag;
|
||||
} else {
|
||||
titleKey = 'REPOSITORY.DELETION_TITLE_TAG';
|
||||
summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG';
|
||||
content = tag.tag;
|
||||
confirmOnly = false;
|
||||
}
|
||||
let message = new ConfirmationMessage(
|
||||
titleKey,
|
||||
@ -155,6 +157,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
||||
content,
|
||||
tag,
|
||||
ConfirmationTargets.TAG);
|
||||
message.confirmOnly = confirmOnly;
|
||||
this.deletionDialogService.openComfirmDialog(message);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="confirmation-content">{{dialogContent}}</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="cancel()">{{'BUTTON.NO' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" *ngIf="!confirmOnly" (click)="cancel()">{{'BUTTON.NO' | translate}}</button>
|
||||
<button type="button" class="btn btn-primary" (click)="confirm()">{{'BUTTON.YES' | translate}}</button>
|
||||
</div>
|
||||
</clr-modal>
|
@ -17,6 +17,7 @@ export class ConfirmationDialogComponent implements OnDestroy {
|
||||
opened: boolean = false;
|
||||
dialogTitle: string = "";
|
||||
dialogContent: string = "";
|
||||
confirmOnly: boolean = false;
|
||||
message: ConfirmationMessage;
|
||||
private annouceSubscription: Subscription;
|
||||
|
||||
@ -27,7 +28,7 @@ export class ConfirmationDialogComponent implements OnDestroy {
|
||||
this.dialogTitle = msg.title;
|
||||
this.dialogContent = msg.message;
|
||||
this.message = msg;
|
||||
|
||||
this.confirmOnly = this.message.confirmOnly;
|
||||
this.translate.get(this.dialogTitle).subscribe((res: string) => this.dialogTitle = res);
|
||||
this.translate.get(this.dialogContent, { 'param': msg.param }).subscribe((res: string) => this.dialogContent = res);
|
||||
//Open dialog
|
||||
|
@ -13,4 +13,5 @@ export class ConfirmationMessage {
|
||||
data: any = {};//default is empty
|
||||
targetId: ConfirmationTargets = ConfirmationTargets.EMPTY;
|
||||
param: string;
|
||||
confirmOnly: boolean;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<div class="modal-body" style="max-height: 85vh;">
|
||||
<form #policyForm="ngForm">
|
||||
<section class="form-block">
|
||||
<div class="alert alert-warning" *ngIf="readonly">
|
||||
<div class="alert alert-warning" *ngIf="!editable">
|
||||
<div class="alert-item">
|
||||
<span class="alert-text">
|
||||
{{'REPLICATION.CANNOT_EDIT' | translate}}
|
||||
@ -77,6 +77,6 @@
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" (click)="testConnection()" [disabled]="testOngoing">{{'REPLICATION.TEST_CONNECTION' | translate}}</button>
|
||||
<button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | translate }}</button>
|
||||
<button type="submit" class="btn btn-primary" [disabled]="!policyForm.form.valid || testOngoing || readonly" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button>
|
||||
<button type="submit" class="btn btn-primary" [disabled]="!policyForm.form.valid || testOngoing || !editable" (click)="onSubmit()">{{'BUTTON.OK' | translate}}</button>
|
||||
</div>
|
||||
</clr-modal>
|
@ -50,6 +50,8 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
hasChanged: boolean;
|
||||
|
||||
editable: boolean;
|
||||
|
||||
@ViewChild(InlineAlertComponent)
|
||||
inlineAlert: InlineAlertComponent;
|
||||
|
||||
@ -100,10 +102,12 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
openCreateEditPolicy(policyId?: number): void {
|
||||
openCreateEditPolicy(editable: boolean, policyId?: number): void {
|
||||
this.createEditPolicyOpened = true;
|
||||
this.createEditPolicy = new CreateEditPolicy();
|
||||
|
||||
this.editable = editable;
|
||||
|
||||
this.isCreateDestination = false;
|
||||
|
||||
this.hasChanged = false;
|
||||
@ -114,7 +118,7 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
if(policyId) {
|
||||
this.actionType = ActionType.EDIT;
|
||||
this.translateService.get('REPLICATION.EDIT_POLICY').subscribe(res=>this.modalTitle=res);
|
||||
this.translateService.get('REPLICATION.EDIT_POLICY_TITLE').subscribe(res=>this.modalTitle=res);
|
||||
this.replicationService
|
||||
.getPolicy(policyId)
|
||||
.subscribe(
|
||||
|
@ -8,7 +8,7 @@
|
||||
<clr-dg-row *ngFor="let p of policies;let i = index;" [clrDgItem]="p" (click)="selectPolicy(p)" [style.backgroundColor]="(!projectless && selectedId === p.id) ? '#eee' : ''">
|
||||
<clr-dg-action-overflow>
|
||||
<button class="action-item" (click)="editPolicy(p)">{{'REPLICATION.EDIT_POLICY' | translate}}</button>
|
||||
<button class="action-item" (click)="togglePolicy(p)">{{ (p.enabled === 0 ? 'REPLICATION.TOGGLE_ENABLE_TITLE' : 'REPLICATION.TOGGLE_DISABLE_TITLE') | translate}}</button>
|
||||
<button class="action-item" (click)="togglePolicy(p)">{{ (p.enabled === 0 ? 'REPLICATION.ENABLE' : 'REPLICATION.DISABLE') | translate}}</button>
|
||||
<button class="action-item" (click)="deletePolicy(p)">{{'REPLICATION.DELETE_POLICY' | translate}}</button>
|
||||
</clr-dg-action-overflow>
|
||||
<clr-dg-cell>
|
||||
|
@ -26,7 +26,7 @@ export class ListPolicyComponent implements OnDestroy {
|
||||
|
||||
@Output() reload = new EventEmitter<boolean>();
|
||||
@Output() selectOne = new EventEmitter<Policy>();
|
||||
@Output() editOne = new EventEmitter<number>();
|
||||
@Output() editOne = new EventEmitter<Policy>();
|
||||
@Output() toggleOne = new EventEmitter<Policy>();
|
||||
|
||||
toggleSubscription: Subscription;
|
||||
@ -106,7 +106,7 @@ export class ListPolicyComponent implements OnDestroy {
|
||||
|
||||
editPolicy(policy: Policy) {
|
||||
console.log('Open modal to edit policy.');
|
||||
this.editOne.emit(policy.id);
|
||||
this.editOne.emit(policy);
|
||||
}
|
||||
|
||||
togglePolicy(policy: Policy) {
|
||||
|
@ -210,8 +210,9 @@
|
||||
"DELETION_TITLE_TARGET": "Confirm Endpoint Deletion",
|
||||
"DELETION_SUMMARY_TARGET": "Do you want to delete the endpoint {{param}}?",
|
||||
"ADD_POLICY": "New Replication Rule",
|
||||
"EDIT_POLICY": "Edit Replication Rule",
|
||||
"DELETE_POLICY": "Delete Replication Rule",
|
||||
"EDIT_POLICY": "Edit",
|
||||
"EDIT_POLICY_TITLE": "Edit Replication Rule",
|
||||
"DELETE_POLICY": "Delete",
|
||||
"TEST_CONNECTION": "Test Connection",
|
||||
"TESTING_CONNECTION": "Testing Connection...",
|
||||
"TEST_CONNECTION_SUCCESS": "Connection tested successfully.",
|
||||
@ -252,9 +253,9 @@
|
||||
"LOGS": "Logs",
|
||||
"ITEMS": "item(s)",
|
||||
"TOGGLE_ENABLE_TITLE": "Enable Rule",
|
||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project \nwill be replicated to the destination registry. \nPlease confirm to continue.",
|
||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. \nPlease confirm to continue.",
|
||||
"TOGGLE_DISABLE_TITLE": "Disable Rule",
|
||||
"CONFIRM_TOGGLE_DISABLE_POLICY": "After disabling the rule, all unfinished replication jobs of this rule \nwill be stopped and canceled. \nPlease confirm to continue.",
|
||||
"CONFIRM_TOGGLE_DISABLE_POLICY": "After disabling the rule, all unfinished replication jobs of this rule will be stopped and canceled. \nPlease confirm to continue.",
|
||||
"CREATED_SUCCESS": "Created replication rule successfully.",
|
||||
"UPDATED_SUCCESS": "Updated replication rule successfully.",
|
||||
"DELETED_SUCCESS": "Deleted replication rule successfully.",
|
||||
@ -290,7 +291,8 @@
|
||||
"UPDATED_SUCCESS": "Updated endpoint successfully.",
|
||||
"DELETED_SUCCESS": "Deleted endpoint successfully.",
|
||||
"DELETED_FAILED": "Deleted endpoint failed.",
|
||||
"CANNOT_EDIT": "Endpoint cannot be changed while the replication rule is enabled."
|
||||
"CANNOT_EDIT": "Endpoint cannot be changed while the replication rule is enabled.",
|
||||
"FAILED_TO_DELETE_TARGET_IN_USED": "Failed to delete endpoint in which being used."
|
||||
},
|
||||
"REPOSITORY": {
|
||||
"COPY_ID": "Copy ID",
|
||||
@ -307,7 +309,7 @@
|
||||
"DELETION_TITLE_TAG": "Confirm Tag Deletion",
|
||||
"DELETION_SUMMARY_TAG": "Do you want to delete tag {{param}}?",
|
||||
"DELETION_TITLE_TAG_DENIED": "Signed Tag can't be deleted",
|
||||
"DELETION_SUMMARY_TAG_DENIED": "The tag must be removed from the Notary before it can be deleted. {{param}}",
|
||||
"DELETION_SUMMARY_TAG_DENIED": "The tag must be removed from the Notary before it can be deleted.\nDelete from Notary via this command:\n {{param}}",
|
||||
"FILTER_FOR_REPOSITORIES": "Filter Repositories",
|
||||
"TAG": "Tag",
|
||||
"SIGNED": "Signed",
|
||||
|
@ -210,8 +210,9 @@
|
||||
"DELETION_TITLE_TARGET": "删除目标确认",
|
||||
"DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?",
|
||||
"ADD_POLICY": "新建规则",
|
||||
"EDIT_POLICY": "修改规则",
|
||||
"DELETE_POLICY": "删除规则",
|
||||
"EDIT_POLICY": "修改",
|
||||
"EDIT_POLICY_TITLE": "修改规则",
|
||||
"DELETE_POLICY": "删除",
|
||||
"TEST_CONNECTION": "测试连接",
|
||||
"TESTING_CONNECTION": "正在测试连接...",
|
||||
"TEST_CONNECTION_SUCCESS": "测试连接成功。",
|
||||
@ -252,9 +253,9 @@
|
||||
"LOGS": "日志",
|
||||
"ITEMS": "条记录",
|
||||
"TOGGLE_ENABLE_TITLE": "启用规则",
|
||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。请确认继续。",
|
||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。\n请确认继续。",
|
||||
"TOGGLE_DISABLE_TITLE": "停用规则",
|
||||
"CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。请确认继续。",
|
||||
"CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。\n请确认继续。",
|
||||
"CREATED_SUCCESS": "创建复制规则成功。",
|
||||
"UPDATED_SUCCESS": "更新复制规则成功。",
|
||||
"DELETED_SUCCESS": "删除复制规则成功。",
|
||||
@ -290,7 +291,8 @@
|
||||
"UPDATED_SUCCESS": "更新目标成功。",
|
||||
"DELETED_SUCCESS": "删除目标成功。",
|
||||
"DELETED_FAILED": "删除目标失败。",
|
||||
"CANNOT_EDIT": "当复制规则启用时目标无法修改。"
|
||||
"CANNOT_EDIT": "当复制规则启用时目标无法修改。",
|
||||
"FAILED_TO_DELETE_TARGET_IN_USED": "无法删除正在使用的目标。"
|
||||
},
|
||||
"REPOSITORY": {
|
||||
"COPY_ID": "复制ID",
|
||||
@ -307,7 +309,7 @@
|
||||
"DELETION_TITLE_TAG": "删除镜像标签确认",
|
||||
"DELETION_SUMMARY_TAG": "确认删除镜像标签 {{param}}?",
|
||||
"DELETION_TITLE_TAG_DENIED": "已签名的镜像不能被删除",
|
||||
"DELETION_SUMMARY_TAG_DENIED": "要删除此镜像标签必须首先从Notary中删除。{{param}}",
|
||||
"DELETION_SUMMARY_TAG_DENIED": "要删除此镜像标签必须首先从Notary中删除。\n请执行如下Notary命令删除:\n{{param}}",
|
||||
"FILTER_FOR_REPOSITORIES": "过滤镜像仓库",
|
||||
"TAG": "标签",
|
||||
"SIGNED": "已签名",
|
||||
|
Loading…
Reference in New Issue
Block a user