From 31f55dedf115025e3935df8a511a83d942c81c28 Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 15:20:40 +0100 Subject: [PATCH 01/14] Simplify AddSegmentLabels() --- .../circular-heatmap/circular-heatmap.component.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.ts b/src/app/component/circular-heatmap/circular-heatmap.component.ts index d23d1cfff..787f91f31 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.ts +++ b/src/app/component/circular-heatmap/circular-heatmap.component.ts @@ -236,14 +236,10 @@ export class CircularHeatmapComponent implements OnInit { return undefined; } - private AddSegmentLabels(allDimensionNames: string[]) { - console.log(allDimensionNames); - for (var i = 0; i < allDimensionNames.length; i++) { - var allSubDimensionInThisDimension = Object.keys( - this.YamlObject[allDimensionNames[i]] - ); - for (var j = 0; j < allSubDimensionInThisDimension.length; j++) { - this.segment_labels.push(allSubDimensionInThisDimension[j]); + private AddSegmentLabels(yampObject: any[]) { + for (let dim in yampObject) { + for (let subdim in yampObject[dim]) { + this.segment_labels.push(subdim); } } console.log(this.segment_labels); From 58ba3f6b4594a9bacdc06e646e64223213ff981c Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 15:37:38 +0100 Subject: [PATCH 02/14] Simplify LoadMaturityDataFromGeneratedYaml() Include genuine teams from meta.yaml --- .../circular-heatmap.component.ts | 207 +++++++++--------- 1 file changed, 100 insertions(+), 107 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.ts b/src/app/component/circular-heatmap/circular-heatmap.component.ts index 787f91f31..3b6573228 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.ts +++ b/src/app/component/circular-heatmap/circular-heatmap.component.ts @@ -95,115 +95,48 @@ export class CircularHeatmapComponent implements OnInit { `${this.perfNow()}s: LoadMaturityDataFromGeneratedYaml Downloaded` ); this.YamlObject = data; - var allDimensionNames = Object.keys(this.YamlObject); - var totalTeamsImplemented: number = 0; - var totalActivityTeams: number = 0; - - this.AddSegmentLabels(allDimensionNames); - - for (var l = 0; l < this.maxLevelOfActivities; l++) { - for (var d = 0; d < allDimensionNames.length; d++) { - var allSubDimensionInThisDimension = Object.keys( - this.YamlObject[allDimensionNames[d]] - ); - for (var s = 0; s < allSubDimensionInThisDimension.length; s++) { - var allActivityInThisSubDimension = Object.keys( - this.YamlObject[allDimensionNames[d]][ - allSubDimensionInThisDimension[s] - ] + this.AddSegmentLabels(this.YamlObject); + const localStorageData = this.getDatasetFromBrowserStorage(); + + // Initialize the card array + let segmentTotalCount = this.segment_labels.length; + let cardTotalCount = segmentTotalCount * this.maxLevelOfActivities; + this.ALL_CARD_DATA = new Array(cardTotalCount).fill(null); + + // Process each card / sector + let subdimCount = -1; + for (let dim in this.YamlObject) { + for (let subdim in this.YamlObject[dim]) { + subdimCount++; + console.log(subdimCount, subdim); + let activities: Map = + this.processActivities( + this.YamlObject[dim][subdim], + localStorageData ); - var level = 'Level ' + (l + 1); - var activity: activitySchema[] = []; - var activityCompletionStatus: number = -1; - - for (var a = 0; a < allActivityInThisSubDimension.length; a++) { - try { - var uuid = - this.YamlObject[allDimensionNames[d]][ - allSubDimensionInThisDimension[s] - ][allActivityInThisSubDimension[a]]['uuid']; - - var lvlOfCurrentActivity = - this.YamlObject[allDimensionNames[d]][ - allSubDimensionInThisDimension[s] - ][allActivityInThisSubDimension[a]]['level']; - - if (lvlOfCurrentActivity == l + 1) { - var nameOfActivity: string = - allActivityInThisSubDimension[a]; - var teamStatus: { [key: string]: boolean } = {}; - const teams = this.teamList; - - totalActivityTeams += 1; - - teams.forEach((singleTeam: any) => { - teamStatus[singleTeam] = false; - }); - - var teamsImplemented: any = - this.YamlObject[allDimensionNames[d]][ - allSubDimensionInThisDimension[s] - ][allActivityInThisSubDimension[a]]['teamsImplemented']; - - if (teamsImplemented) { - teamStatus = teamsImplemented; - } - - var localStorageData = this.getFromBrowserState(); - - if ( - localStorageData != null && - localStorageData.length > 0 - ) { - this.YamlObject[allDimensionNames[d]][ - allSubDimensionInThisDimension[s] - ][allActivityInThisSubDimension[a]]['teamsImplemented'] = - this.getTeamImplementedFromJson( - localStorageData, - allActivityInThisSubDimension[a] - ); - } - - ( - Object.keys(teamStatus) as (keyof typeof teamStatus)[] - ).forEach((key, index) => { - totalActivityTeams += 1; - if (teamStatus[key] === true) { - totalTeamsImplemented += 1; - } - }); - - activity.push({ - uuid: uuid, - activityName: nameOfActivity, - teamsImplemented: teamStatus, - }); - } - - if (totalActivityTeams > 0) { - activityCompletionStatus = - totalTeamsImplemented / totalActivityTeams; - } - } catch { - console.log('level for activity does not exist'); - } - } + for ( + let level: number = 1; + level <= this.maxLevelOfActivities; + level++ + ) { + // Create and store each card (with activities for that level) var cardSchemaData: cardSchema = { - Dimension: allDimensionNames[d], - SubDimension: allSubDimensionInThisDimension[s], - Level: level, - 'Done%': activityCompletionStatus, - Activity: activity, + Dimension: dim, + SubDimension: subdim, + Level: 'Level ' + level, + 'Done%': -1, + Activity: activities.get(level) || [], }; - this.ALL_CARD_DATA.push(cardSchemaData); + // Store cards in sequential slots, by dimension then level + let levelIndex = (level - 1) * segmentTotalCount; + this.ALL_CARD_DATA[levelIndex + subdimCount] = cardSchemaData; } } } console.log('ALL CARD DATA', this.ALL_CARD_DATA); - this.loadState(); this.loadCircularHeatMap( this.ALL_CARD_DATA, '#chart', @@ -219,6 +152,55 @@ export class CircularHeatmapComponent implements OnInit { }); } + /** + * Returns activities of one subdimension, separated by maturity level. + * Source of activities is the cards from the server. + * + * Status of Team Implementation is merged from both server status and + * locally stored changes. + */ + private processActivities( + card: any, + localStorageData: any + ): Map { + let activities: Map = new Map(); + for (let activityName in card) { + let currentActivity: any = card[activityName]; + let level: number = currentActivity.level; + var uuid = currentActivity?.uuid; + + // Initialize a status for all genuine teams + let genuineTeams: any = {}; + this.teamList.forEach((singleTeam: string) => { + genuineTeams[singleTeam] = false; + }); + + // Read server and locally stored teams statuses as well + var teamsFromYaml: any = currentActivity.teamsImplemented; + var teamsFromLocalstorage: any = this.getTeamImplementedFromJson( + localStorageData, + activityName + ); + + // Combine the lot, where local changes takes priority + var combinedTeamsImplemented = Object.assign( + {}, + genuineTeams, + teamsFromYaml, + teamsFromLocalstorage + ); + + // Store each activity, split by maturity level + if (!activities.has(level)) activities.set(level, []); + activities.get(level)?.push({ + uuid: uuid, + activityName: activityName, + teamsImplemented: combinedTeamsImplemented, + }); + } + return activities; + } + private getTeamImplementedFromJson( data: ProjectData, activityName: string @@ -253,9 +235,17 @@ export class CircularHeatmapComponent implements OnInit { console.log(`${this.perfNow()}s: LoadTeamsFromMetaYaml Downloaded`); this.YamlObject = data; - this.teamList = this.YamlObject['teams']; + this.teamList = this.YamlObject['teams']; // Genuine teams (the true source) this.teamGroups = this.YamlObject['teamGroups']; this.teamVisible = [...this.teamList]; + + // Ensure that all team names in the groups are genuine team names + for (let team in this.teamGroups) { + this.teamGroups[team] = this.teamGroups[team].filter((t: string) => + this.teamList.includes(t) + ); + if (this.teamGroups[team].length == 0) delete this.teamGroups[team]; + } resolve(); }); }); @@ -822,22 +812,25 @@ export class CircularHeatmapComponent implements OnInit { } loadState() { - var content = localStorage.getItem('dataset'); + var content = this.getDatasetFromBrowserStorage(); + if (content != null) { + this.ALL_CARD_DATA = content; + } + } + + getDatasetFromBrowserStorage(): any { + console.log(`${this.perfNow()}s: getDatasetFromBrowserStorage() ####`); // @ts-ignore - if (this.ALL_CARD_DATA[0]['Task'] != null) { + if (this.ALL_CARD_DATA?.length && this.ALL_CARD_DATA[0]?.Task != null) { console.log('Found outdated dataset, removing'); localStorage.removeItem('dataset'); } - if (content != null) { - this.ALL_CARD_DATA = JSON.parse(content); - } - } - getFromBrowserState(): any { var content = localStorage.getItem('dataset'); if (content != null) { return JSON.parse(content); } + return null; } perfNow(): string { From fd922e8b9f85245dde6d0b50bc1efd5cac84f303 Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 15:50:43 +0100 Subject: [PATCH 03/14] Minor: Tidier console.l.og --- .../circular-heatmap/circular-heatmap.component.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.ts b/src/app/component/circular-heatmap/circular-heatmap.component.ts index 3b6573228..a48bfc121 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.ts +++ b/src/app/component/circular-heatmap/circular-heatmap.component.ts @@ -85,15 +85,10 @@ export class CircularHeatmapComponent implements OnInit { private LoadMaturityDataFromGeneratedYaml() { return new Promise((resolve, reject) => { - console.log( - `${this.perfNow()}s: LoadMaturityDataFromGeneratedYaml Fetch` - ); + console.log(`${this.perfNow()}s: LoadMaturityData Fetch`); this.yaml.setURI('./assets/YAML/generated/generated.yaml'); - this.yaml.getJson().subscribe(data => { - console.log( - `${this.perfNow()}s: LoadMaturityDataFromGeneratedYaml Downloaded` - ); + console.log(`${this.perfNow()}s: LoadMaturityData Downloaded`); this.YamlObject = data; this.AddSegmentLabels(this.YamlObject); const localStorageData = this.getDatasetFromBrowserStorage(); @@ -144,9 +139,7 @@ export class CircularHeatmapComponent implements OnInit { this.segment_labels ); this.noActivitytoGrey(); - console.log( - `${this.perfNow()}s: LoadMaturityDataFromGeneratedYaml End` - ); + console.log(`${this.perfNow()}s: LoadMaturityData End`); resolve(); }); }); From 49a95aa952ba8c75521540f7f14f58d445148582 Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 15:54:19 +0100 Subject: [PATCH 04/14] Renaming dataset functions and maxLevelOfMaturity --- .../circular-heatmap.component.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.ts b/src/app/component/circular-heatmap/circular-heatmap.component.ts index a48bfc121..bbae3a387 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.ts +++ b/src/app/component/circular-heatmap/circular-heatmap.component.ts @@ -41,7 +41,7 @@ type ProjectData = { }) export class CircularHeatmapComponent implements OnInit { Routing: string = '/activity-description'; - maxLevelOfActivities: number = -1; + maxLevelOfMaturity: number = -1; showActivityCard: boolean = false; cardHeader: string = ''; cardSubheader: string = ''; @@ -95,7 +95,7 @@ export class CircularHeatmapComponent implements OnInit { // Initialize the card array let segmentTotalCount = this.segment_labels.length; - let cardTotalCount = segmentTotalCount * this.maxLevelOfActivities; + let cardTotalCount = segmentTotalCount * this.maxLevelOfMaturity; this.ALL_CARD_DATA = new Array(cardTotalCount).fill(null); // Process each card / sector @@ -112,7 +112,7 @@ export class CircularHeatmapComponent implements OnInit { for ( let level: number = 1; - level <= this.maxLevelOfActivities; + level <= this.maxLevelOfMaturity; level++ ) { // Create and store each card (with activities for that level) @@ -257,7 +257,7 @@ export class CircularHeatmapComponent implements OnInit { for (let x in this.YamlObject['strings']['en']['maturity_levels']) { var y = parseInt(x) + 1; this.radial_labels.push('Level ' + y); - this.maxLevelOfActivities = y; + this.maxLevelOfMaturity = y; } resolve(); }); @@ -354,7 +354,7 @@ export class CircularHeatmapComponent implements OnInit { teamKey ]; - this.saveState(); + this.saveDataset(); this.reColorHeatmap(); } @@ -449,7 +449,6 @@ export class CircularHeatmapComponent implements OnInit { _self.activityData = curr.Activity; _self.cardHeader = curr.SubDimension; _self.showActivityCard = true; - //console.log(_self.activityData) }) .on('mouseover', function (d) { //console.log(d.toElement.__data__.Name) @@ -797,14 +796,14 @@ export class CircularHeatmapComponent implements OnInit { ResetIsImplemented() { localStorage.removeItem('dataset'); - this.loadState(); + this.loadDataset(); } - saveState() { + saveDataset() { localStorage.setItem('dataset', JSON.stringify(this.ALL_CARD_DATA)); } - loadState() { + loadDataset() { var content = this.getDatasetFromBrowserStorage(); if (content != null) { this.ALL_CARD_DATA = content; From 8aa9236a898a06ef93a3823737ae7ba639e13e1f Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 16:52:34 +0100 Subject: [PATCH 05/14] Display genuine teams in mat-card (sorted as in yaml) --- .../circular-heatmap/circular-heatmap.component.html | 11 +++++------ .../circular-heatmap/circular-heatmap.component.ts | 4 ++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.html b/src/app/component/circular-heatmap/circular-heatmap.component.html index 027d2d5a8..ec191be6c 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.html +++ b/src/app/component/circular-heatmap/circular-heatmap.component.html @@ -218,7 +218,7 @@

Nothing to show

{{ group.key }} @@ -264,13 +264,12 @@

Nothing to show

  • + *ngFor="let teamname of teamVisible"> - {{ item.key }} + (click)="this.teamCheckbox(activityIndex, teamname); $event.preventDefault()"> + {{ teamname }}
diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.ts b/src/app/component/circular-heatmap/circular-heatmap.component.ts index bbae3a387..446ff1879 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.ts +++ b/src/app/component/circular-heatmap/circular-heatmap.component.ts @@ -828,4 +828,8 @@ export class CircularHeatmapComponent implements OnInit { perfNow(): string { return (performance.now() / 1000).toFixed(3); } + + unsorted() { + return 0; + } } From 52533defc985bc1045ac4a66c9d19efb67e13ee5 Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 16:55:12 +0100 Subject: [PATCH 06/14] Linting --- .../circular-heatmap/circular-heatmap.component.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.html b/src/app/component/circular-heatmap/circular-heatmap.component.html index ec191be6c..4bba87ffc 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.html +++ b/src/app/component/circular-heatmap/circular-heatmap.component.html @@ -263,13 +263,15 @@

Nothing to show

    -
  • +
  • - {{ teamname }} + (click)=" + this.teamCheckbox(activityIndex, teamname); + $event.preventDefault() + "> + {{ teamname }}
From 7b4cf29ff0784caf692235cb881e7da119801438 Mon Sep 17 00:00:00 2001 From: Vegard Bakke Date: Sat, 4 Jan 2025 16:58:48 +0100 Subject: [PATCH 07/14] Export only genuine teams to new yaml file --- .../circular-heatmap.component.html | 2 +- .../circular-heatmap.component.ts | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/app/component/circular-heatmap/circular-heatmap.component.html b/src/app/component/circular-heatmap/circular-heatmap.component.html index 4bba87ffc..34c586d87 100644 --- a/src/app/component/circular-heatmap/circular-heatmap.component.html +++ b/src/app/component/circular-heatmap/circular-heatmap.component.html @@ -289,7 +289,7 @@

Nothing to show

class="normal-button" mat-raised-button class="downloadButtonClass" - (click)="SaveEditedYAMLfile()"> + (click)="saveEditedYAMLfile()"> Download edited YAML file