added optional task unique field

This commit is contained in:
simon987
2019-01-29 18:16:40 -05:00
parent f250a2180c
commit 64152bfc08
35 changed files with 877 additions and 156 deletions

View File

@@ -1,5 +1,6 @@
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Project} from "./models/project";
@Injectable()
export class ApiService {
@@ -26,4 +27,12 @@ export class ApiService {
getProject(id: number) {
return this.http.get(this.url + "/project/get/" + id)
}
createProject(project: Project) {
return this.http.post(this.url + "/project/create", project)
}
updateProject(project: Project) {
return this.http.post(this.url + "/project/update/" + project.id, project)
}
}

View File

@@ -2,11 +2,11 @@
<ul>
<li><a [routerLink]="''">Index</a></li>
<li><a [routerLink]="'log'">Logs</a></li>
<li><a [routerLink]="'project'">Project</a></li>
<li><a [routerLink]="'projects'">list</a></li>
<li><a [routerLink]="'new_project'">new project</a></li>
</ul>
<!--</mat-toolbar>-->
<messenger-snack-bar></messenger-snack-bar>
<router-outlet></router-outlet>

View File

@@ -20,18 +20,21 @@ import {
MatPaginatorModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatTableModule,
MatToolbarModule,
MatTreeModule
} from "@angular/material";
import {ApiService} from "./api.service";
import {MessengerService} from "./messenger.service";
import {HttpClientModule} from "@angular/common/http";
import {ProjectDashboardComponent} from './project-dashboard/project-dashboard.component';
import {ProjectListComponent} from './project-list/project-list.component';
import {CreateProjectComponent} from './create-project/create-project.component';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {UpdateProjectComponent} from './update-project/update-project.component';
import {SnackBarComponent} from "./messenger/snack-bar.component";
@NgModule({
declarations: [
@@ -40,7 +43,8 @@ import {UpdateProjectComponent} from './update-project/update-project.component'
ProjectDashboardComponent,
ProjectListComponent,
CreateProjectComponent,
UpdateProjectComponent
UpdateProjectComponent,
SnackBarComponent,
],
imports: [
BrowserModule,
@@ -65,12 +69,17 @@ import {UpdateProjectComponent} from './update-project/update-project.component'
MatSliderModule,
MatSlideToggleModule,
MatCheckboxModule,
MatDividerModule
MatDividerModule,
MatSnackBarModule,
],
exports: [],
providers: [
ApiService,
MessengerService,
],
entryComponents: [
SnackBarComponent,
],
bootstrap: [AppComponent]
})

View File

@@ -3,7 +3,7 @@
<mat-card-subtitle></mat-card-subtitle>
<mat-card-content>
<form>
<form (ngSubmit)="onSubmit()">
<mat-form-field appearance="outline">
<mat-label>Project name</mat-label>
<input type="text" matInput [(ngModel)]="project.name" name="name" placeholder="Project name">
@@ -29,11 +29,10 @@
<input type="hidden" name="version" value="{{project.version}}">
<input type="submit" value="Create">
</form>
</mat-card-content>
<mat-card-actions>
<button>Create</button>
</mat-card-actions>
</mat-card>

View File

@@ -1,5 +1,9 @@
import {Component, OnInit} from '@angular/core';
import {Project} from "../models/project";
import {ApiService} from "../api.service";
import {MessengerService} from "../messenger.service";
import {Router} from "@angular/router";
@Component({
selector: 'app-create-project',
@@ -10,7 +14,9 @@ export class CreateProjectComponent implements OnInit {
private project = new Project();
constructor() {
constructor(private apiService: ApiService,
private messengerService: MessengerService,
private router: Router) {
this.project.name = "test";
this.project.public = true;
}
@@ -18,4 +24,16 @@ export class CreateProjectComponent implements OnInit {
ngOnInit() {
}
onSubmit() {
this.apiService.createProject(this.project).subscribe(
data => {
this.router.navigateByUrl("/project/" + data["id"]);
},
error => {
console.log(error.error.message);
this.messengerService.show(error.error.message);
}
)
}
}

View File

@@ -0,0 +1,22 @@
import {Injectable} from '@angular/core';
import {Subject} from "rxjs";
import {MessengerState} from "./messenger/messenger";
@Injectable()
export class MessengerService {
public messengerSubject = new Subject<MessengerState>();
show(message: string) {
this.messengerSubject.next({
message: message,
hidden: false,
})
}
hide() {
this.messengerSubject.next({
hidden: true,
})
}
}

View File

@@ -0,0 +1,6 @@
export class MessengerState {
hidden: boolean;
message?: string;
}

View File

@@ -0,0 +1,32 @@
import {Component, OnInit} from '@angular/core';
import {MessengerService} from "../messenger.service";
import {MessengerState} from "./messenger";
import {Subscription} from "rxjs";
import {MatSnackBar, MatSnackBarConfig} from "@angular/material";
@Component({
selector: 'messenger-snack-bar',
templateUrl: 'messenger-snack-bar.html',
styleUrls: ['messenger-snack-bar.css'],
})
export class SnackBarComponent implements OnInit {
private subscription: Subscription;
constructor(private messengerService: MessengerService, private snackBar: MatSnackBar) {
}
ngOnInit() {
this.subscription = this.messengerService.messengerSubject
.subscribe((state: MessengerState) => {
if (state.hidden) {
this.snackBar.dismiss();
} else {
this.snackBar.open(state.message, "Close", <MatSnackBarConfig>{
duration: 10 * 1000,
})
}
});
}
}

View File

@@ -1,5 +1,6 @@
export class Project {
public id: number;
public priority: number;
public motd: string;
public name: string;

View File

@@ -37,6 +37,8 @@
<pre>{{projectStats | json}}</pre>
</mat-expansion-panel>
<a [routerLink]="'/project/' + projectStats.project.id + '/update'">Update</a>
</mat-card-content>
</mat-card>
</div>

View File

@@ -56,14 +56,14 @@ export class ProjectDashboardComponent implements OnInit {
setupStatusPieChart() {
let tooltip = d3.select("#stooltip");
this.statusSvg = d3.select('#status')
this.statusSvg = d3.select("#status")
.append('svg')
.attr('width', this.pieWidth)
.attr('height', this.pieHeight)
.append("g")
.attr("transform", "translate(" + this.pieRadius + "," + this.pieRadius + ")");
this.statusPath = this.statusSvg.selectAll("path")
this.statusPath = this.statusSvg.selectAll()
.data(this.pieFun(this.statusData))
.enter()
.append('path')
@@ -76,14 +76,14 @@ export class ProjectDashboardComponent implements OnInit {
setupAssigneesPieChart() {
let tooltip = d3.select("#atooltip");
this.assigneesSvg = d3.select('#assignees')
this.assigneesSvg = d3.select("#assignees")
.append('svg')
.attr('width', this.pieWidth)
.attr('height', this.pieHeight)
.append("g")
.attr("transform", "translate(" + this.pieRadius + "," + this.pieRadius + ")");
this.assigneesPath = this.assigneesSvg.selectAll("path")
this.assigneesPath = this.assigneesSvg.selectAll()
.data(this.pieFun(this.assigneesData))
.enter()
.append('path')
@@ -229,10 +229,10 @@ export class ProjectDashboardComponent implements OnInit {
{label: "Failed", count: this.projectStats["failed_task_count"]},
{label: "Closed", count: this.projectStats["closed_task_count"]},
];
this.assigneesData = _.map(this.projectStats["assignees"], (assignedTasks) => {
this.assigneesData = _.map(this.projectStats["assignees"], assignedTask => {
return {
label: assignedTasks["assignee"] == "00000000-0000-0000-0000-000000000000" ? "unassigned" : assignedTasks["assignee"],
count: assignedTasks["task_count"]
label: assignedTask["assignee"],
count: assignedTask["task_count"],
}
});
@@ -256,6 +256,16 @@ export class ProjectDashboardComponent implements OnInit {
];
this.assigneesData = [
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
{label: 'null', count: 0},
];
this.setupStatusPieChart();

View File

@@ -12,6 +12,7 @@
<pre>{{stats.project | json}}</pre>
<div style="display: flex;">
<a [routerLink]="'/project/' + stats.project.id">Dashboard</a>
<a [routerLink]="'/project/' + stats.project.id + '/update'">Update</a>
</div>
</mat-expansion-panel>
</mat-accordion>

View File

@@ -1,29 +1,29 @@
<mat-card>
<mat-card-title>Update project</mat-card-title>
<mat-card-subtitle>Changes are saved in real time</mat-card-subtitle>
<mat-card-content>
<form>
<mat-form-field>
<form (ngSubmit)="onSubmit()" *ngIf="project != undefined">
<mat-form-field appearance="outline">
<input type="text" matInput [(ngModel)]="project.name" name="name" placeholder="Name">
</mat-form-field>
<mat-form-field>
<textarea matInput placeholder="Message of the day"></textarea>
<mat-form-field appearance="outline">
<textarea matInput [(ngModel)]="project.motd" placeholder="Message of the day" name="motd"></textarea>
</mat-form-field>
<mat-form-field>
<mat-form-field appearance="outline">
<input type="text" matInput [(ngModel)]="project.clone_url" name="clone_url"
placeholder="Git clone url">
</mat-form-field>
<mat-form-field>
<input type="text" matInput [(ngModel)]="project.git_repo" name="clone_url"
<mat-form-field appearance="outline">
<input type="text" matInput [(ngModel)]="project.git_repo" name="git_repo"
placeholder='Full repository name (e.g. "simon987/task_tracker")'>
<mat-hint align="start">Changes on the <strong>master</strong> branch will be tracked if webhooks are
enabled
</mat-hint>
</mat-form-field>
<input type="hidden" name="version" value="{{project.version}}">
<input type="submit" value="Update">
</form>
</mat-card-content>
</mat-card>

View File

@@ -1,7 +1,8 @@
import {Component, OnInit} from '@angular/core';
import {Project} from "../models/project";
import {ApiService} from "../api.service";
import {ActivatedRoute} from "@angular/router";
import {ActivatedRoute, Router} from "@angular/router";
import {MessengerService} from "../messenger.service";
@Component({
selector: 'app-update-project',
@@ -10,7 +11,10 @@ import {ActivatedRoute} from "@angular/router";
})
export class UpdateProjectComponent implements OnInit {
constructor(private apiService: ApiService, private route: ActivatedRoute) {
constructor(private apiService: ApiService,
private route: ActivatedRoute,
private messengerService: MessengerService,
private router: Router) {
}
private project: Project;
@@ -26,15 +30,28 @@ export class UpdateProjectComponent implements OnInit {
private getProject() {
this.apiService.getProject(this.projectId).subscribe(data => {
this.project = <Project>{
id: data["project"]["id"],
name: data["project"]["name"],
clone_url: data["project"]["clone_url"],
git_repo: data["project"]["git_repo"],
motd: data["project"]["motd"],
priority: data["project"]["priority"],
version: data["project"]["version"]
version: data["project"]["version"],
public: data["project"]["public"],
}
})
}
onSubmit() {
this.apiService.updateProject(this.project).subscribe(
data => {
this.router.navigateByUrl("/project/" + this.project.id);
},
error => {
console.log(error.error.message);
this.messengerService.show(error.error.message);
}
)
}
}