Skip to content

Commit

Permalink
support multiple datasources
Browse files Browse the repository at this point in the history
  • Loading branch information
mario meltzow committed Aug 21, 2024
1 parent 72689b9 commit 34efaa5
Show file tree
Hide file tree
Showing 22 changed files with 154 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ export class CycleTimeScatterplotComponent {
}

async loadData() {
const items = await this.databaseService.getCycleTimeData();
const appSettings = await this.databaseService.getAppSettings();
const items = await this.databaseService.getCycleTimeData(appSettings.selectedDatasourceId);
items.sort((a, b) => a.issueId > b.issueId ? 1 : -1); // Sort items by issueId in descending order
this.percentilValue = this.businessLogicService.computePercentile(items.map(item => item.cycleTime), 80);
this.updateAnnotationLine(this.percentilValue);
Expand Down
8 changes: 4 additions & 4 deletions src/app/components/datasource/datasource-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ 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 {Datasource, DataSourceType} from '../../models/datasource';
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";
Expand Down Expand Up @@ -36,7 +36,7 @@ import {StatusMappingComponent} from "../status-mapping/status-mapping.component
export class DatasourceEditComponent implements OnInit {
datasourceForm: FormGroup;
datasourceId?: number;
datasourceTypes = Object.values(DataSourceType);
datasourceTypes = Object.values(DatasourceType);
currentStates: Status[] = [];

constructor(
Expand Down Expand Up @@ -64,7 +64,7 @@ export class DatasourceEditComponent implements OnInit {
jql: dataset.jql ?? '',
type: dataset.type ?? this.datasourceTypes[0]
});
this.currentStates = await this.storageService.getAllStatuses();
this.currentStates = await this.storageService.getAllStatuses(this.datasourceId);
}
}

