Skip to content

Commit

Permalink
Merge pull request #12 from qvest-digital/throughputChart
Browse files Browse the repository at this point in the history
Throughput chart
  • Loading branch information
meltzow authored Aug 20, 2024
2 parents 5500b45 + 068ebfc commit 932019e
Show file tree
Hide file tree
Showing 30 changed files with 494 additions and 249 deletions.
19 changes: 11 additions & 8 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import {RouterModule, Routes} from '@angular/router';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import {WorkItemAgePage} from './components/work-item-age-page/work-item-age.page';
import {NgModule} from "@angular/core";
import {ManageDatasetsComponent} from "./components/manage-datasets/manage-datasets.component";
import {DatasourceListComponent} from "./components/datasource/datasource-list.component";
import {CallbackComponent} from "./components/callback.component";
import {CycleTimePage} from "./components/cycle-time-page/cycle-time.page";
import {EditDatasetComponent} from "./components/edit-dataset/edit-dataset.component";
import {DatasourceEditComponent} from "./components/datasource/datasource-edit.component";
import {ThroughputPageComponent} from "./components/throughput-page/throughput-page.component";
import {WorkInProgressPageComponent} from "./components/work-in-progress/work-in-progress-page.component";

export const CALLBACK_JIRA_CLOUD = 'callbackJiraCloud';
export const CALLBACK_JIRA_DATA_CENTER = 'callbackJiraDataCenter';
export const DASHBOARD = 'dashboard';
export const WORK_ITEM_AGE = 'work-item-age';
export const CYCLE_TIME = 'cycle-time';
export const MANAGE_DATASETS = 'datasets';
export const CREATE_DATASETS = MANAGE_DATASETS + '/create';
export const THROUGHPUT = 'troughput';
export const DATASOURCE_LIST = 'datasources';
export const DATASOURCE_CREATE = DATASOURCE_LIST + '/create';
export const THROUGHPUT = 'throughput';
export const WORK_IN_PROGRESS = 'work-in-progress';

