mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-22 23:51:27 +01:00
Merge pull request #1827 from wknet123/dev-revised
Updates for showing image ID and router tags.
This commit is contained in:
commit
79263a8ba7
@ -44,6 +44,7 @@ func initRouters() {
|
|||||||
beego.Router("/harbor/projects/:id/replication", &controllers.IndexController{})
|
beego.Router("/harbor/projects/:id/replication", &controllers.IndexController{})
|
||||||
beego.Router("/harbor/projects/:id/member", &controllers.IndexController{})
|
beego.Router("/harbor/projects/:id/member", &controllers.IndexController{})
|
||||||
beego.Router("/harbor/projects/:id/log", &controllers.IndexController{})
|
beego.Router("/harbor/projects/:id/log", &controllers.IndexController{})
|
||||||
|
beego.Router("/harbor/tags/:id/*", &controllers.IndexController{})
|
||||||
|
|
||||||
beego.Router("/harbor/users", &controllers.IndexController{})
|
beego.Router("/harbor/users", &controllers.IndexController{})
|
||||||
beego.Router("/harbor/logs", &controllers.IndexController{})
|
beego.Router("/harbor/logs", &controllers.IndexController{})
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
top: 60px;
|
top: 60px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
padding-left: 36px;
|
padding-left: 36px;
|
||||||
padding-right: 24px;
|
padding-right: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-header {
|
.search-header {
|
||||||
|
@ -9,4 +9,8 @@
|
|||||||
.start-content-padding {
|
.start-content-padding {
|
||||||
padding: 0px !important;
|
padding: 0px !important;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-area-override {
|
||||||
|
padding: 24px 36px !important;
|
||||||
}
|
}
|
@ -2,27 +2,27 @@
|
|||||||
<global-message [isAppLevel]="true"></global-message>
|
<global-message [isAppLevel]="true"></global-message>
|
||||||
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
|
<navigator (showAccountSettingsModal)="openModal($event)" (showPwdChangeModal)="openModal($event)"></navigator>
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="content-area" [class.container-override]="showSearch" [class.start-content-padding]="shouldOverrideContent">
|
<div class="content-area" [class.container-override]="showSearch" [class.content-area-override]="!shouldOverrideContent" [class.start-content-padding]="shouldOverrideContent">
|
||||||
<global-message [isAppLevel]="false"></global-message>
|
<global-message [isAppLevel]="false"></global-message>
|
||||||
<!-- Only appear when searching -->
|
<!-- Only appear when searching -->
|
||||||
<search-result></search-result>
|
<search-result></search-result>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<nav class="sidenav" *ngIf="isUserExisting">
|
<nav class="sidenav" style="padding: 12px 36px;" *ngIf="isUserExisting">
|
||||||
<section class="sidenav-content">
|
<section class="sidenav-content">
|
||||||
<a routerLink="/harbor/projects" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.PROJECTS' | translate}}</a>
|
<a routerLink="/harbor/projects" routerLinkActive="active" class="nav-link">{{'SIDE_NAV.PROJECTS' | translate}}</a>
|
||||||
<a routerLink="/harbor/logs" routerLinkActive="active" class="nav-link" style="margin-top: 4px;">{{'SIDE_NAV.LOGS' | translate}}</a>
|
<a routerLink="/harbor/logs" routerLinkActive="active" class="nav-link" style="margin-top: 4px;">{{'SIDE_NAV.LOGS' | translate}}</a>
|
||||||
<section class="nav-group collapsible" *ngIf="isSystemAdmin" style="margin-top: 4px;">
|
<section class="nav-group collapsible" *ngIf="isSystemAdmin" style="margin-top: 4px;">
|
||||||
<input id="tabsystem" type="checkbox">
|
<input id="tabsystem" type="checkbox">
|
||||||
<label for="tabsystem">{{'SIDE_NAV.SYSTEM_MGMT.NAME' | translate}}</label>
|
<label for="tabsystem">{{'SIDE_NAV.SYSTEM_MGMT.NAME' | translate}}</label>
|
||||||
<ul class="nav-list">
|
<ul class="nav-list">
|
||||||
<li><a class="nav-link" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
|
<li><a class="nav-link" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
|
||||||
<li><a class="nav-link" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
|
<li><a class="nav-link" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
|
||||||
<li><a class="nav-link" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
|
<li><a class="nav-link" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</clr-main-container>
|
</clr-main-container>
|
||||||
<account-settings-modal></account-settings-modal>
|
<account-settings-modal></account-settings-modal>
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
.custom-h2 {
|
.custom-h2 {
|
||||||
margin-top: 0px !important;
|
margin-top: 0px !important;
|
||||||
}
|
|
||||||
|
|
||||||
.config-container {
|
|
||||||
margin-left: 24px;
|
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
<div class="config-container">
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
<h2 style="display: inline-block;" class="custom-h2">{{'CONFIG.TITLE' | translate }}</h2>
|
<h2 style="display: inline-block;" class="custom-h2">{{'CONFIG.TITLE' | translate }}</h2>
|
||||||
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
||||||
<ul id="configTabs" class="nav" role="tablist">
|
<ul id="configTabs" class="nav" role="tablist">
|
||||||
@ -66,4 +67,5 @@
|
|||||||
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
|
<button type="button" class="btn btn-outline" (click)="testLDAPServer()" *ngIf="showLdapServerBtn" [disabled]="!isLDAPConfigValid()">{{'BUTTON.TEST_LDAP' | translate}}</button>
|
||||||
<span class="spinner spinner-inline" [hidden]="!testingInProgress"></span>
|
<span class="spinner spinner-inline" [hidden]="!testingInProgress"></span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,4 +1,4 @@
|
|||||||
<div class="row" style="margin-right: 12px;">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
<h2 class="header-title">{{'PROJECT.PROJECTS' | translate}}</h2>
|
<h2 class="header-title">{{'PROJECT.PROJECTS' | translate}}</h2>
|
||||||
<div>
|
<div>
|
||||||
|
@ -2,12 +2,19 @@
|
|||||||
<h3 class="modal-title">{{modalTitle}}</h3>
|
<h3 class="modal-title">{{modalTitle}}</h3>
|
||||||
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
|
<inline-alert class="modal-title" (confirmEvt)="confirmCancel($event)"></inline-alert>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-danger" *ngIf="!editable">
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">
|
||||||
|
{{'DESTINATION.CANNOT_EDIT' | translate}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<form #targetForm="ngForm">
|
<form #targetForm="ngForm">
|
||||||
<section class="form-block">
|
<section class="form-block">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="destination_name" class="col-md-4 form-group-label-override">{{ 'DESTINATION.NAME' | translate }}<span style="color: red">*</span></label>
|
<label for="destination_name" class="col-md-4 form-group-label-override">{{ 'DESTINATION.NAME' | translate }}<span style="color: red">*</span></label>
|
||||||
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)" [class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
||||||
<input type="text" id="destination_name" [disabled]="testOngoing" [(ngModel)]="target.name" name="targetName" size="20" #targetName="ngModel" value="" required>
|
<input type="text" id="destination_name" [disabled]="testOngoing || !editable" [(ngModel)]="target.name" name="targetName" size="20" #targetName="ngModel" value="" required>
|
||||||
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
|
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
|
||||||
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}
|
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}
|
||||||
</span>
|
</span>
|
||||||
@ -16,7 +23,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="destination_url" class="col-md-4 form-group-label-override">{{ 'DESTINATION.URL' | translate }}<span style="color: red">*</span></label>
|
<label for="destination_url" class="col-md-4 form-group-label-override">{{ 'DESTINATION.URL' | translate }}<span style="color: red">*</span></label>
|
||||||
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)" [class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)" [class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
||||||
<input type="text" id="destination_url" [disabled]="testOngoing" [(ngModel)]="target.endpoint" size="20" name="endpointUrl" #targetEndpoint="ngModel" required>
|
<input type="text" id="destination_url" [disabled]="testOngoing || !editable" [(ngModel)]="target.endpoint" size="20" name="endpointUrl" #targetEndpoint="ngModel" required>
|
||||||
<span class="tooltip-content" *ngIf="targetEndpoint.errors && targetEndpoint.errors.required && (targetEndpoint.dirty || targetEndpoint.touched)">
|
<span class="tooltip-content" *ngIf="targetEndpoint.errors && targetEndpoint.errors.required && (targetEndpoint.dirty || targetEndpoint.touched)">
|
||||||
{{ 'DESTINATION.URL_IS_REQUIRED' | translate }}
|
{{ 'DESTINATION.URL_IS_REQUIRED' | translate }}
|
||||||
</span>
|
</span>
|
||||||
@ -24,11 +31,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="destination_username" class="col-md-4 form-group-label-override">{{ 'DESTINATION.USERNAME' | translate }}</label>
|
<label for="destination_username" class="col-md-4 form-group-label-override">{{ 'DESTINATION.USERNAME' | translate }}</label>
|
||||||
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing" [(ngModel)]="target.username" size="20" name="username" #username="ngModel">
|
<input type="text" class="col-md-8" id="destination_username" [disabled]="testOngoing || !editable" [(ngModel)]="target.username" size="20" name="username" #username="ngModel">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="destination_password" class="col-md-4 form-group-label-override">{{ 'DESTINATION.PASSWORD' | translate }}</label>
|
<label for="destination_password" class="col-md-4 form-group-label-override">{{ 'DESTINATION.PASSWORD' | translate }}</label>
|
||||||
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing" [(ngModel)]="target.password" size="20" name="password" #password="ngModel">
|
<input type="password" class="col-md-8" id="destination_password" [disabled]="testOngoing || !editable" [(ngModel)]="target.password" size="20" name="password" #password="ngModel">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="spin" class="col-md-4"></label>
|
<label for="spin" class="col-md-4"></label>
|
||||||
@ -41,6 +48,6 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline" (click)="testConnection()" [disabled]="testOngoing || targetEndpoint.errors">{{ 'DESTINATION.TEST_CONNECTION' | translate }}</button>
|
<button type="button" class="btn btn-outline" (click)="testConnection()" [disabled]="testOngoing || targetEndpoint.errors">{{ 'DESTINATION.TEST_CONNECTION' | translate }}</button>
|
||||||
<button type="button" class="btn btn-outline" (click)="onCancel()" [disabled]="testOngoing">{{ 'BUTTON.CANCEL' | translate }}</button>
|
<button type="button" class="btn btn-outline" (click)="onCancel()" [disabled]="testOngoing">{{ 'BUTTON.CANCEL' | translate }}</button>
|
||||||
<button type="submit" class="btn btn-primary" [disabled]="!targetForm.form.valid" (click)="onSubmit()" [disabled]="testOngoing">{{ 'BUTTON.OK' | translate }}</button>
|
<button type="submit" class="btn btn-primary" (click)="onSubmit()" [disabled]="testOngoing || targetForm.form.invalid || !editable">{{ 'BUTTON.OK' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
@ -20,6 +20,8 @@ export class CreateEditDestinationComponent implements AfterViewChecked {
|
|||||||
modalTitle: string;
|
modalTitle: string;
|
||||||
createEditDestinationOpened: boolean;
|
createEditDestinationOpened: boolean;
|
||||||
|
|
||||||
|
editable: boolean;
|
||||||
|
|
||||||
testOngoing: boolean;
|
testOngoing: boolean;
|
||||||
pingTestMessage: string;
|
pingTestMessage: string;
|
||||||
pingStatus: boolean;
|
pingStatus: boolean;
|
||||||
@ -49,10 +51,12 @@ export class CreateEditDestinationComponent implements AfterViewChecked {
|
|||||||
private messageHandlerService: MessageHandlerService,
|
private messageHandlerService: MessageHandlerService,
|
||||||
private translateService: TranslateService) {}
|
private translateService: TranslateService) {}
|
||||||
|
|
||||||
openCreateEditTarget(targetId?: number) {
|
openCreateEditTarget(editable: boolean, targetId?: number) {
|
||||||
|
|
||||||
this.target = new Target();
|
this.target = new Target();
|
||||||
this.createEditDestinationOpened = true;
|
this.createEditDestinationOpened = true;
|
||||||
|
this.editable = editable;
|
||||||
|
|
||||||
this.hasChanged = false;
|
this.hasChanged = false;
|
||||||
|
|
||||||
this.pingTestMessage = '';
|
this.pingTestMessage = '';
|
||||||
|
@ -87,13 +87,31 @@ export class DestinationComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openModal() {
|
openModal() {
|
||||||
this.createEditDestinationComponent.openCreateEditTarget();
|
this.createEditDestinationComponent.openCreateEditTarget(true);
|
||||||
this.target = new Target();
|
this.target = new Target();
|
||||||
}
|
}
|
||||||
|
|
||||||
editTarget(target: Target) {
|
editTarget(target: Target) {
|
||||||
if (target) {
|
if (target) {
|
||||||
this.createEditDestinationComponent.openCreateEditTarget(target.id);
|
let editable = true;
|
||||||
|
this.replicationService
|
||||||
|
.listTargetPolicies(target.id)
|
||||||
|
.subscribe(
|
||||||
|
policies=>{
|
||||||
|
if(policies && policies.length > 0) {
|
||||||
|
for(let i = 0; i < policies.length; i++){
|
||||||
|
let p = policies[i];
|
||||||
|
if(p.enabled === 1) {
|
||||||
|
editable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.createEditDestinationComponent.openCreateEditTarget(editable, target.id);
|
||||||
|
},
|
||||||
|
error=>this.messageHandlerService.handleError(error)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,14 @@ export class ReplicationService {
|
|||||||
.catch(error=>Observable.throw(error));
|
.catch(error=>Observable.throw(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listTargetPolicies(targetId: number): Observable<Policy[]> {
|
||||||
|
console.log('List target with policy.');
|
||||||
|
return this.http
|
||||||
|
.get(`/api/targets/${targetId}/policies`)
|
||||||
|
.map(response=>response.json() as Policy[])
|
||||||
|
.catch(error=>Observable.throw(error));
|
||||||
|
}
|
||||||
|
|
||||||
getTarget(targetId: number): Observable<Target> {
|
getTarget(targetId: number): Observable<Target> {
|
||||||
console.log('Get target by ID:' + targetId);
|
console.log('Get target by ID:' + targetId);
|
||||||
return this.http
|
return this.http
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
<clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPOSITORY.PULL_COUNT' | translate}}</clr-dg-column>
|
||||||
<clr-dg-row *ngFor="let r of repositories" [clrDgItem]='r'>
|
<clr-dg-row *ngFor="let r of repositories" [clrDgItem]='r'>
|
||||||
<clr-dg-action-overflow [hidden]="!hasProjectAdminRole">
|
<clr-dg-action-overflow [hidden]="!hasProjectAdminRole">
|
||||||
<button class="action-item">{{'REPOSITORY.COPY_ID' | translate}}</button>
|
|
||||||
<button class="action-item">{{'REPOSITORY.COPY_PARENT_ID' | translate}}</button>
|
|
||||||
<button class="action-item" (click)="deleteRepo(r.name)">{{'REPOSITORY.DELETE' | translate}}</button>
|
<button class="action-item" (click)="deleteRepo(r.name)">{{'REPOSITORY.DELETE' | translate}}</button>
|
||||||
</clr-dg-action-overflow>
|
</clr-dg-action-overflow>
|
||||||
<clr-dg-cell><a href="javascript:void(0)" (click)="gotoLink(projectId || r.project_id, r.name || r.repository_name)">{{r.name || r.repository_name}}</a></clr-dg-cell>
|
<clr-dg-cell><a href="javascript:void(0)" (click)="gotoLink(projectId || r.project_id, r.name || r.repository_name)">{{r.name || r.repository_name}}</a></clr-dg-cell>
|
||||||
|
@ -1,6 +1,19 @@
|
|||||||
|
|
||||||
<a *ngIf="hasSignedIn" [routerLink]="['/harbor', 'projects', projectId, 'repository']">< {{'REPOSITORY.REPOSITORIES' | translate}}</a>
|
<a *ngIf="hasSignedIn" [routerLink]="['/harbor', 'projects', projectId, 'repository']">< {{'REPOSITORY.REPOSITORIES' | translate}}</a>
|
||||||
<a *ngIf="!hasSignedIn" [routerLink]="['/harbor', 'sign-in']">< {{'SEARCH.BACK' | translate}}</a>
|
<a *ngIf="!hasSignedIn" [routerLink]="['/harbor', 'sign-in']">< {{'SEARCH.BACK' | translate}}</a>
|
||||||
|
|
||||||
|
<clr-modal [(clrModalOpen)]="showTagManifestOpened" [clrModalStaticBackdrop]="staticBackdrop" [clrModalClosable]="closable">
|
||||||
|
<h3 class="modal-title">{{ manifestInfoTitle | translate }}</h3>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row col-md-12">
|
||||||
|
<textarea rows="3" (click)="selectAndCopy($event)">{{tagID}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" (click)="showTagManifestOpened = false">{{'BUTTON.OK' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</clr-modal>
|
||||||
|
|
||||||
<h2 class="sub-header-title">{{repoName}} <span class="badge">{{tags ? tags.length : 0}}</span></h2>
|
<h2 class="sub-header-title">{{repoName}} <span class="badge">{{tags ? tags.length : 0}}</span></h2>
|
||||||
<clr-datagrid>
|
<clr-datagrid>
|
||||||
<clr-dg-column>{{'REPOSITORY.TAG' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPOSITORY.TAG' | translate}}</clr-dg-column>
|
||||||
@ -12,8 +25,10 @@
|
|||||||
<clr-dg-column>{{'REPOSITORY.ARCHITECTURE' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPOSITORY.ARCHITECTURE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'REPOSITORY.OS' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'REPOSITORY.OS' | translate}}</clr-dg-column>
|
||||||
<clr-dg-row *ngFor="let t of tags" [clrDgItem]='t'>
|
<clr-dg-row *ngFor="let t of tags" [clrDgItem]='t'>
|
||||||
<clr-dg-action-overflow *ngIf="hasProjectAdminRole">
|
<clr-dg-action-overflow>
|
||||||
<button class="action-item" (click)="deleteTag(t)">{{'REPOSITORY.DELETE' | translate}}</button>
|
<button class="action-item" (click)="showTagID('tag', t)">{{'REPOSITORY.COPY_ID' | translate}}</button>
|
||||||
|
<button class="action-item" (click)="showTagID('parent', t)">{{'REPOSITORY.COPY_PARENT_ID' | translate}}</button>
|
||||||
|
<button class="action-item" [hidden]="!hasProjectAdminRole" (click)="deleteTag(t)">{{'REPOSITORY.DELETE' | translate}}</button>
|
||||||
</clr-dg-action-overflow>
|
</clr-dg-action-overflow>
|
||||||
<clr-dg-cell>{{t.tag}}</clr-dg-cell>
|
<clr-dg-cell>{{t.tag}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{t.pullCommand}}</clr-dg-cell>
|
<clr-dg-cell>{{t.pullCommand}}</clr-dg-cell>
|
||||||
|
@ -37,6 +37,14 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
hasSignedIn: boolean;
|
hasSignedIn: boolean;
|
||||||
|
|
||||||
|
showTagManifestOpened: boolean;
|
||||||
|
manifestInfoTitle: string;
|
||||||
|
tagID: string;
|
||||||
|
staticBackdrop: boolean = true;
|
||||||
|
closable: boolean = false;
|
||||||
|
|
||||||
|
selectAll: boolean = false;
|
||||||
|
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -123,6 +131,8 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
|||||||
tag.dockerVersion = data['docker_version'];
|
tag.dockerVersion = data['docker_version'];
|
||||||
tag.pullCommand = 'docker pull ' + this.registryUrl + '/' + t.manifest.name + ':' + t.tag;
|
tag.pullCommand = 'docker pull ' + this.registryUrl + '/' + t.manifest.name + ':' + t.tag;
|
||||||
tag.os = data['os'];
|
tag.os = data['os'];
|
||||||
|
tag.id = data['id'];
|
||||||
|
tag.parent = data['parent'];
|
||||||
this.tags.push(tag);
|
this.tags.push(tag);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -149,4 +159,19 @@ export class TagRepositoryComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showTagID(type: string, tag: TagView) {
|
||||||
|
if(tag) {
|
||||||
|
if(type === 'tag') {
|
||||||
|
this.manifestInfoTitle = 'REPOSITORY.COPY_ID';
|
||||||
|
this.tagID = tag.id;
|
||||||
|
} else if(type === 'parent') {
|
||||||
|
this.manifestInfoTitle = 'REPOSITORY.COPY_PARENT_ID';
|
||||||
|
this.tagID = tag.parent;
|
||||||
|
}
|
||||||
|
this.showTagManifestOpened = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectAndCopy($event) {
|
||||||
|
$event.target.select();
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,4 +7,6 @@ export class TagView {
|
|||||||
dockerVersion: string;
|
dockerVersion: string;
|
||||||
architecture: string;
|
architecture: string;
|
||||||
os: string;
|
os: string;
|
||||||
|
id: string;
|
||||||
|
parent: string;
|
||||||
}
|
}
|
@ -4,6 +4,13 @@
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form #policyForm="ngForm">
|
<form #policyForm="ngForm">
|
||||||
<section class="form-block">
|
<section class="form-block">
|
||||||
|
<div class="alert alert-danger" *ngIf="readonly">
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">
|
||||||
|
{{'REPLICATION.CANNOT_EDIT' | translate}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="policy_name" class="col-md-4 form-group-label-override">{{'REPLICATION.NAME' | translate}}<span style="color: red">*</span></label>
|
<label for="policy_name" class="col-md-4 form-group-label-override">{{'REPLICATION.NAME' | translate}}<span style="color: red">*</span></label>
|
||||||
<label for="policy_name" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="name.errors && (name.dirty || name.touched)" [class.valid]="name.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
<label for="policy_name" class="col-md-8" aria-haspopup="true" role="tooltip" [class.invalid]="name.errors && (name.dirty || name.touched)" [class.valid]="name.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
|
||||||
|
@ -27,6 +27,7 @@ export const errorHandler = function (error: any): string {
|
|||||||
case 404:
|
case 404:
|
||||||
return "NOT_FOUND_ERROR";
|
return "NOT_FOUND_ERROR";
|
||||||
case 412:
|
case 412:
|
||||||
|
return "PRECONDITION_FAILED";
|
||||||
case 409:
|
case 409:
|
||||||
return "CONFLICT_ERROR";
|
return "CONFLICT_ERROR";
|
||||||
case 500:
|
case 500:
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
.action-panel-pos {
|
.action-panel-pos {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 6px;
|
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,37 @@
|
|||||||
<div style="margin-left: 24px;">
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||||
<h2 class="custom-h2">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</h2>
|
<h2 class="custom-h2">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</h2>
|
||||||
<div class="action-panel-pos">
|
<div class="action-panel-pos">
|
||||||
<span>
|
<span>
|
||||||
<button *ngIf="canCreateUser" type="submit" class="btn btn-primary custom-add-button" (click)="addNewUser()"><clr-icon shape="add"></clr-icon> {{'USER.ADD_ACTION' | translate}}</button>
|
<button *ngIf="canCreateUser" type="submit" class="btn btn-primary custom-add-button" (click)="addNewUser()"><clr-icon shape="add"></clr-icon> {{'USER.ADD_ACTION' | translate}}</button>
|
||||||
</span>
|
</span>
|
||||||
<grid-filter class="filter-pos" filterPlaceholder='{{"USER.FILTER_PLACEHOLDER" | translate}}' (filter)="doFilter($event)"></grid-filter>
|
<grid-filter class="filter-pos" filterPlaceholder='{{"USER.FILTER_PLACEHOLDER" | translate}}' (filter)="doFilter($event)"></grid-filter>
|
||||||
<span class="refresh-btn" (click)="refreshUser()">
|
<span class="refresh-btn" (click)="refreshUser()">
|
||||||
<clr-icon shape="refresh" [hidden]="inProgress" ng-disabled="inProgress"></clr-icon>
|
<clr-icon shape="refresh" [hidden]="inProgress" ng-disabled="inProgress"></clr-icon>
|
||||||
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
<span class="spinner spinner-inline" [hidden]="inProgress === false"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<clr-datagrid>
|
<clr-datagrid>
|
||||||
<clr-dg-column>{{'USER.COLUMN_NAME' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'USER.COLUMN_NAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'USER.COLUMN_ADMIN' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'USER.COLUMN_ADMIN' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'USER.COLUMN_EMAIL' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'USER.COLUMN_EMAIL' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'USER.COLUMN_REG_NAME' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'USER.COLUMN_REG_NAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-row *ngFor="let user of users" [clrDgItem]="user">
|
<clr-dg-row *ngFor="let user of users" [clrDgItem]="user">
|
||||||
<clr-dg-action-overflow [hidden]="isMySelf(user.user_id)">
|
<clr-dg-action-overflow [hidden]="isMySelf(user.user_id)">
|
||||||
<button class="action-item" (click)="changeAdminRole(user)">{{adminActions(user)}}</button>
|
<button class="action-item" (click)="changeAdminRole(user)">{{adminActions(user)}}</button>
|
||||||
<button class="action-item" (click)="deleteUser(user)">{{'USER.DEL_ACTION' | translate}}</button>
|
<button class="action-item" (click)="deleteUser(user)">{{'USER.DEL_ACTION' | translate}}</button>
|
||||||
</clr-dg-action-overflow>
|
</clr-dg-action-overflow>
|
||||||
<clr-dg-cell>{{user.username}}</clr-dg-cell>
|
<clr-dg-cell>{{user.username}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{isSystemAdmin(user)}}</clr-dg-cell>
|
<clr-dg-cell>{{isSystemAdmin(user)}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{user.email}}</clr-dg-cell>
|
<clr-dg-cell>{{user.email}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
{{user.creation_time}}
|
{{user.creation_time}}
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>{{users.length}} {{'USER.ADD_ACTION' | translate}}</clr-dg-footer>
|
<clr-dg-footer>{{users.length}} {{'USER.ADD_ACTION' | translate}}</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
<new-user-modal (addNew)="addUserToList($event)"></new-user-modal>
|
<new-user-modal (addNew)="addUserToList($event)"></new-user-modal>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
@ -255,7 +255,8 @@
|
|||||||
"UPDATED_SUCCESS": "Updated replication rule successfully.",
|
"UPDATED_SUCCESS": "Updated replication rule successfully.",
|
||||||
"DELETED_SUCCESS": "Deleted replication rule successfully.",
|
"DELETED_SUCCESS": "Deleted replication rule successfully.",
|
||||||
"DELETED_FAILED": "Deleted replication rule failed.",
|
"DELETED_FAILED": "Deleted replication rule failed.",
|
||||||
"TOGGLED_SUCCESS": "Toggled replication rule status successfully."
|
"TOGGLED_SUCCESS": "Toggled replication rule status successfully.",
|
||||||
|
"CANNOT_EDIT": "Replication rule cannot be changed while it is enabled."
|
||||||
},
|
},
|
||||||
"DESTINATION": {
|
"DESTINATION": {
|
||||||
"NEW_ENDPOINT": "New Endpoint",
|
"NEW_ENDPOINT": "New Endpoint",
|
||||||
@ -281,7 +282,8 @@
|
|||||||
"CREATED_SUCCESS": "Created endpoint successfully.",
|
"CREATED_SUCCESS": "Created endpoint successfully.",
|
||||||
"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."
|
||||||
},
|
},
|
||||||
"REPOSITORY": {
|
"REPOSITORY": {
|
||||||
"COPY_ID": "Copy ID",
|
"COPY_ID": "Copy ID",
|
||||||
@ -312,7 +314,8 @@
|
|||||||
"ITEMS": "item(s)",
|
"ITEMS": "item(s)",
|
||||||
"POP_REPOS": "Popular Repositories",
|
"POP_REPOS": "Popular Repositories",
|
||||||
"DELETED_REPO_SUCCESS": "Deleted repository successfully.",
|
"DELETED_REPO_SUCCESS": "Deleted repository successfully.",
|
||||||
"DELETED_TAG_SUCCESS": "Deleted tag successfully."
|
"DELETED_TAG_SUCCESS": "Deleted tag successfully.",
|
||||||
|
"COPY": "Copy"
|
||||||
},
|
},
|
||||||
"ALERT": {
|
"ALERT": {
|
||||||
"FORM_CHANGE_CONFIRMATION": "Some changes are not saved yet, do you really want to cancel?"
|
"FORM_CHANGE_CONFIRMATION": "Some changes are not saved yet, do you really want to cancel?"
|
||||||
@ -421,6 +424,7 @@
|
|||||||
"BAD_REQUEST_ERROR": "We are unable to perform your action because of a bad request",
|
"BAD_REQUEST_ERROR": "We are unable to perform your action because of a bad request",
|
||||||
"NOT_FOUND_ERROR": "Your request can not be completed because the object does not exist",
|
"NOT_FOUND_ERROR": "Your request can not be completed because the object does not exist",
|
||||||
"CONFLICT_ERROR": "We are unable to perform your action because your submission has conflicts",
|
"CONFLICT_ERROR": "We are unable to perform your action because your submission has conflicts",
|
||||||
|
"PRECONDITION_FAILED": "We are unable to perform your action because of a precondition failure.",
|
||||||
"SERVER_ERROR": "We are unable to perform your action because internal server errors have occurred",
|
"SERVER_ERROR": "We are unable to perform your action because internal server errors have occurred",
|
||||||
"INCONRRECT_OLD_PWD": "The old password is incorrect",
|
"INCONRRECT_OLD_PWD": "The old password is incorrect",
|
||||||
"UNKNOWN": "n/a"
|
"UNKNOWN": "n/a"
|
||||||
|
@ -255,7 +255,8 @@
|
|||||||
"UPDATED_SUCCESS": "更新复制策略成功。",
|
"UPDATED_SUCCESS": "更新复制策略成功。",
|
||||||
"DELETED_SUCCESS": "删除复制策略成功。",
|
"DELETED_SUCCESS": "删除复制策略成功。",
|
||||||
"DELETED_FAILED": "删除复制策略失败。",
|
"DELETED_FAILED": "删除复制策略失败。",
|
||||||
"TOGGLED_SUCCESS": "切换复制策略状态成功。"
|
"TOGGLED_SUCCESS": "切换复制策略状态成功。",
|
||||||
|
"CANNOT_EDIT": "当复制规则启用时无法修改。"
|
||||||
},
|
},
|
||||||
"DESTINATION": {
|
"DESTINATION": {
|
||||||
"NEW_ENDPOINT": "新建目标",
|
"NEW_ENDPOINT": "新建目标",
|
||||||
@ -281,7 +282,8 @@
|
|||||||
"CREATED_SUCCESS": "创建目标成功。",
|
"CREATED_SUCCESS": "创建目标成功。",
|
||||||
"UPDATED_SUCCESS": "更新目标成功。",
|
"UPDATED_SUCCESS": "更新目标成功。",
|
||||||
"DELETED_SUCCESS": "删除目标成功。",
|
"DELETED_SUCCESS": "删除目标成功。",
|
||||||
"DELETED_FAILED": "删除目标失败。"
|
"DELETED_FAILED": "删除目标失败。",
|
||||||
|
"CANNOT_EDIT": "当复制规则启用时目标无法修改。"
|
||||||
},
|
},
|
||||||
"REPOSITORY": {
|
"REPOSITORY": {
|
||||||
"COPY_ID": "复制ID",
|
"COPY_ID": "复制ID",
|
||||||
@ -312,7 +314,8 @@
|
|||||||
"ITEMS": "条记录",
|
"ITEMS": "条记录",
|
||||||
"POP_REPOS": "受欢迎的镜像库",
|
"POP_REPOS": "受欢迎的镜像库",
|
||||||
"DELETED_REPO_SUCCESS": "删除镜像仓库成功。",
|
"DELETED_REPO_SUCCESS": "删除镜像仓库成功。",
|
||||||
"DELETED_TAG_SUCCESS": "删除镜像标签成功。"
|
"DELETED_TAG_SUCCESS": "删除镜像标签成功。",
|
||||||
|
"COPY": "复制"
|
||||||
},
|
},
|
||||||
"ALERT": {
|
"ALERT": {
|
||||||
"FORM_CHANGE_CONFIRMATION": "表单内容改变,确认取消?"
|
"FORM_CHANGE_CONFIRMATION": "表单内容改变,确认取消?"
|
||||||
@ -421,6 +424,7 @@
|
|||||||
"BAD_REQUEST_ERROR": "错误请求导致无法完成操作",
|
"BAD_REQUEST_ERROR": "错误请求导致无法完成操作",
|
||||||
"NOT_FOUND_ERROR": "对象不存在故无法完成你的请求",
|
"NOT_FOUND_ERROR": "对象不存在故无法完成你的请求",
|
||||||
"CONFLICT_ERROR": "你的提交包含冲突故操作无法完成",
|
"CONFLICT_ERROR": "你的提交包含冲突故操作无法完成",
|
||||||
|
"PRECONDITION_FAILED": "由于前置条件包含冲突导致无法执行提交操作。",
|
||||||
"SERVER_ERROR": "服务器出现内部错误,请求无法完成",
|
"SERVER_ERROR": "服务器出现内部错误,请求无法完成",
|
||||||
"INCONRRECT_OLD_PWD": "旧密码不正确",
|
"INCONRRECT_OLD_PWD": "旧密码不正确",
|
||||||
"UNKNOWN": "n/a"
|
"UNKNOWN": "n/a"
|
||||||
|
Loading…
Reference in New Issue
Block a user