mirror of
https://github.com/simon987/task_tracker.git
synced 2025-12-11 14:08:52 +00:00
More work on UI
This commit is contained in:
10
web/angular/src/app/api.service.ts
Normal file → Executable file
10
web/angular/src/app/api.service.ts
Normal file → Executable file
@@ -12,10 +12,18 @@ export class ApiService {
|
||||
}
|
||||
|
||||
getLogs() {
|
||||
return this.http.get(this.url + "/logs");
|
||||
return this.http.post(this.url + "/logs", "{\"level\":\"info\", \"since\":10000}");
|
||||
}
|
||||
|
||||
getProjectStats(id: number) {
|
||||
return this.http.get(this.url + "/project/stats/" + id)
|
||||
}
|
||||
|
||||
getProjects() {
|
||||
return this.http.get(this.url + "/project/stats")
|
||||
}
|
||||
|
||||
getProject(id: number) {
|
||||
return this.http.get(this.url + "/project/get/" + id)
|
||||
}
|
||||
}
|
||||
|
||||
8
web/angular/src/app/app-routing.module.ts
Normal file → Executable file
8
web/angular/src/app/app-routing.module.ts
Normal file → Executable file
@@ -2,10 +2,16 @@ import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {LogsComponent} from "./logs/logs.component";
|
||||
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 {UpdateProjectComponent} from "./update-project/update-project.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: "log", component: LogsComponent},
|
||||
{path: "project", component: ProjectDashboardComponent}
|
||||
{path: "projects", component: ProjectListComponent},
|
||||
{path: "project/:id", component: ProjectDashboardComponent},
|
||||
{path: "project/:id/update", component: UpdateProjectComponent},
|
||||
{path: "new_project", component: CreateProjectComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
0
web/angular/src/app/app.component.css
Normal file → Executable file
0
web/angular/src/app/app.component.css
Normal file → Executable file
14
web/angular/src/app/app.component.html
Normal file → Executable file
14
web/angular/src/app/app.component.html
Normal file → Executable file
@@ -1,8 +1,12 @@
|
||||
<mat-toolbar>
|
||||
<a [routerLink]="''">Index</a>
|
||||
<a [routerLink]="'log'">Logs</a>
|
||||
<a [routerLink]="'project'">Project</a>
|
||||
</mat-toolbar>
|
||||
<!--<mat-toolbar>-->
|
||||
<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>-->
|
||||
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
15
web/angular/src/app/app.module.ts
Normal file → Executable file
15
web/angular/src/app/app.module.ts
Normal file → Executable file
@@ -7,6 +7,8 @@ import {LogsComponent} from './logs/logs.component';
|
||||
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatExpansionModule,
|
||||
MatFormFieldModule,
|
||||
@@ -22,12 +24,19 @@ import {
|
||||
import {ApiService} from "./api.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';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
LogsComponent,
|
||||
ProjectDashboardComponent
|
||||
ProjectDashboardComponent,
|
||||
ProjectListComponent,
|
||||
CreateProjectComponent,
|
||||
UpdateProjectComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -41,6 +50,10 @@ import {ProjectDashboardComponent} from './project-dashboard/project-dashboard.c
|
||||
MatInputModule,
|
||||
MatToolbarModule,
|
||||
MatCardModule,
|
||||
MatButtonModule,
|
||||
MatAutocompleteModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
MatExpansionModule,
|
||||
MatTreeModule,
|
||||
BrowserAnimationsModule,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<mat-card>
|
||||
<mat-card-title>Create new project</mat-card-title>
|
||||
<mat-card-subtitle></mat-card-subtitle>
|
||||
|
||||
<mat-card-content>
|
||||
<form>
|
||||
<mat-form-field>
|
||||
<input type="text" matInput [(ngModel)]="project.name" name="name" placeholder="Name">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<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"
|
||||
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}}">
|
||||
</form>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions>
|
||||
<button>Create</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</mat-card>
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Project} from "../models/project";
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-project',
|
||||
templateUrl: './create-project.component.html',
|
||||
styleUrls: ['./create-project.component.css']
|
||||
})
|
||||
export class CreateProjectComponent implements OnInit {
|
||||
|
||||
private project = new Project();
|
||||
|
||||
constructor() {
|
||||
this.project.name = "test"
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {LogsComponent} from './logs.component';
|
||||
|
||||
describe('LogsComponent', () => {
|
||||
let component: LogsComponent;
|
||||
let fixture: ComponentFixture<LogsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LogsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LogsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ export class LogsComponent implements OnInit {
|
||||
private getLogs() {
|
||||
this.apiService.getLogs().subscribe(
|
||||
data => {
|
||||
this.data.data = _.map(data, (entry) => {
|
||||
this.data.data = _.map(data["logs"], (entry) => {
|
||||
return <LogEntry>{
|
||||
message: entry.message,
|
||||
timestamp: moment.unix(entry.timestamp).toISOString(),
|
||||
|
||||
9
web/angular/src/app/models/project.ts
Normal file
9
web/angular/src/app/models/project.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export class Project {
|
||||
|
||||
public priority: number;
|
||||
public motd: string;
|
||||
public name: string;
|
||||
public clone_url: string;
|
||||
public git_repo: string;
|
||||
public version: string;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import * as d3 from "d3"
|
||||
import * as _ from "lodash"
|
||||
import {interval} from "rxjs";
|
||||
import {ApiService} from "../api.service";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-dashboard',
|
||||
@@ -12,7 +13,9 @@ import {ApiService} from "../api.service";
|
||||
})
|
||||
export class ProjectDashboardComponent implements OnInit {
|
||||
|
||||
private projectId;
|
||||
projectStats;
|
||||
|
||||
private pieWidth = 360;
|
||||
private pieHeight = 360;
|
||||
private pieRadius = Math.min(this.pieWidth, this.pieHeight) / 2;
|
||||
@@ -47,7 +50,7 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
private assigneesPath: any;
|
||||
private assigneesSvg: any;
|
||||
|
||||
constructor(private apiService: ApiService) {
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
setupStatusPieChart() {
|
||||
@@ -165,7 +168,7 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
}
|
||||
|
||||
getStats() {
|
||||
this.apiService.getProjectStats(2).subscribe((data) => {
|
||||
this.apiService.getProjectStats(this.projectId).subscribe((data) => {
|
||||
|
||||
this.projectStats = data["stats"];
|
||||
|
||||
@@ -259,9 +262,13 @@ export class ProjectDashboardComponent implements OnInit {
|
||||
this.setupAssigneesPieChart();
|
||||
this.setupLine();
|
||||
|
||||
this.getStats();
|
||||
interval(1000).subscribe(() => {
|
||||
this.getStats()
|
||||
})
|
||||
this.route.params.subscribe(params => {
|
||||
this.projectId = params["id"];
|
||||
this.getStats();
|
||||
interval(1000).subscribe(() => {
|
||||
// this.getStats()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
0
web/angular/src/app/project-list/project-list.component.css
Executable file
0
web/angular/src/app/project-list/project-list.component.css
Executable file
19
web/angular/src/app/project-list/project-list.component.html
Executable file
19
web/angular/src/app/project-list/project-list.component.html
Executable file
@@ -0,0 +1,19 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Projects</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel *ngFor="let stats of projects">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{stats.project.id}}: {{stats.project.name}}</mat-panel-title>
|
||||
<mat-panel-description>{{stats.project.motd}}</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<pre>{{stats.project | json}}</pre>
|
||||
<div style="display: flex;">
|
||||
<a [routerLink]="'/project/' + stats.project.id">Dashboard</a>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
24
web/angular/src/app/project-list/project-list.component.ts
Executable file
24
web/angular/src/app/project-list/project-list.component.ts
Executable file
@@ -0,0 +1,24 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ApiService} from "../api.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-project-list',
|
||||
templateUrl: './project-list.component.html',
|
||||
styleUrls: ['./project-list.component.css']
|
||||
})
|
||||
export class ProjectListComponent implements OnInit {
|
||||
|
||||
constructor(private apiService: ApiService) {
|
||||
}
|
||||
|
||||
projects: any[];
|
||||
|
||||
ngOnInit() {
|
||||
this.getProjects()
|
||||
}
|
||||
|
||||
getProjects() {
|
||||
this.apiService.getProjects().subscribe(data => this.projects = data["stats"]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"sourceMap": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
.mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +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>
|
||||
<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>
|
||||
|
||||
<mat-form-field>
|
||||
<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"
|
||||
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}}">
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,40 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Project} from "../models/project";
|
||||
import {ApiService} from "../api.service";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-update-project',
|
||||
templateUrl: './update-project.component.html',
|
||||
styleUrls: ['./update-project.component.css']
|
||||
})
|
||||
export class UpdateProjectComponent implements OnInit {
|
||||
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
private project: Project;
|
||||
private projectId: number;
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(params => {
|
||||
this.projectId = params["id"];
|
||||
this.getProject();
|
||||
})
|
||||
}
|
||||
|
||||
private getProject() {
|
||||
this.apiService.getProject(this.projectId).subscribe(data => {
|
||||
this.project = <Project>{
|
||||
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"]
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user