export const routes: Routes = [
{path: '', redirectTo: `/${DASHBOARD}`, pathMatch: 'full'},
Expand All @@ -26,9 +28,10 @@ export const routes: Routes = [
{path: WORK_ITEM_AGE, component: WorkItemAgePage},
{path: THROUGHPUT, component: ThroughputPageComponent},
{path: CYCLE_TIME, component: CycleTimePage},
{path: MANAGE_DATASETS, component: ManageDatasetsComponent},
{path: MANAGE_DATASETS + '/:id', component: EditDatasetComponent},
{path: CREATE_DATASETS, component: EditDatasetComponent},
{path: DATASOURCE_LIST, component: DatasourceListComponent},
{path: DATASOURCE_LIST + '/:id', component: DatasourceEditComponent},
{path: DATASOURCE_CREATE, component: DatasourceEditComponent},
{path: WORK_IN_PROGRESS, component: WorkInProgressPageComponent}
];

@NgModule({
Expand Down
8 changes: 4 additions & 4 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import {StorageService, dbConfigIssueData, dataSetDbConfig} from './services/storage.service';
import {StorageService, dbConfigIssueData, dbConfigCore} from './services/storage.service';
import { provideCharts, withDefaultRegisterables } from 'ng2-charts';
import { ToastrModule } from 'ngx-toastr';
import { NgxIndexedDBModule } from 'ngx-indexed-db';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {AppRoutingModule, routes} from "./app-routing.module";
import {AppComponent} from "./app.component";
import {RouterModule} from "@angular/router";
import {ManageDatasetsComponent} from "./components/manage-datasets/manage-datasets.component";
import {DatasourceListComponent} from "./components/datasource/datasource-list.component";
import {DragDropModule} from "@angular/cdk/drag-drop";
import {MatChipsModule} from "@angular/material/chips";

Expand All @@ -19,12 +19,12 @@ import {MatChipsModule} from "@angular/material/chips";
imports: [
BrowserModule,
AppRoutingModule,
NgxIndexedDBModule.forRoot(dbConfigIssueData, dataSetDbConfig),
NgxIndexedDBModule.forRoot(dbConfigIssueData, dbConfigCore),
FormsModule,
ToastrModule.forRoot(),
BrowserAnimationsModule,
RouterModule.forRoot(routes),
ManageDatasetsComponent,
DatasourceListComponent,
DragDropModule,
MatChipsModule
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
<form [formGroup]="datasetForm" (ngSubmit)="saveDataset()" class="edit-dataset-form">
<form [formGroup]="datasourceForm" (ngSubmit)="saveDataset()" class="edit-dataset-form">
<mat-grid-list cols="2" rowHeight="100px">
<mat-grid-tile colspan="2">
<mat-form-field appearance="fill">
<mat-label>Name</mat-label>
<input matInput id="name" formControlName="name" type="text" required/>
<mat-error *ngIf="datasetForm.get('name')?.hasError('required')">Name is required</mat-error>
<mat-error *ngIf="datasourceForm.get('name')?.hasError('required')">Name is required</mat-error>
</mat-form-field>
</mat-grid-tile>
<mat-grid-tile colspan="2">
<mat-form-field appearance="fill">
<mat-label>Base URL</mat-label>
<input matInput id="baseUrl" formControlName="baseUrl" type="text" required/>
<mat-error *ngIf="datasetForm.get('baseUrl')?.hasError('required')">Base URL is required</mat-error>
<mat-error *ngIf="datasetForm.get('baseUrl')?.hasError('pattern')">Invalid URL format</mat-error>
<mat-error *ngIf="datasourceForm.get('baseUrl')?.hasError('required')">Base URL is required</mat-error>
<mat-error *ngIf="datasourceForm.get('baseUrl')?.hasError('pattern')">Invalid URL format</mat-error>
</mat-form-field>
</mat-grid-tile>
<mat-grid-tile colspan="2">
<mat-form-field appearance="fill">
<mat-label>JQL</mat-label>
<input matInput id="jql" formControlName="jql" type="text" required/>
<mat-error *ngIf="datasetForm.get('jql')?.hasError('required')">JQL is required</mat-error>
<mat-error *ngIf="datasourceForm.get('jql')?.hasError('required')">JQL is required</mat-error>
</mat-form-field>
</mat-grid-tile>
<mat-grid-tile colspan="2">
<mat-form-field appearance="fill">
<mat-label>Type</mat-label>
<mat-select id="type" formControlName="type" required>
<mat-option *ngFor="let type of datasetTypes" [value]="type">{{ type }}</mat-option>
<mat-option *ngFor="let type of datasourceTypes" [value]="type">{{ type }}</mat-option>
</mat-select>
<mat-error *ngIf="datasetForm.get('type')?.hasError('required')">Type is required</mat-error>
<mat-error *ngIf="datasourceForm.get('type')?.hasError('required')">Type is required</mat-error>
</mat-form-field>
</mat-grid-tile>
<mat-grid-tile colspan="2">
<button mat-raised-button color="primary" type="submit" [disabled]="datasetForm.invalid">Save</button>
<button *ngIf="datasetId" mat-raised-button color="warn" type="button" (click)="deleteDataset()">Delete</button>
<button mat-raised-button color="primary" type="submit" [disabled]="datasourceForm.invalid">Save</button>
<button *ngIf="datasourceId" mat-raised-button color="warn" type="button" (click)="deleteDataset()">Delete
</button>
</mat-grid-tile>
</mat-grid-list>
</form>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { EditDatasetComponent } from './edit-dataset.component';
import {DatasourceEditComponent} from './datasource-edit.component';

describe('EditDatasetComponent', () => {
let component: EditDatasetComponent;
let fixture: ComponentFixture<EditDatasetComponent>;
let component: DatasourceEditComponent;
let fixture: ComponentFixture<DatasourceEditComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [EditDatasetComponent]
imports: [DatasourceEditComponent]
})
.compileComponents();

fixture = TestBed.createComponent(EditDatasetComponent);
fixture = TestBed.createComponent(DatasourceEditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import { StorageService } from '../../services/storage.service';
import {Dataset, DataSetType} from '../../models/dataset';
import {Datasource, DataSourceType} from '../../models/datasource';
import {MatGridList, MatGridTile} from "@angular/material/grid-list";
import {MatError, MatFormField, MatLabel} from "@angular/material/form-field";
import {MatInput} from "@angular/material/input";
import {MatButton} from "@angular/material/button";
import {MatOption, MatSelect} from "@angular/material/select";
import {NgForOf, NgIf} from "@angular/common";
import {ToastrService} from "ngx-toastr";
import {MANAGE_DATASETS} from "../../app-routing.module";
import {DATASOURCE_LIST} from "../../app-routing.module";
import {Status} from "../../models/status";
import {StatusMappingComponent} from "../status-mapping/status-mapping.component";

@Component({
selector: 'app-edit-dataset',
templateUrl: './edit-dataset.component.html',
templateUrl: './datasource-edit.component.html',
standalone: true,
imports: [
ReactiveFormsModule,
Expand All @@ -31,12 +31,12 @@ import {StatusMappingComponent} from "../status-mapping/status-mapping.component
NgForOf,
NgIf, MatError, StatusMappingComponent
],
styleUrls: ['./edit-dataset.component.scss']
styleUrls: ['./datasource-edit.component.scss']
})
export class EditDatasetComponent implements OnInit {
datasetForm: FormGroup;
datasetId?: number;
datasetTypes = Object.values(DataSetType);
export class DatasourceEditComponent implements OnInit {
datasourceForm: FormGroup;
datasourceId?: number;
datasourceTypes = Object.values(DataSourceType);
currentStates: Status[] = [];

constructor(
Expand All @@ -46,50 +46,50 @@ export class EditDatasetComponent implements OnInit {
private storageService: StorageService,
private toastr: ToastrService
) {
this.datasetForm = this.fb.group({
this.datasourceForm = this.fb.group({
name: [''],
baseUrl: ['', Validators.required],
jql: ['', Validators.required],
type: [this.datasetTypes[0]]
type: [this.datasourceTypes[0]]
});
}

async ngOnInit() {
this.datasetId = +this.route.snapshot.paramMap.get('id')!;
if (this.datasetId !== undefined && this.datasetId > 0) {
const dataset = await this.storageService.getDataset(this.datasetId);
this.datasetForm.patchValue({
this.datasourceId = +this.route.snapshot.paramMap.get('id')!;
if (this.datasourceId !== undefined && this.datasourceId > 0) {
const dataset = await this.storageService.getDatasource(this.datasourceId);
this.datasourceForm.patchValue({
name: dataset.name ?? '',
baseUrl: dataset.baseUrl ?? '',
jql: dataset.jql ?? '',
type: dataset.type ?? this.datasetTypes[0]
type: dataset.type ?? this.datasourceTypes[0]
});
this.currentStates = await this.storageService.getAllStatuses();
}
}

async saveDataset(): Promise<void> {
if (this.datasetForm.valid) {
const updatedDataset: Dataset = {
...this.datasetForm.value
if (this.datasourceForm.valid) {
const updatedDataset: Datasource = {
...this.datasourceForm.value
};
if (this.datasetId !== undefined && !isNaN(this.datasetId)) {
updatedDataset.id = this.datasetId;
await this.storageService.updateDataset(updatedDataset);
this.toastr.success('Dataset updated');
if (this.datasourceId !== undefined && !isNaN(this.datasourceId)) {
updatedDataset.id = this.datasourceId;
await this.storageService.updateDatasource(updatedDataset);
this.toastr.success('Datasource updated');
} else {
await this.storageService.createDataset(updatedDataset);
this.toastr.success('Dataset created');
this.toastr.success('Datasource created');
}
this.router.navigate([MANAGE_DATASETS]);
this.router.navigate([DATASOURCE_LIST]);
}
}

async deleteDataset(): Promise<void> {
if (this.datasetId) {
await this.storageService.removeDataset(this.datasetId);
this.toastr.success('Dataset deleted');
this.router.navigate([MANAGE_DATASETS]);
if (this.datasourceId) {
await this.storageService.removeDatasource(this.datasourceId);
this.toastr.success('Datasource deleted');
this.router.navigate([DATASOURCE_LIST]);
}
}
}
17 changes: 17 additions & 0 deletions src/app/components/datasource/datasource-list.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div>
<h2>Manage Datasource</h2>
<button mat-raised-button color="primary" (click)="createDatasource()">Create New Datasource</button>
<mat-list>
<mat-list-item *ngFor="let datasource of datasources">
<div>
{{ datasource.name }} - {{ datasource.jql }}
<button mat-icon-button (click)="editDatasource(datasource)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button (click)="removeDatasource(datasource)">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-list-item>
</mat-list>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// src/app/components/manage-datasets/manage-datasets.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatFormField, MatLabel } from "@angular/material/form-field";
Expand All @@ -10,14 +9,14 @@ import { NgForOf, NgIf } from "@angular/common";
import { MatInput } from "@angular/material/input";
import { MatSelect, MatOption } from "@angular/material/select";
import { StorageService } from '../../services/storage.service';
import {Dataset} from '../../models/dataset';
import {Datasource} from '../../models/datasource';
import {LayoutComponent} from "../layout/layout.component";
import {CREATE_DATASETS, MANAGE_DATASETS} from "../../app-routing.module";
import {DATASOURCE_CREATE, DATASOURCE_LIST} from "../../app-routing.module";
import {Router} from "@angular/router";

@Component({
selector: 'app-manage-datasets',
templateUrl: './manage-datasets.component.html',
selector: 'app-datasources-list',
templateUrl: './datasource-list.component.html',
standalone: true,
imports: [
MatFormField,
Expand All @@ -35,33 +34,31 @@ import {Router} from "@angular/router";
MatSelect,
MatOption
],
styleUrls: ['./manage-datasets.component.scss']
styleUrls: ['./datasource-list.component.scss']
})
export class ManageDatasetsComponent implements OnInit {
datasets: Dataset[] = [];
export class DatasourceListComponent implements OnInit {
datasources: Datasource[] = [];

constructor(
private storageService: StorageService,
private fb: FormBuilder,
private layoutComponent: LayoutComponent,
private router: Router
) {
}

async ngOnInit() {
this.datasets = await this.storageService.getAllDatasets();
this.datasources = await this.storageService.getAllDatasources();
}

async removeDataset(dataset: Dataset) {
await this.storageService.removeDataset(dataset.id!);
this.datasets = await this.storageService.getAllDatasets();
async removeDatasource(datasource: Datasource) {
await this.storageService.removeDatasource(datasource.id!);
this.datasources = await this.storageService.getAllDatasources();
}

editDataset(dataset: Dataset) {
this.router.navigate([MANAGE_DATASETS, dataset.id]);
editDatasource(datasource: Datasource) {
this.router.navigate([DATASOURCE_LIST, datasource.id]);
}

createDataset() {
this.router.navigate([CREATE_DATASETS]);
createDatasource() {
this.router.navigate([DATASOURCE_CREATE]);
}
}
12 changes: 6 additions & 6 deletions src/app/components/layout/layout.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<a mat-list-item [routerLink]="WORK_ITEM_AGE">Work Item Age</a>
<a mat-list-item [routerLink]="CYCLE_TIME">Cycle Time</a>
<a mat-list-item [routerLink]="THROUGHPUT">Throughput</a>
<a mat-list-item disabled routerLink="/settings">WIP</a>
<a mat-list-item [routerLink]="WORK_IN_PROGRESS">Work in Progress</a>
<a mat-list-item disabled routerLink="/settings">Monte Carlo Simulation</a>
</mat-nav-list>
</mat-sidenav>
Expand All @@ -29,14 +29,14 @@
clear Database
</button>
<mat-form-field appearance="outline">
<mat-label>Select Dataset</mat-label>
<mat-select [(value)]="selectedDataset" (selectionChange)="onDatasetChange($event)">
<mat-option *ngFor="let dataset of datasets" [value]="dataset.id">{{ dataset.name }}</mat-option>
<mat-label>Select Datasource</mat-label>
<mat-select [(value)]="selectedDatasource" (selectionChange)="onDatasourceChange($event)">
<mat-option *ngFor="let datasource of datasources" [value]="datasource.id">{{ datasource.name }}</mat-option>
</mat-select>
</mat-form-field>
<button mat-button [routerLink]="MANAGE_DATASETS">
<button mat-button [routerLink]="DATASOURCE_LIST">
<mat-icon>settings</mat-icon>
Manage Datasets
Manage Datasources
</button>
<button mat-button (click)="login()">
<mat-icon>login</mat-icon>
Expand Down
Loading

0 comments on commit 932019e

Please sign in to comment.