mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
Add audit log component and refine projects navigation flow.
This commit is contained in:
parent
c64ebc8b57
commit
c282653bec
@ -1,8 +1,28 @@
|
|||||||
<div class="row">
|
<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">
|
||||||
<div class="row flex-items-xs-between">
|
<div class="row flex-items-xs-right">
|
||||||
<div class="col-md-2 push-md-8">
|
<div class="col-xs-3 push-md-2 flex-xs-middle">
|
||||||
<input type="text" placeholder="Search for user">
|
<button class="btn btn-link" (click)="toggleOptionalName(currentOption)">{{toggleName[currentOption]}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-3 flex-xs-middle">
|
||||||
|
<clr-icon shape="filter" style="position: relative; left: 15px;"></clr-icon><input style="padding-left: 20px;" type="text" placeholder="Filter logs" #searchUsername (keyup.enter)="doSearchAuditLogs(searchUsername.value)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row flex-items-xs-right advance-option" [hidden]="currentOption === 0">
|
||||||
|
<div class="col-xs-2 push-md-1">
|
||||||
|
<clr-dropdown [clrMenuPosition]="'bottom-left'" >
|
||||||
|
<button class="btn btn-link" clrDropdownToggle>
|
||||||
|
All Operations
|
||||||
|
<clr-icon shape="caret down"></clr-icon>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a href="javascript:void(0)" clrDropdownItem *ngFor="let f of filterOptions" (click)="toggleFilterOption(f.key)"><clr-icon shape="check" [hidden]="!f.checked"></clr-icon> {{f.description}}</a>
|
||||||
|
</div>
|
||||||
|
</clr-dropdown>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-5 push-md-1">
|
||||||
|
<clr-icon shape="date"></clr-icon><input type="date" #fromTime (change)="doSearchByTimeRange(fromTime.value, 'begin')">
|
||||||
|
<clr-icon shape="date"></clr-icon><input type="date" #toTime (change)="doSearchByTimeRange(toTime.value, 'end')">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<clr-datagrid>
|
<clr-datagrid>
|
||||||
@ -13,12 +33,12 @@
|
|||||||
<clr-dg-column>Timestamp</clr-dg-column>
|
<clr-dg-column>Timestamp</clr-dg-column>
|
||||||
<clr-dg-row *ngFor="let l of auditLogs">
|
<clr-dg-row *ngFor="let l of auditLogs">
|
||||||
<clr-dg-cell>{{l.username}}</clr-dg-cell>
|
<clr-dg-cell>{{l.username}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.repoName}}</clr-dg-cell>
|
<clr-dg-cell>{{l.repo_name}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.tag}}</clr-dg-cell>
|
<clr-dg-cell>{{l.repo_tag}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.operation}}</clr-dg-cell>
|
<clr-dg-cell>{{l.operation}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.timestamp}}</clr-dg-cell>
|
<clr-dg-cell>{{l.op_time}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>{{auditLogs.length}} item(s)</clr-dg-footer>
|
<clr-dg-footer>{{ (auditLogs ? auditLogs.length : 0) }} item(s)</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,18 +1,138 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
|
|
||||||
import { AuditLog } from './audit-log';
|
import { AuditLog } from './audit-log';
|
||||||
|
import { SessionUser } from '../shared/session-user';
|
||||||
|
|
||||||
|
import { AuditLogService } from './audit-log.service';
|
||||||
|
import { SessionService } from '../shared/session.service';
|
||||||
|
import { MessageService } from '../global-message/message.service';
|
||||||
|
|
||||||
|
export const optionalSearch: {} = {0: 'Advanced', 1: 'Simple'};
|
||||||
|
|
||||||
|
|
||||||
|
export class FilterOption {
|
||||||
|
key: string;
|
||||||
|
description: string;
|
||||||
|
checked: boolean;
|
||||||
|
|
||||||
|
constructor(private iKey: string, private iDescription: string, private iChecked: boolean) {
|
||||||
|
this.key = iKey;
|
||||||
|
this.description = iDescription;
|
||||||
|
this.checked = iChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return 'key:' + this.key + ', description:' + this.description + ', checked:' + this.checked + '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './audit-log.component.html'
|
selector: 'audit-log',
|
||||||
|
templateUrl: './audit-log.component.html',
|
||||||
|
styleUrls: [ 'audit-log.css' ]
|
||||||
})
|
})
|
||||||
export class AuditLogComponent implements OnInit {
|
export class AuditLogComponent implements OnInit {
|
||||||
|
|
||||||
|
currentUser: SessionUser;
|
||||||
|
projectId: number;
|
||||||
|
queryParam: AuditLog = new AuditLog();
|
||||||
auditLogs: AuditLog[];
|
auditLogs: AuditLog[];
|
||||||
|
|
||||||
|
toggleName = optionalSearch;
|
||||||
|
currentOption: number = 0;
|
||||||
|
filterOptions: FilterOption[] = [
|
||||||
|
new FilterOption('all', 'All Operations', true),
|
||||||
|
new FilterOption('pull', 'Pull', true),
|
||||||
|
new FilterOption('push', 'Push', true),
|
||||||
|
new FilterOption('create', 'Create', true),
|
||||||
|
new FilterOption('delete', 'Delete', true),
|
||||||
|
new FilterOption('others', 'Others', true)
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private router: Router, private auditLogService: AuditLogService, private messageService: MessageService) {
|
||||||
|
//Get current user from registered resolver.
|
||||||
|
this.route.data.subscribe(data=>this.currentUser = <SessionUser>data['auditLogResolver']);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.auditLogs = [
|
this.projectId = +this.route.snapshot.parent.params['id'];
|
||||||
{ username: 'Admin', repoName: 'project01', tag: '', operation: 'create', timestamp: '2016-12-23 12:05:17' },
|
console.log('Get projectId from route params snapshot:' + this.projectId);
|
||||||
{ username: 'Admin', repoName: 'project01/ubuntu', tag: '14.04', operation: 'push', timestamp: '2016-12-30 14:52:23' },
|
this.queryParam.project_id = this.projectId;
|
||||||
{ username: 'user1', repoName: 'project01/mysql', tag: '5.6', operation: 'pull', timestamp: '2016-12-30 12:12:33' }
|
this.retrieve(this.queryParam);
|
||||||
];
|
}
|
||||||
|
|
||||||
|
retrieve(queryParam: AuditLog): void {
|
||||||
|
this.auditLogService
|
||||||
|
.listAuditLogs(queryParam)
|
||||||
|
.subscribe(
|
||||||
|
response=>this.auditLogs = response,
|
||||||
|
error=>{
|
||||||
|
this.router.navigate(['/harbor', 'projects']);
|
||||||
|
this.messageService.announceMessage('Failed to list audit logs with project ID:' + queryParam.project_id);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearchAuditLogs(searchUsername: string): void {
|
||||||
|
this.queryParam.username = searchUsername;
|
||||||
|
this.retrieve(this.queryParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearchByTimeRange(strDate: string, target: string): void {
|
||||||
|
let oneDayOffset = 3600 * 24;
|
||||||
|
switch(target) {
|
||||||
|
case 'begin':
|
||||||
|
this.queryParam.begin_timestamp = new Date(strDate).getTime() / 1000;
|
||||||
|
break;
|
||||||
|
case 'end':
|
||||||
|
this.queryParam.end_timestamp = new Date(strDate).getTime() / 1000 + oneDayOffset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log('Search audit log filtered by time range, begin: ' + this.queryParam.begin_timestamp + ', end:' + this.queryParam.end_timestamp);
|
||||||
|
this.retrieve(this.queryParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearchByOptions() {
|
||||||
|
let selectAll = true;
|
||||||
|
let operationFilter: string[] = [];
|
||||||
|
for(var i in this.filterOptions) {
|
||||||
|
let filterOption = this.filterOptions[i];
|
||||||
|
if(filterOption.checked) {
|
||||||
|
operationFilter.push(this.filterOptions[i].key);
|
||||||
|
}else{
|
||||||
|
selectAll = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(selectAll) {
|
||||||
|
operationFilter = [];
|
||||||
|
}
|
||||||
|
this.queryParam.keywords = operationFilter.join('/');
|
||||||
|
this.retrieve(this.queryParam);
|
||||||
|
console.log('Search option filter:' + operationFilter.join('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleOptionalName(option: number): void {
|
||||||
|
(option === 1) ? this.currentOption = 0 : this.currentOption = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleFilterOption(option: string): void {
|
||||||
|
let selectedOption = this.filterOptions.find(value =>(value.key === option));
|
||||||
|
selectedOption.checked = !selectedOption.checked;
|
||||||
|
if(selectedOption.key === 'all') {
|
||||||
|
this.filterOptions.filter(value=> value.key !== selectedOption.key).forEach(value => value.checked = selectedOption.checked);
|
||||||
|
} else {
|
||||||
|
if(!selectedOption.checked) {
|
||||||
|
this.filterOptions.find(value=>value.key === 'all').checked = false;
|
||||||
|
}
|
||||||
|
let selectAll = true;
|
||||||
|
this.filterOptions.filter(value=> value.key !== 'all').forEach(value =>{
|
||||||
|
if(!value.checked) {
|
||||||
|
selectAll = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.filterOptions.find(value=>value.key === 'all').checked = selectAll;
|
||||||
|
}
|
||||||
|
this.doSearchByOptions();
|
||||||
}
|
}
|
||||||
}
|
}
|
3
harbor-app/src/app/log/audit-log.css
Normal file
3
harbor-app/src/app/log/audit-log.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.advance-option {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
35
harbor-app/src/app/log/audit-log.service.ts
Normal file
35
harbor-app/src/app/log/audit-log.service.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
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';
|
||||||
|
import 'rxjs/add/operator/catch';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
import 'rxjs/add/observable/throw';
|
||||||
|
|
||||||
|
export const urlPrefix = '';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuditLogService extends BaseService {
|
||||||
|
|
||||||
|
constructor(private http: Http) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
listAuditLogs(queryParam: AuditLog): Observable<AuditLog[]> {
|
||||||
|
return this.http
|
||||||
|
.post(urlPrefix + `/api/projects/${queryParam.project_id}/logs/filter`, {
|
||||||
|
begin_timestamp: queryParam.begin_timestamp,
|
||||||
|
end_timestamp: queryParam.end_timestamp,
|
||||||
|
keywords: queryParam.keywords,
|
||||||
|
operation: queryParam.operation,
|
||||||
|
project_id: queryParam.project_id,
|
||||||
|
username: queryParam.username })
|
||||||
|
.map(response=>response.json() as AuditLog[])
|
||||||
|
.catch(error=>this.handleError(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,30 @@
|
|||||||
|
/*
|
||||||
|
{
|
||||||
|
"log_id": 3,
|
||||||
|
"user_id": 0,
|
||||||
|
"project_id": 0,
|
||||||
|
"repo_name": "library/mysql",
|
||||||
|
"repo_tag": "5.6",
|
||||||
|
"guid": "",
|
||||||
|
"operation": "push",
|
||||||
|
"op_time": "2017-02-14T09:22:58Z",
|
||||||
|
"username": "admin",
|
||||||
|
"keywords": "",
|
||||||
|
"BeginTime": "0001-01-01T00:00:00Z",
|
||||||
|
"begin_timestamp": 0,
|
||||||
|
"EndTime": "0001-01-01T00:00:00Z",
|
||||||
|
"end_timestamp": 0
|
||||||
|
}
|
||||||
|
*/
|
||||||
export class AuditLog {
|
export class AuditLog {
|
||||||
|
log_id: number;
|
||||||
|
project_id: number;
|
||||||
username: string;
|
username: string;
|
||||||
repoName: string;
|
repo_name: string;
|
||||||
tag: string;
|
repo_tag: string;
|
||||||
operation: string;
|
operation: string;
|
||||||
timestamp: string;
|
op_time: Date;
|
||||||
|
begin_timestamp: number = 0;
|
||||||
|
end_timestamp: number = 0;
|
||||||
|
keywords: string;
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { AuditLogComponent } from './audit-log.component';
|
import { AuditLogComponent } from './audit-log.component';
|
||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
import { AuditLogService } from './audit-log.service';
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [ SharedModule ],
|
imports: [ SharedModule ],
|
||||||
declarations: [ AuditLogComponent ],
|
declarations: [ AuditLogComponent ],
|
||||||
|
providers: [ AuditLogService ],
|
||||||
exports: [ AuditLogComponent ]
|
exports: [ AuditLogComponent ]
|
||||||
})
|
})
|
||||||
export class LogModule {}
|
export class LogModule {}
|
@ -1,12 +1,12 @@
|
|||||||
<div class="row">
|
<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">
|
||||||
<div class="row flex-items-xs-between">
|
<div class="row flex-items-xs-between">
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-4 flex-xs-middle">
|
||||||
<button class="btn btn-sm" (click)="openAddMemberModal()">new user</button>
|
<button class="btn btn-link" (click)="openAddMemberModal()"><clr-icon shape="add"></clr-icon> new user</button>
|
||||||
<add-member [projectId]="projectId" (added)="addedMember($event)"></add-member>
|
<add-member [projectId]="projectId" (added)="addedMember($event)"></add-member>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-4 flex-xs-middle">
|
||||||
<input type="text" placeholder="Search for users" #searchMember (keyup.enter)="doSearch(searchMember.value)">
|
<clr-icon shape="filter" style="position: relative; left: 15px;"></clr-icon><input style="padding-left: 20px;" type="text" placeholder="Search for users" #searchMember (keyup.enter)="doSearch(searchMember.value)">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<clr-datagrid>
|
<clr-datagrid>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
|
|
||||||
import { SessionUser } from '../../shared/session-user';
|
import { SessionUser } from '../../shared/session-user';
|
||||||
import { Member } from './member';
|
import { Member } from './member';
|
||||||
@ -30,7 +30,7 @@ export class MemberComponent implements OnInit {
|
|||||||
@ViewChild(AddMemberComponent)
|
@ViewChild(AddMemberComponent)
|
||||||
addMemberComponent: AddMemberComponent;
|
addMemberComponent: AddMemberComponent;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private memberService: MemberService, private messageService: MessageService) {
|
constructor(private route: ActivatedRoute, private router: Router, private memberService: MemberService, private messageService: MessageService) {
|
||||||
//Get current user from registered resolver.
|
//Get current user from registered resolver.
|
||||||
this.route.data.subscribe(data=>this.currentUser = <SessionUser>data['memberResolver']);
|
this.route.data.subscribe(data=>this.currentUser = <SessionUser>data['memberResolver']);
|
||||||
}
|
}
|
||||||
@ -40,7 +40,10 @@ export class MemberComponent implements OnInit {
|
|||||||
.listMembers(projectId, username)
|
.listMembers(projectId, username)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
response=>this.members = response,
|
response=>this.members = response,
|
||||||
error=>console.log(error)
|
error=>{
|
||||||
|
this.router.navigate(['/harbor', 'projects']);
|
||||||
|
this.messageService.announceMessage('Failed to get project member with project ID:' + projectId);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<h1 class="display-in-line">Project 01</h1><h6 class="display-in-line project-title">PROJECT</h6>
|
<h1 class="display-in-line">{{currentProject.name}}</h1>
|
||||||
<nav class="subnav">
|
<nav class="subnav">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
|
||||||
|
import { Project } from '../project';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'project-detail',
|
selector: 'project-detail',
|
||||||
templateUrl: "project-detail.component.html",
|
templateUrl: "project-detail.component.html",
|
||||||
styleUrls: [ 'project-detail.css' ]
|
styleUrls: [ 'project-detail.css' ]
|
||||||
})
|
})
|
||||||
export class ProjectDetailComponent {}
|
export class ProjectDetailComponent {
|
||||||
|
|
||||||
|
currentProject: Project;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private router: Router) {
|
||||||
|
this.route.data.subscribe(data=>this.currentProject = <Project>data['projectResolver']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
import { Project } from './project';
|
||||||
|
import { ProjectService } from './project.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ProjectRoutingResolver implements Resolve<Project>{
|
||||||
|
|
||||||
|
constructor(private projectService: ProjectService, private router: Router) {}
|
||||||
|
|
||||||
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Project> {
|
||||||
|
let projectId = route.params['id'];
|
||||||
|
return this.projectService
|
||||||
|
.getProject(projectId)
|
||||||
|
.then(project=> {
|
||||||
|
if(project) {
|
||||||
|
return project;
|
||||||
|
} else {
|
||||||
|
this.router.navigate(['/harbor', 'projects']);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import { MemberComponent } from './member/member.component';
|
|||||||
import { AuditLogComponent } from '../log/audit-log.component';
|
import { AuditLogComponent } from '../log/audit-log.component';
|
||||||
|
|
||||||
import { BaseRoutingResolver } from '../base/base-routing-resolver.service';
|
import { BaseRoutingResolver } from '../base/base-routing-resolver.service';
|
||||||
|
import { ProjectRoutingResolver } from './project-routing-resolver.service';
|
||||||
|
|
||||||
const projectRoutes: Routes = [
|
const projectRoutes: Routes = [
|
||||||
{
|
{
|
||||||
@ -31,7 +32,7 @@ const projectRoutes: Routes = [
|
|||||||
path: 'projects/:id',
|
path: 'projects/:id',
|
||||||
component: ProjectDetailComponent,
|
component: ProjectDetailComponent,
|
||||||
resolve: {
|
resolve: {
|
||||||
projectResolver: BaseRoutingResolver
|
projectResolver: ProjectRoutingResolver
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{ path: 'repository', component: RepositoryComponent },
|
{ path: 'repository', component: RepositoryComponent },
|
||||||
@ -42,7 +43,12 @@ const projectRoutes: Routes = [
|
|||||||
memberResolver: BaseRoutingResolver
|
memberResolver: BaseRoutingResolver
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ path: 'log', component: AuditLogComponent }
|
{
|
||||||
|
path: 'log', component: AuditLogComponent,
|
||||||
|
resolve: {
|
||||||
|
auditLogResolver: BaseRoutingResolver
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<h3>Projects</h3>
|
<h1>Projects</h1>
|
||||||
<div class="row flex-items-xs-between">
|
<div class="row flex-items-xs-between">
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-4">
|
||||||
<button class="btn btn-link" (click)="openModal()"><clr-icon shape="add"></clr-icon> New Project</button>
|
<button class="btn btn-link" (click)="openModal()"><clr-icon shape="add"></clr-icon> New Project</button>
|
||||||
|
@ -8,6 +8,7 @@ import { LogModule } from '../log/log.module';
|
|||||||
import { ProjectComponent } from './project.component';
|
import { ProjectComponent } from './project.component';
|
||||||
import { CreateProjectComponent } from './create-project/create-project.component';
|
import { CreateProjectComponent } from './create-project/create-project.component';
|
||||||
import { ActionProjectComponent } from './action-project/action-project.component';
|
import { ActionProjectComponent } from './action-project/action-project.component';
|
||||||
|
import { ListProjectComponent } from './list-project/list-project.component';
|
||||||
|
|
||||||
import { ProjectDetailComponent } from './project-detail/project-detail.component';
|
import { ProjectDetailComponent } from './project-detail/project-detail.component';
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ import { ProjectRoutingModule } from './project-routing.module';
|
|||||||
|
|
||||||
import { ProjectService } from './project.service';
|
import { ProjectService } from './project.service';
|
||||||
import { MemberService } from './member/member.service';
|
import { MemberService } from './member/member.service';
|
||||||
|
import { ProjectRoutingResolver } from './project-routing-resolver.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -31,12 +33,13 @@ import { MemberService } from './member/member.service';
|
|||||||
ProjectComponent,
|
ProjectComponent,
|
||||||
CreateProjectComponent,
|
CreateProjectComponent,
|
||||||
ActionProjectComponent,
|
ActionProjectComponent,
|
||||||
|
ListProjectComponent,
|
||||||
ProjectDetailComponent,
|
ProjectDetailComponent,
|
||||||
MemberComponent,
|
MemberComponent,
|
||||||
AddMemberComponent
|
AddMemberComponent
|
||||||
],
|
],
|
||||||
exports: [ ProjectComponent ],
|
exports: [ ProjectComponent ],
|
||||||
providers: [ ProjectService, MemberService ]
|
providers: [ ProjectRoutingResolver, ProjectService, MemberService ]
|
||||||
})
|
})
|
||||||
export class ProjectModule {
|
export class ProjectModule {
|
||||||
|
|
||||||
|
@ -22,6 +22,14 @@ export class ProjectService extends BaseService {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProject(projectId: number): Promise<Project> {
|
||||||
|
return this.http
|
||||||
|
.get(url_prefix + `/api/projects/${projectId}`)
|
||||||
|
.toPromise()
|
||||||
|
.then(response=>response.json() as Project)
|
||||||
|
.catch(error=>Observable.throw(error));
|
||||||
|
}
|
||||||
|
|
||||||
listProjects(name: string, isPublic: number): Observable<Project[]>{
|
listProjects(name: string, isPublic: number): Observable<Project[]>{
|
||||||
return this.http
|
return this.http
|
||||||
.get(url_prefix + `/api/projects?project_name=${name}&is_public=${isPublic}`, this.options)
|
.get(url_prefix + `/api/projects?project_name=${name}&is_public=${isPublic}`, this.options)
|
||||||
|
Loading…
Reference in New Issue
Block a user