Commit bb837638 authored by kunw's avatar kunw
Browse files

Add project member component.

parent 793416e4
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -55,4 +55,4 @@
"typings": "^1.4.0",
"webdriver-manager": "10.2.5"
}
}
\ No newline at end of file
}
......@@ -4,7 +4,8 @@ import 'rxjs/add/operator/toPromise';
import { SignInCredential } from './sign-in-credential';
const signInUrl = '/login';
const url_prefix = '/ng';
const signInUrl = url_prefix + '/login';
/**
*
* Define a service to provide sign in methods
......
......@@ -9,7 +9,7 @@
<button class="action-item" (click)="onEdit(p)">Edit</button>
<button class="action-item" (click)="onDelete(p)">Delete</button>
</clr-dg-action-overflow>-->
<clr-dg-cell><a [routerLink]="['/harbor', 'projects', p.id, 'repository']" >{{p.name}}</a></clr-dg-cell>
<clr-dg-cell><a [routerLink]="['/harbor', 'projects', p.project_id, 'repository']" >{{p.name}}</a></clr-dg-cell>
<clr-dg-cell>{{p.public == 1 ? 'Public': 'Private'}}</clr-dg-cell>
<clr-dg-cell>{{p.repo_count}}</clr-dg-cell>
<clr-dg-cell>{{p.creation_time}}</clr-dg-cell>
......
<clr-modal [(clrModalOpen)]="addMemberOpened">
<h3 class="modal-title">Add Member</h3>
<div class="modal-body">
<form>
<section class="form-block">
<div class="form-group">
<label for="member_name" class="col-md-4">Username</label>
<label for="member_name" aria-haspopup="true" role="tooltip" [class.invalid]="hasError" [class.valid]="!hasError" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-right">
<input type="text" id="member_name" [(ngModel)]="member.username" name="name" size="20" (keyup)="hasError=false;">
<span class="tooltip-content">
{{errorMessage}}
</span>
</label>
</div>
<div class="form-group">
<label class="col-md-4">Role</label>
<div class="radio">
<input type="radio" name="roleRadios" id="checkrads_project_admin" (click)="member.role_id = 1" [checked]="member.role_id === 1">
<label for="checkrads_project_admin">Project Admin</label>
</div>
<div class="radio">
<input type="radio" name="roleRadios" id="checkrads_developer" (click)="member.role_id = 2" [checked]="member.role_id === 2">
<label for="checkrads_developer">Developer</label>
</div>
<div class="radio">
<input type="radio" name="roleRadios" id="checkrads_guest" (click)="member.role_id = 3" [checked]="member.role_id === 3">
<label for="checkrads_guest">Guest</label>
</div>
</div>
</section>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="addMemberOpened = false">Cancel</button>
<button type="button" class="btn btn-primary" (click)="onSubmit()">Ok</button>
</div>
</clr-modal>
import { Component, Input, EventEmitter, Output } from '@angular/core';
import { Response } from '@angular/http';
import { MemberService } from '../member.service';
import { MessageService } from '../../../global-message/message.service';
import { Member } from '../member';
@Component({
selector: 'add-member',
templateUrl: 'add-member.component.html'
})
export class AddMemberComponent {
member: Member = new Member();
addMemberOpened: boolean;
errorMessage: string;
hasError: boolean;
@Input() projectId: number;
@Output() added = new EventEmitter<boolean>();
constructor(private memberService: MemberService, private messageService: MessageService) {}
onSubmit(): void {
this.hasError = false;
console.log('Adding member:' + JSON.stringify(this.member));
this.memberService
.addMember(this.projectId, this.member.username, this.member.role_id)
.subscribe(
response=>{
console.log('Added member successfully.');
this.added.emit(true);
this.addMemberOpened = false;
},
error=>{
this.hasError = true;
if (error instanceof Response) {
switch(error.status){
case 404:
this.errorMessage = 'Username does not exist.';
break;
case 409:
this.errorMessage = 'Username already exists.';
break;
default:
this.errorMessage = 'Unknow error occurred while adding member.';
this.messageService.announceMessage(this.errorMessage);
}
}
console.log('Failed to add member of project:' + this.projectId, ' with error:' + error);
}
);
}
openAddMemberModal(): void {
this.hasError = false;
this.member = new Member();
this.addMemberOpened = true;
}
}
\ No newline at end of file
......@@ -2,10 +2,11 @@
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="row flex-items-xs-between">
<div class="col-xs-4">
<button class="btn btn-sm">new user</button>
<button class="btn btn-sm" (click)="openAddMemberModal()">new user</button>
<add-member [projectId]="projectId" (added)="addedMember($event)"></add-member>
</div>
<div class="col-xs-4">
<input type="text" placeholder="Search for users">
<input type="text" placeholder="Search for users" #searchMember (keyup.enter)="doSearch(searchMember.value)">
</div>
</div>
<clr-datagrid>
......@@ -13,23 +14,25 @@
<clr-dg-column>Role</clr-dg-column>
<clr-dg-column>Action</clr-dg-column>
<clr-dg-row *ngFor="let u of members">
<clr-dg-cell>{{u.name}}</clr-dg-cell>
<clr-dg-cell>{{u.role}}</clr-dg-cell>
<clr-dg-cell>{{u.username}}</clr-dg-cell>
<clr-dg-cell>{{roleInfo[u.role_id]}}</clr-dg-cell>
<clr-dg-cell>
<clr-dropdown [clrMenuPosition]="'bottom-left'">
<clr-dropdown [clrMenuPosition]="'bottom-left'" [hidden]="u.user_id === currentUser.user_id">
<button class="btn btn-sm btn-link" clrDropdownToggle>
Actions
<clr-icon shape="caret down"></clr-icon>
</button>
<div class="dropdown-menu">
<a href="javascript:void(0)" clrDropdownItem>Project Admin</a>
<a href="javascript:void(0)" clrDropdownItem>Developer</a>
<a href="javascript:void(0)" clrDropdownItem>Guest</a>
<a href="javascript:void(0)" clrDropdownItem (click)="changeRole(u.user_id, 1)">Project Admin</a>
<a href="javascript:void(0)" clrDropdownItem (click)="changeRole(u.user_id, 2)">Developer</a>
<a href="javascript:void(0)" clrDropdownItem (click)="changeRole(u.user_id, 3)">Guest</a>
<div class="dropdown-divider"></div>
<a href="javascript:void(0)" clrDropdownItem (click)="deleteMember(u.user_id)">Delete Member</a>
</div>
</clr-dropdown>
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>{{members.length}} item(s)</clr-dg-footer>
<clr-dg-footer>{{ (members ? members.length : 0) }} item(s)</clr-dg-footer>
</clr-datagrid>
</div>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { SessionUser } from '../../shared/session-user';
import { Member } from './member';
import { MemberService } from './member.service';
import { AddMemberComponent } from './add-member/add-member.component';
import { MessageService } from '../../global-message/message.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
export const roleInfo: {} = { 1: 'ProjectAdmin', 2: 'Developer', 3: 'Guest'};
@Component({
templateUrl: 'member.component.html'
})
export class MemberComponent implements OnInit {
currentUser: SessionUser;
members: Member[];
projectId: number;
roleInfo = roleInfo;
@ViewChild(AddMemberComponent)
addMemberComponent: AddMemberComponent;
constructor(private route: ActivatedRoute, private memberService: MemberService, private messageService: MessageService) {
//Get current user from registered resolver.
this.route.data.subscribe(data=>this.currentUser = <SessionUser>data['memberResolver']);
}
retrieve(projectId:number, username: string) {
this.memberService
.listMembers(projectId, username)
.subscribe(
response=>this.members = response,
error=>console.log(error)
);
}
ngOnInit(): void {
this.members = [
{ name: 'Admin', role: 'Sys admin'},
{ name: 'user01', role: 'Project Admin'},
{ name: 'user02', role: 'Developer'},
{ name: 'user03', role: 'Guest'}
];
ngOnInit() {
//Get projectId from route params snapshot.
this.projectId = +this.route.snapshot.parent.params['id'];
console.log('Get projectId from route params snapshot:' + this.projectId);
this.retrieve(this.projectId, '');
}
openAddMemberModal() {
this.addMemberComponent.openAddMemberModal();
}
addedMember() {
this.retrieve(this.projectId, '');
}
changeRole(userId: number, roleId: number) {
this.memberService
.changeMemberRole(this.projectId, userId, roleId)
.subscribe(
response=>{
console.log('Successful change role with user ' + userId + ' to roleId ' + roleId);
this.retrieve(this.projectId, '');
},
error => this.messageService.announceMessage('Failed to change role with user ' + userId + ' to roleId ' + roleId)
);
}
deleteMember(userId: number) {
this.memberService
.deleteMember(this.projectId, userId)
.subscribe(
response=>{
console.log('Successful change role with user ' + userId);
this.retrieve(this.projectId, '');
},
error => this.messageService.announceMessage('Failed to change role with user ' + userId)
);
}
doSearch(searchMember) {
this.retrieve(this.projectId, searchMember);
}
}
\ No newline at end of file
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import { BaseService } from '../../service/base.service';
import { Member } from './member';
export const urlPrefix = '/ng';
@Injectable()
export class MemberService extends BaseService {
constructor(private http: Http) {
super();
}
listMembers(projectId: number, username: string): Observable<Member[]> {
console.log('Get member from project_id:' + projectId + ', username:' + username);
return this.http
.get(urlPrefix + `/api/projects/${projectId}/members?username=${username}`)
.map(response=>response.json())
.catch(error=>this.handleError(error));
}
addMember(projectId: number, username: string, roleId: number): Observable<any> {
console.log('Adding member with username:' + username + ', roleId:' + roleId + ' under projectId:' + projectId);
return this.http
.post(urlPrefix + `/api/projects/${projectId}/members`, { username: username, roles: [ roleId ] })
.map(response=>response.status)
.catch(error=>Observable.throw(error));
}
changeMemberRole(projectId: number, userId: number, roleId: number): Observable<any> {
console.log('Changing member role with userId:' + ' to roleId:' + roleId + ' under projectId:' + projectId);
return this.http
.put(urlPrefix + `/api/projects/${projectId}/members/${userId}`, { roles: [ roleId ]})
.map(response=>response.status)
.catch(error=>Observable.throw(error));
}
deleteMember(projectId: number, userId: number): Observable<any> {
console.log('Deleting member role with userId:' + userId + ' under projectId:' + projectId);
return this.http
.delete(urlPrefix + `/api/projects/${projectId}/members/${userId}`)
.map(response=>response.status)
.catch(error=>Observable.throw(error));
}
}
\ No newline at end of file
/*
{
"user_id": 1,
"username": "admin",
"email": "",
"password": "",
"realname": "",
"comment": "",
"deleted": 0,
"role_name": "projectAdmin",
"role_id": 1,
"has_admin_role": 0,
"reset_uuid": "",
"creation_time": "0001-01-01T00:00:00Z",
"update_time": "0001-01-01T00:00:00Z"
}
*/
export class Member {
name: string;
role: string;
user_id: number;
username: string;
role_name: string;
has_admin_role: number;
role_id: number;
}
\ No newline at end of file
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'project-detail',
templateUrl: "project-detail.component.html",
styleUrls: [ 'project-detail.css' ]
})
export class ProjectDetailComponent {
// constructor(private router: Router){}
}
\ No newline at end of file
export class ProjectDetailComponent {}
\ No newline at end of file
......@@ -36,7 +36,12 @@ const projectRoutes: Routes = [
children: [
{ path: 'repository', component: RepositoryComponent },
{ path: 'replication', component: ReplicationComponent },
{ path: 'member', component: MemberComponent },
{
path: 'member', component: MemberComponent,
resolve: {
memberResolver: BaseRoutingResolver
}
},
{ path: 'log', component: AuditLogComponent }
]
}
......
......@@ -14,10 +14,11 @@ import { ListProjectComponent } from './list-project/list-project.component';
import { ProjectDetailComponent } from './project-detail/project-detail.component';
import { MemberComponent } from './member/member.component';
import { AddMemberComponent } from './member/add-member/add-member.component';
import { ProjectRoutingModule } from './project-routing.module';
import { ProjectService } from './project.service';
import { DATAGRID_DIRECTIVES } from 'clarity-angular';
import { MemberService } from './member/member.service';
@NgModule({
imports: [
......@@ -35,10 +36,11 @@ import { DATAGRID_DIRECTIVES } from 'clarity-angular';
ActionProjectComponent,
ListProjectComponent,
ProjectDetailComponent,
MemberComponent
MemberComponent,
AddMemberComponent
],
exports: [ ListProjectComponent ],
providers: [ ProjectService ]
providers: [ ProjectService, MemberService ]
})
export class ProjectModule {
......
......@@ -10,6 +10,8 @@ import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
const url_prefix = '/ng';
@Injectable()
export class ProjectService extends BaseService {
......@@ -22,14 +24,14 @@ export class ProjectService extends BaseService {
listProjects(name: string, isPublic: number): Observable<Project[]>{
return this.http
.get(`/ng/api/projects?project_name=${name}&is_public=${isPublic}`, this.options)
.get(url_prefix + `/api/projects?project_name=${name}&is_public=${isPublic}`, this.options)
.map(response=>response.json())
.catch(this.handleError);
}
createProject(name: string, isPublic: number): Observable<any> {
return this.http
.post(`/ng/api/projects`,
.post(url_prefix + `/api/projects`,
JSON.stringify({'project_name': name, 'public': isPublic})
, this.options)
.map(response=>response.status)
......@@ -38,14 +40,14 @@ export class ProjectService extends BaseService {
toggleProjectPublic(projectId: number, isPublic: number): Observable<any> {
return this.http
.put(`/ng/api/projects/${projectId}/publicity`, { 'public': isPublic }, this.options)
.put(url_prefix + `/api/projects/${projectId}/publicity`, { 'public': isPublic }, this.options)
.map(response=>response.status)
.catch(error=>Observable.throw(error));
}
deleteProject(projectId: number): Observable<any> {
return this.http
.delete(`/ng/api/projects/${projectId}`)
.delete(url_prefix + `/api/projects/${projectId}`)
.map(response=>response.status)
.catch(error=>Observable.throw(error));
}
......
......@@ -5,10 +5,12 @@ import 'rxjs/add/operator/toPromise';
import { SessionUser } from './session-user';
import { SignInCredential } from './sign-in-credential';
const signInUrl = '/login';
const currentUserEndpint = "/api/users/current";
const signOffEndpoint = "/log_out";
const accountEndpoint = "/api/users/:id";
const urlPrefix = '/ng';
const signInUrl = urlPrefix + '/login';
const currentUserEndpint = urlPrefix + "/api/users/current";
const signOffEndpoint = urlPrefix + "/log_out";
const accountEndpoint = urlPrefix + "/api/users/:id";
/**
* Define related methods to handle account and session corresponding things
*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment