diff --git a/src/ui/views/reset-password-mail.tpl b/src/ui/views/reset-password-mail.tpl new file mode 100644 index 000000000..31fb438ef --- /dev/null +++ b/src/ui/views/reset-password-mail.tpl @@ -0,0 +1,21 @@ + + + + +

Please click this link to reset your password:

+ {{.URL}}/reset_password?reset_uuid={{.UUID}} + + diff --git a/src/ui_ng/src/app/harbor-routing.module.ts b/src/ui_ng/src/app/harbor-routing.module.ts index 967a3c402..583071bfb 100644 --- a/src/ui_ng/src/app/harbor-routing.module.ts +++ b/src/ui_ng/src/app/harbor-routing.module.ts @@ -76,7 +76,10 @@ const harborRoutes: Routes = [ }, { path: 'tags/:id/:repo', - component: TagRepositoryComponent + component: TagRepositoryComponent, + resolve: { + projectResolver: ProjectRoutingResolver + } }, { path: 'projects/:id', diff --git a/src/ui_ng/src/app/log/audit-log.service.ts b/src/ui_ng/src/app/log/audit-log.service.ts index 320d589b5..28be16021 100644 --- a/src/ui_ng/src/app/log/audit-log.service.ts +++ b/src/ui_ng/src/app/log/audit-log.service.ts @@ -1,8 +1,6 @@ import { Injectable } from '@angular/core'; import { Http, Headers, RequestOptions } from '@angular/http'; -import { BaseService } from '../service/base.service'; - import { AuditLog } from './audit-log'; import { Observable } from 'rxjs/Observable'; @@ -13,7 +11,7 @@ import 'rxjs/add/observable/throw'; export const logEndpoint = "/api/logs"; @Injectable() -export class AuditLogService extends BaseService { +export class AuditLogService { private httpOptions = new RequestOptions({ headers: new Headers({ "Content-Type": 'application/json', @@ -21,9 +19,7 @@ export class AuditLogService extends BaseService { }) }); - constructor(private http: Http) { - super(); - } + constructor(private http: Http) {} listAuditLogs(queryParam: AuditLog): Observable { return this.http @@ -36,12 +32,12 @@ export class AuditLogService extends BaseService { username: queryParam.username }) .map(response => response) - .catch(error => this.handleError(error)); + .catch(error => Observable.throw(error)); } getRecentLogs(lines: number): Observable { return this.http.get(logEndpoint + "?lines=" + lines, this.httpOptions) .map(response => response.json() as AuditLog[]) - .catch(error => this.handleError(error)); + .catch(error => Observable.throw(error)); } } \ No newline at end of file diff --git a/src/ui_ng/src/app/project/create-project/create-project.component.html b/src/ui_ng/src/app/project/create-project/create-project.component.html index 725f538a6..785ba7fe9 100644 --- a/src/ui_ng/src/app/project/create-project/create-project.component.html +++ b/src/ui_ng/src/app/project/create-project/create-project.component.html @@ -31,6 +31,6 @@ diff --git a/src/ui_ng/src/app/project/list-project/list-project.component.html b/src/ui_ng/src/app/project/list-project/list-project.component.html index fa6074706..c04437c00 100644 --- a/src/ui_ng/src/app/project/list-project/list-project.component.html +++ b/src/ui_ng/src/app/project/list-project/list-project.component.html @@ -1,9 +1,9 @@ {{'PROJECT.NAME' | translate}} {{'PROJECT.PUBLIC_OR_PRIVATE' | translate}} + {{'PROJECT.ROLE' | translate}} {{'PROJECT.REPO_COUNT'| translate}} {{'PROJECT.CREATION_TIME' | translate}} - {{'PROJECT.DESCRIPTION' | translate}} @@ -12,9 +12,9 @@ {{p.name}} {{ (p.public === 1 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} + {{roleInfo[p.current_user_role_id] | translate}} {{p.repo_count}} {{p.creation_time}} - {{p.description}} {{totalRecordCount || (projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}} diff --git a/src/ui_ng/src/app/project/list-project/list-project.component.ts b/src/ui_ng/src/app/project/list-project/list-project.component.ts index c4a5895cb..1a4c8b5ea 100644 --- a/src/ui_ng/src/app/project/list-project/list-project.component.ts +++ b/src/ui_ng/src/app/project/list-project/list-project.component.ts @@ -5,7 +5,7 @@ import { ProjectService } from '../project.service'; import { SessionService } from '../../shared/session.service'; import { SearchTriggerService } from '../../base/global-search/search-trigger.service'; -import { ListMode } from '../../shared/shared.const'; +import { ListMode, ProjectTypes, RoleInfo } from '../../shared/shared.const'; import { State } from 'clarity-angular'; @@ -24,6 +24,8 @@ export class ListProjectComponent implements OnInit { @Input() totalRecordCount: number; pageOffset: number = 1; + @Input() filteredType: string; + @Output() paginate = new EventEmitter(); @Output() toggle = new EventEmitter(); @@ -31,6 +33,8 @@ export class ListProjectComponent implements OnInit { @Input() mode: string = ListMode.FULL; + roleInfo = RoleInfo; + constructor( private session: SessionService, private router: Router, @@ -43,6 +47,10 @@ export class ListProjectComponent implements OnInit { return this.mode === ListMode.FULL && this.session.getCurrentUser() != null; } + get showRoleInfo(): boolean { + return this.listFullMode && this.filteredType === ProjectTypes[0]; + } + public get isSystemAdmin(): boolean { let account = this.session.getCurrentUser(); return account != null && account.has_admin_role > 0; diff --git a/src/ui_ng/src/app/project/member/add-member/add-member.component.html b/src/ui_ng/src/app/project/member/add-member/add-member.component.html index 844ddd209..55764ae35 100644 --- a/src/ui_ng/src/app/project/member/add-member/add-member.component.html +++ b/src/ui_ng/src/app/project/member/add-member/add-member.component.html @@ -36,6 +36,6 @@ diff --git a/src/ui_ng/src/app/project/member/member.component.html b/src/ui_ng/src/app/project/member/member.component.html index a0563db81..ac4a5ea5f 100644 --- a/src/ui_ng/src/app/project/member/member.component.html +++ b/src/ui_ng/src/app/project/member/member.component.html @@ -17,15 +17,15 @@ {{'MEMBER.NAME' | translate}} {{'MEMBER.ROLE' | translate}} - - - - - - + + + + + + - {{u.username}} - {{roleInfo[u.role_id] | translate}} + {{m.username}} + {{roleInfo[m.role_id] | translate}} {{ (members ? members.length : 0) }} {{'MEMBER.ITEMS' | translate}} diff --git a/src/ui_ng/src/app/project/member/member.component.ts b/src/ui_ng/src/app/project/member/member.component.ts index b13b04c3b..765f67ee6 100644 --- a/src/ui_ng/src/app/project/member/member.component.ts +++ b/src/ui_ng/src/app/project/member/member.component.ts @@ -15,6 +15,8 @@ import { ConfirmationDialogService } from '../../shared/confirmation-dialog/conf import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message'; import { SessionService } from '../../shared/session.service'; +import { RoleInfo } from '../../shared/shared.const'; + import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/switchMap'; import 'rxjs/add/operator/catch'; @@ -22,7 +24,7 @@ import 'rxjs/add/operator/map'; import 'rxjs/add/observable/throw'; import { Subscription } from 'rxjs/Subscription'; -export const roleInfo: {} = { 1: 'MEMBER.PROJECT_ADMIN', 2: 'MEMBER.DEVELOPER', 3: 'MEMBER.GUEST' }; +import { Project } from '../../project/project'; @Component({ moduleId: module.id, @@ -31,31 +33,22 @@ export const roleInfo: {} = { 1: 'MEMBER.PROJECT_ADMIN', 2: 'MEMBER.DEVELOPER', }) export class MemberComponent implements OnInit, OnDestroy { - currentUser: SessionUser; members: Member[]; projectId: number; - roleInfo = roleInfo; + roleInfo = RoleInfo; private delSub: Subscription; @ViewChild(AddMemberComponent) addMemberComponent: AddMemberComponent; + currentUser: SessionUser; hasProjectAdminRole: boolean; constructor(private route: ActivatedRoute, private router: Router, private memberService: MemberService, private messageService: MessageService, private deletionDialogService: ConfirmationDialogService, - session: SessionService) { - //Get current user from registered resolver. - this.currentUser = session.getCurrentUser(); - let projectMembers: Member[] = session.getProjectMembers(); - if(this.currentUser && projectMembers) { - let currentMember = projectMembers.find(m=>m.user_id === this.currentUser.user_id); - if(currentMember) { - this.hasProjectAdminRole = (currentMember.role_name === 'projectAdmin'); - } - } - + private session: SessionService) { + this.delSub = deletionDialogService.confirmationConfirm$.subscribe(message => { if (message && message.state === ConfirmationState.CONFIRMED && @@ -82,8 +75,7 @@ export class MemberComponent implements OnInit, OnDestroy { error => { this.router.navigate(['/harbor', 'projects']); this.messageService.announceMessage(error.status, 'Failed to get project member with project ID:' + projectId, AlertType.DANGER); - } - ); + }); } ngOnDestroy() { @@ -97,6 +89,15 @@ export class MemberComponent implements OnInit, OnDestroy { this.projectId = +this.route.snapshot.parent.params['id']; console.log('Get projectId from route params snapshot:' + this.projectId); + this.currentUser = this.session.getCurrentUser(); + //Get current user from registered resolver. + let resolverData = this.route.snapshot.parent.data; + if(resolverData) { + this.hasProjectAdminRole = (resolverData['projectResolver']).has_project_admin_role; + } + + + this.retrieve(this.projectId, ''); } @@ -108,25 +109,27 @@ export class MemberComponent implements OnInit, OnDestroy { this.retrieve(this.projectId, ''); } - changeRole(userId: number, roleId: number) { - this.memberService - .changeMemberRole(this.projectId, userId, roleId) - .subscribe( - response => { - this.messageService.announceMessage(response, 'MEMBER.SWITCHED_SUCCESS', AlertType.SUCCESS); - console.log('Successful change role with user ' + userId + ' to roleId ' + roleId); - this.retrieve(this.projectId, ''); - }, - error => this.messageService.announceMessage(error.status, 'Failed to change role with user ' + userId + ' to roleId ' + roleId, AlertType.DANGER) - ); + changeRole(m: Member, roleId: number) { + if(m) { + this.memberService + .changeMemberRole(this.projectId, m.user_id, roleId) + .subscribe( + response => { + this.messageService.announceMessage(response, 'MEMBER.SWITCHED_SUCCESS', AlertType.SUCCESS); + console.log('Successful change role with user ' + m.user_id + ' to roleId ' + roleId); + this.retrieve(this.projectId, ''); + }, + error => this.messageService.announceMessage(error.status, 'Failed to change role with user ' + m.user_id + ' to roleId ' + roleId, AlertType.DANGER) + ); + } } - deleteMember(userId: number) { + deleteMember(m: Member) { let deletionMessage: ConfirmationMessage = new ConfirmationMessage( 'MEMBER.DELETION_TITLE', 'MEMBER.DELETION_SUMMARY', - userId + "", - userId, + m.username, + m.user_id, ConfirmationTargets.PROJECT_MEMBER ); this.deletionDialogService.openComfirmDialog(deletionMessage); diff --git a/src/ui_ng/src/app/project/member/member.service.ts b/src/ui_ng/src/app/project/member/member.service.ts index 5578b1083..28cb0c895 100644 --- a/src/ui_ng/src/app/project/member/member.service.ts +++ b/src/ui_ng/src/app/project/member/member.service.ts @@ -6,22 +6,19 @@ 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'; @Injectable() -export class MemberService extends BaseService { +export class MemberService { - constructor(private http: Http) { - super(); - } + constructor(private http: Http) {} listMembers(projectId: number, username: string): Observable { console.log('Get member from project_id:' + projectId + ', username:' + username); return this.http .get(`/api/projects/${projectId}/members?username=${username}`) - .map(response=>response.json()) - .catch(error=>this.handleError(error)); + .map(response=>response.json() as Member[]) + .catch(error=>Observable.throw(error)); } addMember(projectId: number, username: string, roleId: number): Observable { diff --git a/src/ui_ng/src/app/project/project-detail/project-detail.component.html b/src/ui_ng/src/app/project/project-detail/project-detail.component.html index ccfd09356..b33359980 100644 --- a/src/ui_ng/src/app/project/project-detail/project-detail.component.html +++ b/src/ui_ng/src/app/project/project-detail/project-detail.component.html @@ -5,10 +5,10 @@ - -