Update for UX issues.

This commit is contained in:
kunw 2017-03-31 00:51:03 +08:00
parent 08d30777ad
commit 00bd8f3194
17 changed files with 73 additions and 40 deletions

View File

@ -33,9 +33,10 @@ func initRouters() {
beego.Router("/", &controllers.IndexController{}) beego.Router("/", &controllers.IndexController{})
beego.Router("/sign-in", &controllers.IndexController{}) beego.Router("/sign-in", &controllers.IndexController{})
beego.Router("/sign-up", &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", &controllers.IndexController{})
beego.Router("/harbor/sign-in", &controllers.IndexController{}) beego.Router("/harbor/sign-in", &controllers.IndexController{})
beego.Router("/harbor/sign-up", &controllers.IndexController{}) beego.Router("/harbor/sign-up", &controllers.IndexController{})
beego.Router("/harbor/dashboard", &controllers.IndexController{}) beego.Router("/harbor/dashboard", &controllers.IndexController{})

View File

@ -1,6 +1,7 @@
.inline-help-public { .inline-help-public {
color: #CCCCCC; color: #CCCCCC;
font-size: 12px; font-size: 12px;
line-height: 1.5em;
letter-spacing: 0.01em; letter-spacing: 0.01em;
margin-top: 0; margin-top: 0;
padding: 0 14px; padding: 0 14px;

View File

@ -46,7 +46,11 @@ export class DestinationComponent implements OnInit {
this.reload(); this.reload();
}, },
error => { 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); console.log('Failed to delete target with ID:' + targetId + ', error:' + error);
}); });
} }

View File

@ -19,12 +19,6 @@ export class ListJobComponent {
refresh(state: State) { refresh(state: State) {
if(this.jobs) { 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); this.paginate.emit(state);
} }
} }

View File

