mirror of
https://github.com/simon987/task_tracker.git
synced 2025-12-11 14:08:52 +00:00
added optional task unique field
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]
|
||||
})
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
22
web/angular/src/app/messenger.service.ts
Normal file
22
web/angular/src/app/messenger.service.ts
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
6
web/angular/src/app/messenger/messenger.ts
Normal file
6
web/angular/src/app/messenger/messenger.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export class MessengerState {
|
||||
|
||||
hidden: boolean;
|
||||
message?: string;
|
||||
|
||||
}
|
||||
32
web/angular/src/app/messenger/snack-bar.component.ts
Normal file
32
web/angular/src/app/messenger/snack-bar.component.ts
Normal 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,
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export class Project {
|
||||
|
||||
public id: number;
|
||||
public priority: number;
|
||||
public motd: string;
|
||||
public name: string;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user