Expand All @@ -78,7 +78,7 @@ export class DatasourceEditComponent implements OnInit {
await this.storageService.updateDatasource(updatedDataset);
this.toastr.success('Datasource updated');
} else {
await this.storageService.createDataset(updatedDataset);
await this.storageService.createDatasource(updatedDataset);
this.toastr.success('Datasource created');
}
this.router.navigate([DATASOURCE_LIST]);
Expand Down
14 changes: 7 additions & 7 deletions src/app/components/layout/layout.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {RouterLink, RouterOutlet} from "@angular/router";
import {MatSelectModule} from "@angular/material/select";
import {MatFormFieldModule} from "@angular/material/form-field";
import {StorageService} from "../../services/storage.service";
import {Datasource, DataSourceType} from "../../models/datasource";
import {Datasource, DatasourceType} from "../../models/datasource";
import {ToastrService} from "ngx-toastr";
import {
CYCLE_TIME,
Expand Down Expand Up @@ -93,10 +93,10 @@ export class LayoutComponent implements OnInit {

async login() {
if (this.selectedDatasource) {
const selectedDataset = this.datasources.find(dataset => dataset.id === this.selectedDatasource);
const selectedDatasource = this.datasources.find(dataset => dataset.id === this.selectedDatasource);
await this.storageService.saveAppSettings({selectedDatasourceId: this.selectedDatasource});
if (selectedDataset) {
if (selectedDataset.type === 'JIRA_CLOUD') {
if (selectedDatasource) {
if (selectedDatasource.type === 'JIRA_CLOUD') {
this.loginToJiraCloud();
} else {
this.loginToJiraDataCenter();
Expand Down Expand Up @@ -124,9 +124,9 @@ export class LayoutComponent implements OnInit {

async refreshIssues(silent = false) {
if (this.selectedDatasource) {
const selectedDataset = this.datasources.find(dataset => dataset.id === this.selectedDatasource);
if (selectedDataset) {
if (selectedDataset.type === DataSourceType.JIRA_CLOUD) {
const selectedDatasource = this.datasources.find(dataset => dataset.id === this.selectedDatasource);
if (selectedDatasource) {
if (selectedDatasource.type === DatasourceType.JIRA_CLOUD) {

await this.jiraCloudService.getAndSaveIssues(this.selectedDatasource!);
try {
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/monte-carlo/monte-carlo-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ export class MonteCarloPageComponent implements OnInit {
}

private async getThroughputsFromLast20Days(): Promise<number[]> {
const throughputEntries = await this.storageService.getThroughputData();
const appSettings = await this.storageService.getAppSettings();
const throughputEntries = await this.storageService.getThroughputData(appSettings.selectedDatasourceId);
const today = new Date();
const last20DaysThroughputs: number[] = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ export class StatusHistoryTableComponent implements OnInit {
}

async ngOnInit() {
const issueHistories = await this.storageService.getAllIssueHistoriesForStatuses();
const appSettings = await this.storageService.getAppSettings();
const issueHistories = await this.storageService.getAllIssueHistoriesForStatuses(appSettings.selectedDatasourceId);
const issuesIds = this.businessLogic.removeDuplicates(issueHistories.map(issueHistory => issueHistory.issueId), (a, b) => a == b);
const issues = await this.storageService.getIssuesByIds(issuesIds);

Expand Down
13 changes: 10 additions & 3 deletions src/app/components/status-mapping/status-mapping.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {StorageService} from '../../services/storage.service';
import {NgForOf} from "@angular/common";
import {MatChip} from "@angular/material/chips";
import {ToastrService} from "ngx-toastr";
import {ActivatedRoute, Router} from "@angular/router";

@Component({
selector: 'app-status-mapping',
Expand All @@ -22,13 +23,19 @@ export class StatusMappingComponent implements OnInit {
statuses: Status[] = [];
statusCategories = Object.values(StatusCategory);
connectedDropLists: string[] = [];
datasourceId?: number;

constructor(private storageService: StorageService, private toastr: ToastrService) {
constructor(private storageService: StorageService, private toastr: ToastrService, private route: ActivatedRoute,
private router: Router,) {
}

async ngOnInit() {
this.statuses = await this.storageService.getAllStatuses();
this.connectedDropLists = ['uncategorized', ...this.statusCategories.map(category => category)];
this.datasourceId = +this.route.snapshot.paramMap.get('id')!;
if (this.datasourceId !== undefined && this.datasourceId > 0) {
this.statuses = await this.storageService.getAllStatuses(this.datasourceId);
this.connectedDropLists = ['uncategorized', ...this.statusCategories.map(category => category)];
}

}

async drop(event: CdkDragDrop<Status[]>, categoryName: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export class ThroughputPageComponent implements OnInit {
constructor(private storageService: StorageService) {}

async ngOnInit() {
const throughputData: ThroughputEntry[] = await this.storageService.getThroughputData();
const appSettings = await this.storageService.getAppSettings();
const throughputData: ThroughputEntry[] = await this.storageService.getThroughputData(appSettings.selectedDatasourceId);
const allDates = this.generateAllDates(throughputData);
const mappedData = this.mapDataToDates(allDates, throughputData);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export class WorkInProgressPageComponent implements OnInit {
}

async ngOnInit() {
const wipData: WorkInProgressEntry[] = await this.storageService.getWorkInProgressData();
const appSettings = await this.storageService.getAppSettings();
const wipData: WorkInProgressEntry[] = await this.storageService.getWorkInProgressData(appSettings.selectedDatasourceId);
const allDates = this.generateAllDates(wipData);
const mappedData = this.mapDataToDates(allDates, wipData);

Expand Down
5 changes: 3 additions & 2 deletions src/app/components/work-item-age-page/work-item-age.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ export class WorkItemAgePage implements OnInit {
}

async loadData() {
let data = await this.databaseService.getWorkItemAgeData();
const appSettings = await this.databaseService.getAppSettings();
let data = await this.databaseService.getWorkItemAgeData(appSettings.selectedDatasourceId);

const statusInProgress = await this.databaseService.getAllStatuses().then(statuses => {
const statusInProgress = await this.databaseService.getAllStatuses(appSettings.selectedDatasourceId).then(statuses => {
return statuses.filter(status => status.category === StatusCategory.InProgress);
})

Expand Down
1 change: 1 addition & 0 deletions src/app/models/canceledCycleEntry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// a cycle is started if the issue switches into a inProgressState from a state that is not inProgressState
// because of this, it's possible that some issues has multiple cycles
export interface CanceledCycleEntry {
datasourceId: number;
id?: number;
issueId: number;
issueKey: string;
Expand Down
1 change: 1 addition & 0 deletions src/app/models/cycleTimeEntry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// a cycle is started if the issue switches into a inProgressState from a state that is not inProgressState
// because of this, it's possible that some issues has multiple cycles
export interface CycleTimeEntry {
datasourceId: number;
id?: number;
issueId: number;
issueKey: string;
Expand Down
4 changes: 2 additions & 2 deletions src/app/models/datasource.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export enum DataSourceType {
export enum DatasourceType {
JIRA_CLOUD = 'JIRA_CLOUD',
JIRA_DATACENTER = 'JIRA_DATACENTER',
}

//FIXME: rename this to datasource
export interface Datasource {
type: DataSourceType;
type: DatasourceType;
baseUrl: string;
access_token: string;
cloudId?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/app/models/issue.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface Issue {
dataSourceId: number;
datasourceId: number;
issueKey: string;
title: string;
createdDate: Date;
Expand Down
2 changes: 1 addition & 1 deletion src/app/models/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export enum StatusCategory {
}

export interface Status {
dataSourceId: number;
datasourceId: number;
id?: number;
name: string;
color?: string;
Expand Down
1 change: 1 addition & 0 deletions src/app/models/throughputEntry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface ThroughputEntry {
datasourceId: number;
issueIds: number[];
throughput: number;
date: Date;
Expand Down
1 change: 1 addition & 0 deletions src/app/models/workInProgressEntry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface WorkInProgressEntry {
datasourceId: number;
issueIds: number[];
wip: number;
date: Date;
Expand Down
1 change: 1 addition & 0 deletions src/app/models/workItemAgeEntry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface WorkItemAgeEntry {
id?: number;
datasourceId: number;
issueId: number;
issueKey: string;
title: string;
Expand Down
112 changes: 14 additions & 98 deletions src/app/services/business-logic.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,99 +25,12 @@ describe('BusinessLogicService', () => {
storageService = TestBed.inject(StorageService) as jasmine.SpyObj<StorageService>;
});

it('should return the latest resolved issue history', async () => {
const issueHistories: IssueHistory[] = [
{field: 'status', toValueId: 1, createdDate: new Date('2023-01-01')},
{field: 'status', toValueId: 2, createdDate: new Date('2023-02-01')}
] as IssueHistory[];

const statuses: Status[] = [
{
externalId: 1, category: StatusCategory.Done,
dataSourceId: 0,
name: 'resolved'
},
{
externalId: 2, category: StatusCategory.Done,
dataSourceId: 0,
name: 'wont do'
}
];

storageService.getAllStatuses.and.returnValue(Promise.resolve(statuses));

const result = await service.findLatestResolvedIssueHistory(issueHistories);
expect(result!.id).toEqual(issueHistories[1].id);
});

it('should return the first in-progress issue history', async () => {
const issueHistories: IssueHistory[] = [
{field: 'status', toValueId: 1, createdDate: new Date('2023-01-01')},
{field: 'status', toValueId: 2, createdDate: new Date('2023-02-01')}
] as IssueHistory[];

const statuses: Status[] = [
{
externalId: 1, category: StatusCategory.InProgress,
dataSourceId: 0,
name: 'In Arbeit'
},
{
externalId: 2, category: StatusCategory.InProgress,
dataSourceId: 0,
name: 'in review'
}
];

storageService.getAllStatuses.and.returnValue(Promise.resolve(statuses));

const result = await service.findFirstInProgressIssueHistory(issueHistories);
expect(result).toEqual(issueHistories[1]);
});

it('but If the issue was already in done, It should return the first in-progress issue history after reopen the issue', async () => {
const issueHistories: IssueHistory[] = [
{field: 'status', toValueId: 1, createdDate: new Date('2023-01-01'), id: 1},
{field: 'status', toValueId: 2, createdDate: new Date('2023-02-01'), id: 2},
{field: 'status', toValueId: 3, createdDate: new Date('2023-02-01'), id: 3},
//reopen the issue
{field: 'status', toValueId: 1, createdDate: new Date('2023-03-01'), id: 4},
{field: 'status', toValueId: 2, createdDate: new Date('2023-04-01'), id: 5},
] as IssueHistory[];

const statuses: Status[] = [
{
externalId: 2, category: StatusCategory.InProgress,
dataSourceId: 0,
name: 'in review',
order: 2 // the second in-progress status
},
{
externalId: 1, category: StatusCategory.InProgress,
dataSourceId: 0,
name: 'In Arbeit',
order: 1 // the first in-progress status
},
{
externalId: 3, category: StatusCategory.Done,
dataSourceId: 0,
name: 'Done',
order: 3
}
];

storageService.getAllStatuses.and.returnValue(Promise.resolve(statuses));

const result = await service.findFirstInProgressIssueHistory(issueHistories);
expect(result).toEqual(issueHistories[4]);
});

it('should map issue histories to cycle time entries', async () => {
const issue: Issue = {
id: 1,
issueKey: 'ISSUE-1',
title: 'Test Issue',
dataSourceId: 1,
datasourceId: 1,
createdDate: new Date('2023-01-01'),
status: 'Done',
externalStatusId: 3,
Expand Down Expand Up @@ -148,9 +61,9 @@ describe('BusinessLogicService', () => {
];

const statuses: Status[] = [
{externalId: 1, category: StatusCategory.ToDo, dataSourceId: 1, name: 'To Do'},
{externalId: 2, category: StatusCategory.InProgress, dataSourceId: 1, name: 'In Progress'},
{externalId: 3, category: StatusCategory.Done, dataSourceId: 1, name: 'Done'}
{externalId: 1, category: StatusCategory.ToDo, datasourceId: 1, name: 'To Do'},
{externalId: 2, category: StatusCategory.InProgress, datasourceId: 1, name: 'In Progress'},
{externalId: 3, category: StatusCategory.Done, datasourceId: 1, name: 'Done'}
];

storageService.getAllStatuses.and.returnValue(Promise.resolve(statuses));
Expand All @@ -170,7 +83,8 @@ describe('BusinessLogicService', () => {
status: 'Done',
externalStatusId: 3,
externalResolvedStatusId: 3,
externalInProgressStatusId: 2
externalInProgressStatusId: 2,
datasourceId: 1
}
];

Expand All @@ -182,7 +96,7 @@ describe('BusinessLogicService', () => {
id: 1,
issueKey: 'ISSUE-1',
title: 'Test Issue',
dataSourceId: 1,
datasourceId: 1,
createdDate: new Date('2023-01-01'),
status: 'Done',
externalStatusId: 3,
Expand Down Expand Up @@ -233,9 +147,9 @@ describe('BusinessLogicService', () => {
];

const statuses: Status[] = [
{externalId: 1, category: StatusCategory.ToDo, dataSourceId: 1, name: 'To Do'},
{externalId: 2, category: StatusCategory.InProgress, dataSourceId: 1, name: 'In Progress'},
{externalId: 3, category: StatusCategory.Done, dataSourceId: 1, name: 'Done'}
{externalId: 1, category: StatusCategory.ToDo, datasourceId: 1, name: 'To Do'},
{externalId: 2, category: StatusCategory.InProgress, datasourceId: 1, name: 'In Progress'},
{externalId: 3, category: StatusCategory.Done, datasourceId: 1, name: 'Done'}
];

storageService.getAllStatuses.and.returnValue(Promise.resolve(statuses));
Expand All @@ -255,7 +169,8 @@ describe('BusinessLogicService', () => {
status: 'Done',
externalStatusId: 3,
externalResolvedStatusId: 3,
externalInProgressStatusId: 2
externalInProgressStatusId: 2,
datasourceId: 1
},
{
inProgressState: 'In Progress',
Expand All @@ -269,7 +184,8 @@ describe('BusinessLogicService', () => {
status: 'Done',
externalStatusId: 3,
externalResolvedStatusId: 3,
externalInProgressStatusId: 2
externalInProgressStatusId: 2,
datasourceId: 1
}
];

Expand Down
Loading

0 comments on commit 34efaa5

Please sign in to comment.