@ -126,12 +126,18 @@ export class ReplicationComponent implements OnInit {
openModal(): void { openModal(): void {
console.log('Open modal to create policy.'); console.log('Open modal to create policy.');
this.createEditPolicyComponent.openCreateEditPolicy(); this.createEditPolicyComponent.openCreateEditPolicy(true);
} }
openEditPolicy(policyId: number) { openEditPolicy(policy: Policy) {
console.log('Open modal to edit policy ID:' + policyId); if(policy) {
this.createEditPolicyComponent.openCreateEditPolicy(policyId); 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) { fetchPolicyJobs(state?: State) {
@ -148,6 +154,14 @@ export class ReplicationComponent implements OnInit {
this.jobsTotalPage = Math.ceil(this.jobsTotalRecordCount / this.search.pageSize); this.jobsTotalPage = Math.ceil(this.jobsTotalRecordCount / this.search.pageSize);
this.changedJobs = response.json(); this.changedJobs = response.json();
this.jobs = this.changedJobs; 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) error=>this.messageHandlerService.handleError(error)
); );

View File

@ -48,9 +48,15 @@ export class TotalReplicationComponent implements OnInit {
this.retrievePolicies(); this.retrievePolicies();
} }
openEditPolicy(policyId: number) { openEditPolicy(policy: Policy) {
console.log('Open modal to edit policy ID:' + policyId); if(policy) {
this.createEditPolicyComponent.openCreateEditPolicy(policyId); 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) { selectPolicy(policy: Policy) {

View File

@ -14,7 +14,7 @@
</div> </div>
</clr-modal> </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-datagrid>
<clr-dg-column>{{'REPOSITORY.TAG' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.TAG' | translate}}</clr-dg-column>
<clr-dg-column>{{'REPOSITORY.PULL_COMMAND' | translate}}</clr-dg-column> <clr-dg-column>{{'REPOSITORY.PULL_COMMAND' | translate}}</clr-dg-column>

View File

@ -62,7 +62,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
&& message.state === ConfirmationState.CONFIRMED) { && message.state === ConfirmationState.CONFIRMED) {
let tag = message.data; let tag = message.data;
if (tag) { if (tag) {
if (tag.verified) { if (tag.signed) {
return; return;
} else { } else {
let tagName = tag.tag; let tagName = tag.tag;
@ -139,15 +139,17 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
deleteTag(tag: TagView) { deleteTag(tag: TagView) {
if (tag) { if (tag) {
let titleKey: string, summaryKey: string, content: string; let titleKey: string, summaryKey: string, content: string, confirmOnly: boolean;
if (tag.signed) { if (tag.signed) {
titleKey = 'REPOSITORY.DELETION_TITLE_TAG_DENIED'; titleKey = 'REPOSITORY.DELETION_TITLE_TAG_DENIED';
summaryKey = 'REPOSITORY.DELETION_SUMMARY_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; content = 'notary -s https://' + this.registryUrl + ' -d ~/.docker/trust remove -p ' + this.registryUrl + '/' + this.repoName + ':' + tag.tag;
} else { } else {
titleKey = 'REPOSITORY.DELETION_TITLE_TAG'; titleKey = 'REPOSITORY.DELETION_TITLE_TAG';
summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG'; summaryKey = 'REPOSITORY.DELETION_SUMMARY_TAG';
content = tag.tag; content = tag.tag;
confirmOnly = false;
} }
let message = new ConfirmationMessage( let message = new ConfirmationMessage(
titleKey, titleKey,
@ -155,6 +157,7 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
content, content,
tag, tag,
ConfirmationTargets.TAG); ConfirmationTargets.TAG);
message.confirmOnly = confirmOnly;
this.deletionDialogService.openComfirmDialog(message); this.deletionDialogService.openComfirmDialog(message);
} }
} }

View File

@ -7,7 +7,7 @@
<div class="confirmation-content">{{dialogContent}}</div> <div class="confirmation-content">{{dialogContent}}</div>
</div> </div>
<div class="modal-footer"> <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> <button type="button" class="btn btn-primary" (click)="confirm()">{{'BUTTON.YES' | translate}}</button>
</div> </div>
</clr-modal> </clr-modal>

View File

@ -17,6 +17,7 @@ export class ConfirmationDialogComponent implements OnDestroy {
opened: boolean = false; opened: boolean = false;
dialogTitle: string = ""; dialogTitle: string = "";
dialogContent: string = ""; dialogContent: string = "";
confirmOnly: boolean = false;
message: ConfirmationMessage; message: ConfirmationMessage;
private annouceSubscription: Subscription; private annouceSubscription: Subscription;
@ -27,7 +28,7 @@ export class ConfirmationDialogComponent implements OnDestroy {
this.dialogTitle = msg.title; this.dialogTitle = msg.title;
this.dialogContent = msg.message; this.dialogContent = msg.message;
this.message = msg; this.message = msg;
this.confirmOnly = this.message.confirmOnly;
this.translate.get(this.dialogTitle).subscribe((res: string) => this.dialogTitle = res); 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); this.translate.get(this.dialogContent, { 'param': msg.param }).subscribe((res: string) => this.dialogContent = res);
//Open dialog //Open dialog

View File

@ -13,4 +13,5 @@ export class ConfirmationMessage {
data: any = {};//default is empty data: any = {};//default is empty
targetId: ConfirmationTargets = ConfirmationTargets.EMPTY; targetId: ConfirmationTargets = ConfirmationTargets.EMPTY;
param: string; param: string;
confirmOnly: boolean;
} }

View File

@ -4,7 +4,7 @@
<div class="modal-body" style="max-height: 85vh;"> <div class="modal-body" style="max-height: 85vh;">
<form #policyForm="ngForm"> <form #policyForm="ngForm">
<section class="form-block"> <section class="form-block">
<div class="alert alert-warning" *ngIf="readonly"> <div class="alert alert-warning" *ngIf="!editable">
<div class="alert-item"> <div class="alert-item">
<span class="alert-text"> <span class="alert-text">
{{'REPLICATION.CANNOT_EDIT' | translate}} {{'REPLICATION.CANNOT_EDIT' | translate}}
@ -77,6 +77,6 @@
<div class="modal-footer"> <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)="testConnection()" [disabled]="testOngoing">{{'REPLICATION.TEST_CONNECTION' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="onCancel()">{{'BUTTON.CANCEL' | 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> </div>
</clr-modal> </clr-modal>

View File

@ -50,6 +50,8 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
hasChanged: boolean; hasChanged: boolean;
editable: boolean;
@ViewChild(InlineAlertComponent) @ViewChild(InlineAlertComponent)
inlineAlert: InlineAlertComponent; inlineAlert: InlineAlertComponent;
@ -100,10 +102,12 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
ngOnInit(): void {} ngOnInit(): void {}
openCreateEditPolicy(policyId?: number): void { openCreateEditPolicy(editable: boolean, policyId?: number): void {
this.createEditPolicyOpened = true; this.createEditPolicyOpened = true;
this.createEditPolicy = new CreateEditPolicy(); this.createEditPolicy = new CreateEditPolicy();
this.editable = editable;
this.isCreateDestination = false; this.isCreateDestination = false;
this.hasChanged = false; this.hasChanged = false;
@ -114,7 +118,7 @@ export class CreateEditPolicyComponent implements OnInit, AfterViewChecked {
if(policyId) { if(policyId) {
this.actionType = ActionType.EDIT; 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 this.replicationService
.getPolicy(policyId) .getPolicy(policyId)
.subscribe( .subscribe(

View File

@ -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-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> <clr-dg-action-overflow>
<button class="action-item" (click)="editPolicy(p)">{{'REPLICATION.EDIT_POLICY' | translate}}</button> <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> <button class="action-item" (click)="deletePolicy(p)">{{'REPLICATION.DELETE_POLICY' | translate}}</button>
</clr-dg-action-overflow> </clr-dg-action-overflow>
<clr-dg-cell> <clr-dg-cell>

View File

@ -26,7 +26,7 @@ export class ListPolicyComponent implements OnDestroy {
@Output() reload = new EventEmitter<boolean>(); @Output() reload = new EventEmitter<boolean>();
@Output() selectOne = new EventEmitter<Policy>(); @Output() selectOne = new EventEmitter<Policy>();
@Output() editOne = new EventEmitter<number>(); @Output() editOne = new EventEmitter<Policy>();
@Output() toggleOne = new EventEmitter<Policy>(); @Output() toggleOne = new EventEmitter<Policy>();
toggleSubscription: Subscription; toggleSubscription: Subscription;
@ -106,7 +106,7 @@ export class ListPolicyComponent implements OnDestroy {
editPolicy(policy: Policy) { editPolicy(policy: Policy) {
console.log('Open modal to edit policy.'); console.log('Open modal to edit policy.');
this.editOne.emit(policy.id); this.editOne.emit(policy);
} }
togglePolicy(policy: Policy) { togglePolicy(policy: Policy) {

View File

@ -210,8 +210,9 @@
"DELETION_TITLE_TARGET": "Confirm Endpoint Deletion", "DELETION_TITLE_TARGET": "Confirm Endpoint Deletion",
"DELETION_SUMMARY_TARGET": "Do you want to delete the endpoint {{param}}?", "DELETION_SUMMARY_TARGET": "Do you want to delete the endpoint {{param}}?",
"ADD_POLICY": "New Replication Rule", "ADD_POLICY": "New Replication Rule",
"EDIT_POLICY": "Edit Replication Rule", "EDIT_POLICY": "Edit",
"DELETE_POLICY": "Delete Replication Rule", "EDIT_POLICY_TITLE": "Edit Replication Rule",
"DELETE_POLICY": "Delete",
"TEST_CONNECTION": "Test Connection", "TEST_CONNECTION": "Test Connection",
"TESTING_CONNECTION": "Testing Connection...", "TESTING_CONNECTION": "Testing Connection...",
"TEST_CONNECTION_SUCCESS": "Connection tested successfully.", "TEST_CONNECTION_SUCCESS": "Connection tested successfully.",
@ -252,9 +253,9 @@
"LOGS": "Logs", "LOGS": "Logs",
"ITEMS": "item(s)", "ITEMS": "item(s)",
"TOGGLE_ENABLE_TITLE": "Enable Rule", "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", "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.", "CREATED_SUCCESS": "Created replication rule successfully.",
"UPDATED_SUCCESS": "Updated replication rule successfully.", "UPDATED_SUCCESS": "Updated replication rule successfully.",
"DELETED_SUCCESS": "Deleted replication rule successfully.", "DELETED_SUCCESS": "Deleted replication rule successfully.",
@ -290,7 +291,8 @@
"UPDATED_SUCCESS": "Updated endpoint successfully.", "UPDATED_SUCCESS": "Updated endpoint successfully.",
"DELETED_SUCCESS": "Deleted endpoint successfully.", "DELETED_SUCCESS": "Deleted endpoint successfully.",
"DELETED_FAILED": "Deleted endpoint failed.", "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": { "REPOSITORY": {
"COPY_ID": "Copy ID", "COPY_ID": "Copy ID",
@ -307,7 +309,7 @@
"DELETION_TITLE_TAG": "Confirm Tag Deletion", "DELETION_TITLE_TAG": "Confirm Tag Deletion",
"DELETION_SUMMARY_TAG": "Do you want to delete tag {{param}}?", "DELETION_SUMMARY_TAG": "Do you want to delete tag {{param}}?",
"DELETION_TITLE_TAG_DENIED": "Signed Tag can't be deleted", "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", "FILTER_FOR_REPOSITORIES": "Filter Repositories",
"TAG": "Tag", "TAG": "Tag",
"SIGNED": "Signed", "SIGNED": "Signed",

View File

@ -210,8 +210,9 @@
"DELETION_TITLE_TARGET": "删除目标确认", "DELETION_TITLE_TARGET": "删除目标确认",
"DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?", "DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?",
"ADD_POLICY": "新建规则", "ADD_POLICY": "新建规则",
"EDIT_POLICY": "修改规则", "EDIT_POLICY": "修改",
"DELETE_POLICY": "删除规则", "EDIT_POLICY_TITLE": "修改规则",
"DELETE_POLICY": "删除",
"TEST_CONNECTION": "测试连接", "TEST_CONNECTION": "测试连接",
"TESTING_CONNECTION": "正在测试连接...", "TESTING_CONNECTION": "正在测试连接...",
"TEST_CONNECTION_SUCCESS": "测试连接成功。", "TEST_CONNECTION_SUCCESS": "测试连接成功。",
@ -252,9 +253,9 @@
"LOGS": "日志", "LOGS": "日志",
"ITEMS": "条记录", "ITEMS": "条记录",
"TOGGLE_ENABLE_TITLE": "启用规则", "TOGGLE_ENABLE_TITLE": "启用规则",
"CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。请确认继续。", "CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。\n请确认继续。",
"TOGGLE_DISABLE_TITLE": "停用规则", "TOGGLE_DISABLE_TITLE": "停用规则",
"CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。请确认继续。", "CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。\n请确认继续。",
"CREATED_SUCCESS": "创建复制规则成功。", "CREATED_SUCCESS": "创建复制规则成功。",
"UPDATED_SUCCESS": "更新复制规则成功。", "UPDATED_SUCCESS": "更新复制规则成功。",
"DELETED_SUCCESS": "删除复制规则成功。", "DELETED_SUCCESS": "删除复制规则成功。",
@ -290,7 +291,8 @@
"UPDATED_SUCCESS": "更新目标成功。", "UPDATED_SUCCESS": "更新目标成功。",
"DELETED_SUCCESS": "删除目标成功。", "DELETED_SUCCESS": "删除目标成功。",
"DELETED_FAILED": "删除目标失败。", "DELETED_FAILED": "删除目标失败。",
"CANNOT_EDIT": "当复制规则启用时目标无法修改。" "CANNOT_EDIT": "当复制规则启用时目标无法修改。",
"FAILED_TO_DELETE_TARGET_IN_USED": "无法删除正在使用的目标。"
}, },
"REPOSITORY": { "REPOSITORY": {
"COPY_ID": "复制ID", "COPY_ID": "复制ID",
@ -307,7 +309,7 @@
"DELETION_TITLE_TAG": "删除镜像标签确认", "DELETION_TITLE_TAG": "删除镜像标签确认",
"DELETION_SUMMARY_TAG": "确认删除镜像标签 {{param}}?", "DELETION_SUMMARY_TAG": "确认删除镜像标签 {{param}}?",
"DELETION_TITLE_TAG_DENIED": "已签名的镜像不能被删除", "DELETION_TITLE_TAG_DENIED": "已签名的镜像不能被删除",
"DELETION_SUMMARY_TAG_DENIED": "要删除此镜像标签必须首先从Notary中删除。{{param}}", "DELETION_SUMMARY_TAG_DENIED": "要删除此镜像标签必须首先从Notary中删除。\n请执行如下Notary命令删除:\n{{param}}",
"FILTER_FOR_REPOSITORIES": "过滤镜像仓库", "FILTER_FOR_REPOSITORIES": "过滤镜像仓库",
"TAG": "标签", "TAG": "标签",
"SIGNED": "已签名", "SIGNED": "已签名",