diff --git a/harbor-app/src/app/base/harbor-shell/harbor-shell.component.html b/harbor-app/src/app/base/harbor-shell/harbor-shell.component.html index e8abe9435..f56210587 100644 --- a/harbor-app/src/app/base/harbor-shell/harbor-shell.component.html +++ b/harbor-app/src/app/base/harbor-shell/harbor-shell.component.html @@ -1,40 +1,41 @@ - - - - - - -
-
- -
+ + + - \ No newline at end of file + + + + +
+
+ +
+
+ diff --git a/harbor-app/src/app/global-message/message.component.html b/harbor-app/src/app/global-message/message.component.html new file mode 100644 index 000000000..283e40ad9 --- /dev/null +++ b/harbor-app/src/app/global-message/message.component.html @@ -0,0 +1,7 @@ + +
+ + {{globalMessage}} + +
+
\ No newline at end of file diff --git a/harbor-app/src/app/global-message/message.component.ts b/harbor-app/src/app/global-message/message.component.ts new file mode 100644 index 000000000..6d00c19a9 --- /dev/null +++ b/harbor-app/src/app/global-message/message.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { MessageService } from './message.service'; + +@Component({ + selector: 'global-message', + templateUrl: 'message.component.html' +}) +export class MessageComponent { + + globalMessageOpened: boolean; + globalMessage: string; + + constructor(messageService: MessageService) { + messageService.messageAnnounced$.subscribe( + message=>{ + this.globalMessageOpened = true; + this.globalMessage = message; + console.log('received message:' + message); + } + ) + } + + onClose() { + this.globalMessageOpened = false; + } +} \ No newline at end of file diff --git a/harbor-app/src/app/global-message/message.service.ts b/harbor-app/src/app/global-message/message.service.ts new file mode 100644 index 000000000..834ae2ca3 --- /dev/null +++ b/harbor-app/src/app/global-message/message.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +@Injectable() +export class MessageService { + + private messageAnnouncedSource = new Subject(); + + messageAnnounced$ = this.messageAnnouncedSource.asObservable(); + + announceMessage(message: string) { + this.messageAnnouncedSource.next(message); + } +} \ No newline at end of file diff --git a/harbor-app/src/app/project/create-project/create-project.component.html b/harbor-app/src/app/project/create-project/create-project.component.html index 5a2d82f46..c8e2c5c66 100644 --- a/harbor-app/src/app/project/create-project/create-project.component.html +++ b/harbor-app/src/app/project/create-project/create-project.component.html @@ -1,16 +1,21 @@ - + - \ No newline at end of file + \ No newline at end of file diff --git a/harbor-app/src/app/project/create-project/create-project.component.ts b/harbor-app/src/app/project/create-project/create-project.component.ts index 26319e4e9..f9df072d5 100644 --- a/harbor-app/src/app/project/create-project/create-project.component.ts +++ b/harbor-app/src/app/project/create-project/create-project.component.ts @@ -1,9 +1,55 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; +import { Response } from '@angular/http'; + +import { Project } from '../project'; +import { ProjectService } from '../project.service'; + @Component({ selector: 'create-project', - templateUrl: 'create-project.component.html' + templateUrl: 'create-project.component.html', + styleUrls: [ 'create-project.css' ] }) export class CreateProjectComponent { + + project: Project = new Project(); + createProjectOpened: boolean; + + errorMessage: string; + hasError: boolean; + + @Output() create = new EventEmitter(); + + constructor(private projectService: ProjectService) {} + + onSubmit() { + this.hasError = false; + this.projectService + .createProject(this.project.name, this.project.public) + .subscribe( + status=>{ + this.create.emit(true); + this.createProjectOpened = false; + }, + error=>{ + this.hasError = true; + if (error instanceof Response) { + switch(error.status) { + case 409: + this.errorMessage = 'Project name already exists.'; break; + case 400: + this.errorMessage = 'Project name is illegal.'; break; + default: + this.errorMessage = 'Unknown error for project name.'; + } + } + }); + } + + newProject() { + this.hasError = false; + this.project = new Project(); + this.createProjectOpened = true; + } +} -} \ No newline at end of file diff --git a/harbor-app/src/app/project/create-project/create-project.css b/harbor-app/src/app/project/create-project/create-project.css new file mode 100644 index 000000000..e69de29bb diff --git a/harbor-app/src/app/project/filter-project/filter-project.component.html b/harbor-app/src/app/project/filter-project/filter-project.component.html index 263169d93..d44a24e35 100644 --- a/harbor-app/src/app/project/filter-project/filter-project.component.html +++ b/harbor-app/src/app/project/filter-project/filter-project.component.html @@ -1,10 +1,9 @@ \ No newline at end of file diff --git a/harbor-app/src/app/project/filter-project/filter-project.component.ts b/harbor-app/src/app/project/filter-project/filter-project.component.ts index aee1f8637..3db3fa14a 100644 --- a/harbor-app/src/app/project/filter-project/filter-project.component.ts +++ b/harbor-app/src/app/project/filter-project/filter-project.component.ts @@ -1,7 +1,23 @@ -import { Component } from '@angular/core'; +import { Component, Output, EventEmitter } from '@angular/core'; + +export const projectTypes = [ + { 'key' : 0, 'value': 'My Projects' }, + { 'key' : 1, 'value': 'Public Projects'} +]; @Component({ selector: 'filter-project', templateUrl: 'filter-project.component.html' }) -export class FilterProjectComponent {} \ No newline at end of file +export class FilterProjectComponent { + + @Output() filter = new EventEmitter(); + types = projectTypes; + currentType = projectTypes[0]; + + doFilter(type: number) { + console.log('Filtered projects by:' + type); + this.currentType = projectTypes.find(item=>item.key === type); + this.filter.emit(type); + } +} \ No newline at end of file diff --git a/harbor-app/src/app/project/list-project/list-project.component.html b/harbor-app/src/app/project/list-project/list-project.component.html index b3177f9bf..56fc667a1 100644 --- a/harbor-app/src/app/project/list-project/list-project.component.html +++ b/harbor-app/src/app/project/list-project/list-project.component.html @@ -8,12 +8,12 @@ Description {{p.name}} - {{p.isPublic ? 'Public': 'Private'}} - {{p.repoCount}} - {{p.creationTime}} - {{p.destination}} + {{p.public == 1 ? 'Public': 'Private'}} + {{p.repo_count}} + {{p.creation_time}} + -- {{p.owner}} {{p.description}} - {{projects.length}} item(s) + {{ (projects ? projects.length : 0) }} item(s) \ No newline at end of file diff --git a/harbor-app/src/app/project/list-project/list-project.component.ts b/harbor-app/src/app/project/list-project/list-project.component.ts index 050d30897..3d993d88e 100644 --- a/harbor-app/src/app/project/list-project/list-project.component.ts +++ b/harbor-app/src/app/project/list-project/list-project.component.ts @@ -1,46 +1,24 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Project } from '../project'; +import { ProjectService } from '../project.service'; @Component({ selector: 'list-project', templateUrl: 'list-project.component.html' }) -export class ListProjectComponent implements OnInit { - projects: Project[]; +export class ListProjectComponent { - ngOnInit(): void { - this.projects = [ - { - id: 1, - name: 'Project01', - isPublic: true, - repoCount: 0, - creationTime: '2016-12-29 14:58 PM', - destination: '10.117.4.61', - owner: 'Administrator', - description: 'New updated by Alice.' - }, - { - id: 2, - name: 'Project02', - isPublic: false, - repoCount: 2, - creationTime: '2016-12-29 15:28 PM', - destination: '10.117.4.61', - owner: 'Administrator', - description: '--' - }, - { - id: 3, - name: 'Project03', - isPublic: true, - repoCount: 5, - creationTime: '2016-12-21 10:25 AM', - destination: '10.117.4.61', - owner: 'Administrator', - description: 'Deprecated' - }, - ]; + projects: Project[]; + errorMessage: string; + + constructor(private projectService: ProjectService) {} + + retrieve(name: string, isPublic: number): void { + this.projectService + .listProjects(name, isPublic) + .subscribe( + response => this.projects = response, + error => this.errorMessage = error); } } \ No newline at end of file diff --git a/harbor-app/src/app/project/project.component.html b/harbor-app/src/app/project/project.component.html index cea50c4b1..a8c04767d 100644 --- a/harbor-app/src/app/project/project.component.html +++ b/harbor-app/src/app/project/project.component.html @@ -1,20 +1,11 @@

Projects

- +
- - - - - + +
diff --git a/harbor-app/src/app/project/project.component.ts b/harbor-app/src/app/project/project.component.ts index 835f3ba92..148f2c417 100644 --- a/harbor-app/src/app/project/project.component.ts +++ b/harbor-app/src/app/project/project.component.ts @@ -1,14 +1,39 @@ -import { Component, OnInit } from '@angular/core'; -import { Project } from './project'; +import { Component, OnInit, ViewChild } from '@angular/core'; + import { Router } from '@angular/router'; +import { ListProjectComponent } from './list-project/list-project.component'; + @Component({ selector: 'project', templateUrl: 'project.component.html', styleUrls: [ 'project.css' ] }) export class ProjectComponent implements OnInit { - ngOnInit(): void { - + + @ViewChild(ListProjectComponent) + listProjects: ListProjectComponent; + lastFilteredType: number = 0; + + createProject(created: boolean): void { + console.log('Project has been created:' + created); + this.listProjects.retrieve('', 0); } + + filterProjects(type: number): void { + this.lastFilteredType = type; + this.listProjects.retrieve('', type); + console.log('Projects were filtered by:' + type); + + } + + searchProjects(projectName: string): void { + console.log('Search for project name:' + projectName); + this.listProjects.retrieve(projectName, this.lastFilteredType); + } + + ngOnInit(): void { + this.listProjects.retrieve('', 0); + } + } \ No newline at end of file diff --git a/harbor-app/src/app/project/project.module.ts b/harbor-app/src/app/project/project.module.ts index 0a0f7d3b2..e5d006764 100644 --- a/harbor-app/src/app/project/project.module.ts +++ b/harbor-app/src/app/project/project.module.ts @@ -14,6 +14,7 @@ import { ProjectDetailComponent } from './project-detail/project-detail.componen import { MemberComponent } from './member/member.component'; import { ProjectRoutingModule } from './project-routing.module'; +import { ProjectService } from './project.service'; @NgModule({ imports: [ @@ -32,6 +33,9 @@ import { ProjectRoutingModule } from './project-routing.module'; ProjectDetailComponent, MemberComponent ], - exports: [ ListProjectComponent ] + exports: [ ListProjectComponent ], + providers: [ ProjectService ] }) -export class ProjectModule {} \ No newline at end of file +export class ProjectModule { + +} \ No newline at end of file diff --git a/harbor-app/src/app/project/project.service.ts b/harbor-app/src/app/project/project.service.ts new file mode 100644 index 000000000..75ca04356 --- /dev/null +++ b/harbor-app/src/app/project/project.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; + +import { Http, Headers, RequestOptions } from '@angular/http'; +import { Project } from './project'; + +import { BaseService } from '../service/base.service'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/map'; + +@Injectable() +export class ProjectService extends BaseService { + + headers = new Headers({'Content-type': 'application/json'}); + options = new RequestOptions({'headers': this.headers}); + + constructor(private http: Http) { + super(); + } + + listProjects(name: string, isPublic: number): Observable{ + return this.http + .get(`/ng/api/projects?project_name=${name}&is_public=${isPublic}`, this.options) + .map(response=>response.json()) + .catch(this.handleError); + } + + createProject(name: string, isPublic: number): Observable { + return this.http + .post(`/ng/api/projects`, + JSON.stringify({'project_name': name, 'public': (isPublic ? 1 : 0)}) + , this.options) + .map(response=>response.status) + .catch(error=>Observable.throw(error)); + } + +} \ No newline at end of file diff --git a/harbor-app/src/app/project/project.ts b/harbor-app/src/app/project/project.ts index 09a59731f..1c6d73014 100644 --- a/harbor-app/src/app/project/project.ts +++ b/harbor-app/src/app/project/project.ts @@ -1,10 +1,32 @@ +/* + [ + { + "project_id": 1, + "owner_id": 1, + "name": "library", + "creation_time": "2017-02-10T07:57:56Z", + "creation_time_str": "", + "deleted": 0, + "owner_name": "", + "public": 1, + "Togglable": true, + "update_time": "2017-02-10T07:57:56Z", + "current_user_role_id": 1, + "repo_count": 0 + } + ] +*/ export class Project { - id: number; + project_id: number; + owner_id: number; name: string; - isPublic: boolean; - repoCount: number; - creationTime: string; - destination: string; - owner: string; - description: string; + creation_time: Date; + creation_time_str: string; + deleted: number; + owner_name: string; + public: number; + Togglable: boolean; + update_time: Date; + current_user_role_id: number; + repo_count: number; } \ No newline at end of file diff --git a/harbor-app/src/app/project/search-project/search-project.component.html b/harbor-app/src/app/project/search-project/search-project.component.html index b34cdbabc..db9d6a293 100644 --- a/harbor-app/src/app/project/search-project/search-project.component.html +++ b/harbor-app/src/app/project/search-project/search-project.component.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/harbor-app/src/app/project/search-project/search-project.component.ts b/harbor-app/src/app/project/search-project/search-project.component.ts index 346d4ec9c..737aebc56 100644 --- a/harbor-app/src/app/project/search-project/search-project.component.ts +++ b/harbor-app/src/app/project/search-project/search-project.component.ts @@ -1,9 +1,13 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'search-project', templateUrl: 'search-project.component.html' }) export class SearchProjectComponent { + @Output() search = new EventEmitter(); + doSearch(projectName) { + this.search.emit(projectName); + } } \ No newline at end of file diff --git a/harbor-app/src/app/service/base.service.ts b/harbor-app/src/app/service/base.service.ts new file mode 100644 index 000000000..617b916db --- /dev/null +++ b/harbor-app/src/app/service/base.service.ts @@ -0,0 +1,18 @@ +import { Http, Response} from '@angular/http'; +import { Observable } from 'rxjs/Observable'; + +export abstract class BaseService { + protected handleError(error: Response | any) { + // In a real world app, we might use a remote logging infrastructure + let errMsg: string; + if (error instanceof Response) { + const body = error.json() || ''; + const err = body.error || JSON.stringify(body); + errMsg = `${error.status} - ${error.statusText || ''} ${err}`; + } else { + errMsg = error.message ? error.message : error.toString(); + } + console.error(errMsg); + return Observable.throw(errMsg); + } +} \ No newline at end of file diff --git a/harbor-app/src/app/shared/shared.module.ts b/harbor-app/src/app/shared/shared.module.ts index 7a370cae2..1609b5fc8 100644 --- a/harbor-app/src/app/shared/shared.module.ts +++ b/harbor-app/src/app/shared/shared.module.ts @@ -2,15 +2,21 @@ import { NgModule } from '@angular/core'; import { CoreModule } from '../core/core.module'; import { SessionService } from '../shared/session.service'; +import { MessageComponent } from '../global-message/message.component'; +import { MessageService } from '../global-message/message.service'; @NgModule({ imports: [ CoreModule ], - exports: [ - CoreModule + declarations: [ + MessageComponent ], - providers: [SessionService] + exports: [ + CoreModule, + MessageComponent + ], + providers: [SessionService, MessageService] }) export class SharedModule {