1- import { Component , OnInit } from '@angular/core' ;
1+ import { Component , OnInit , OnDestroy } from '@angular/core' ;
22import { equalArray } from 'src/app/util/util' ;
33import { LoaderService } from 'src/app/service/loader/data-loader.service' ;
44import * as d3 from 'd3' ;
5- import { Router } from '@angular/router' ;
5+ import { Router , ActivatedRoute } from '@angular/router' ;
6+ import { Location } from '@angular/common' ;
67import { MatChip } from '@angular/material/chips' ;
8+ import { Subject } from 'rxjs' ;
9+ import { takeUntil , distinctUntilChanged } from 'rxjs/operators' ;
710import * as md from 'markdown-it' ;
811import {
912 ModalMessageComponent ,
@@ -22,7 +25,7 @@ import { ThemeService } from '../../service/theme.service';
2225 templateUrl : './circular-heatmap.component.html' ,
2326 styleUrls : [ './circular-heatmap.component.css' ] ,
2427} )
25- export class CircularHeatmapComponent implements OnInit {
28+ export class CircularHeatmapComponent implements OnInit , OnDestroy {
2629 Routing : string = '/activity-description' ;
2730 markdown : md = md ( ) ;
2831 maxLevelOfMaturity : number = - 1 ;
@@ -52,10 +55,15 @@ export class CircularHeatmapComponent implements OnInit {
5255 theme : string ;
5356 theme_colors ! : Record < string , string > ;
5457
58+ private destroy$ = new Subject < void > ( ) ;
59+
5560 constructor (
5661 private loader : LoaderService ,
5762 private sectorService : SectorService ,
5863 private themeService : ThemeService ,
64+ private router : Router ,
65+ private route : ActivatedRoute ,
66+ private location : Location ,
5967 public modal : ModalMessageComponent
6068 ) {
6169 this . theme = this . themeService . getTheme ( ) ;
@@ -110,6 +118,9 @@ export class CircularHeatmapComponent implements OnInit {
110118 // For now, just draw the sectors (no activities yet)
111119 this . loadCircularHeatMap ( '#chart' , this . allSectors , this . dimensionLabels , this . maxLevel ) ;
112120 console . log ( `${ perfNow ( ) } : Page loaded: Circular Heatmap` ) ;
121+
122+ // Check if there's a URL fragment and open the corresponding activity
123+ this . checkUrlFragmentForActivity ( ) ;
113124 } )
114125 . catch ( err => {
115126 this . displayMessage ( new DialogInfo ( err . message , 'An error occurred' ) ) ;
@@ -119,7 +130,7 @@ export class CircularHeatmapComponent implements OnInit {
119130 } ) ;
120131 } ) ;
121132 // Reactively handle theme changes (if user toggles later)
122- this . themeService . theme$ . subscribe ( ( theme : string ) => {
133+ this . themeService . theme$ . pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( theme : string ) => {
123134 const css = getComputedStyle ( document . body ) ;
124135 this . theme_colors = {
125136 background : css . getPropertyValue ( '--heatmap-background' ) . trim ( ) ,
@@ -133,6 +144,22 @@ export class CircularHeatmapComponent implements OnInit {
133144 } ) ;
134145 }
135146
147+ ngOnDestroy ( ) : void {
148+ this . destroy$ . next ( ) ;
149+ this . destroy$ . complete ( ) ;
150+ }
151+
152+ checkUrlFragmentForActivity ( ) {
153+ // Check if there's a URL fragment that might be an activity UUID
154+ this . route . fragment
155+ . pipe ( takeUntil ( this . destroy$ ) , distinctUntilChanged ( ) )
156+ . subscribe ( fragment => {
157+ if ( fragment && this . dataStore ) {
158+ this . navigateToActivityByUuid ( fragment ) ;
159+ }
160+ } ) ;
161+ }
162+
136163 displayMessage ( dialogInfo : DialogInfo ) {
137164 this . modal . openDialog ( dialogInfo ) ;
138165 }
@@ -237,6 +264,14 @@ export class CircularHeatmapComponent implements OnInit {
237264 return this . sectorService . getSectorProgress ( sector . activities ) ;
238265 }
239266
267+ onDependencyClicked ( activityName : string ) {
268+ console . log ( `${ perfNow ( ) } : Heat: Dependency clicked: '${ activityName } '` ) ;
269+ const activity = this . dataStore ?. activityStore ?. getActivityByName ( activityName ) ;
270+ if ( activity ?. uuid ) {
271+ this . navigateToActivityByUuid ( activity . uuid ) ;
272+ }
273+ }
274+
240275 loadCircularHeatMap (
241276 dom_element_to_append_to : string ,
242277 dataset : any ,
@@ -540,38 +575,71 @@ export class CircularHeatmapComponent implements OnInit {
540575 console . log ( `${ perfNow ( ) } : Heat: Card Panel closed: '${ activity . name } '` ) ;
541576 }
542577
543- openActivityDetails ( dimension : string , activityName : string ) {
578+ openActivityDetails ( uuid : string ) {
544579 // Find the activity in the selected sector
545- console . log ( `${ perfNow ( ) } : Heat: Open Overlay: '${ activityName } '` ) ;
546- if ( ! this . dataStore ) {
547- console . error ( `Data store is not initialized. Cannot open activity ${ activityName } ` ) ;
580+ if ( ! this . dataStore || ! this . dataStore . activityStore ) {
581+ console . error ( `Data store is not initialized. Cannot open activity ${ uuid } ` ) ;
548582 return ;
549583 }
550584 if ( ! this . showActivityCard || ! this . showActivityCard . activities ) {
551585 this . showOverlay = true ;
552586 return ;
553587 }
554- const activity = this . showActivityCard . activities . find (
555- ( a : any ) => a . activityName === activityName || a . name === activityName
556- ) ;
588+
589+ const activity : Activity = this . dataStore . activityStore . getActivityByUuid ( uuid ) ;
557590 if ( ! activity ) {
558591 this . showOverlay = true ;
559592 return ;
560593 }
594+
561595 // Prepare navigationExtras and details
562596 /* eslint-disable */
597+ console . log ( `${ perfNow ( ) } : Heat: Open Overlay: '${ activity . name } '` ) ;
563598 this . showActivityDetails = activity ;
564599 this . KnowledgeLabel = this . dataStore . getMetaString ( 'knowledgeLabels' , activity . difficultyOfImplementation . knowledge ) ;
565600 this . TimeLabel = this . dataStore . getMetaString ( 'labels' , activity . difficultyOfImplementation . time ) ;
566601 this . ResourceLabel = this . dataStore . getMetaString ( 'labels' , activity . difficultyOfImplementation . resources ) ;
567602 this . UsefulnessLabel = this . dataStore . getMetaString ( 'labels' , activity . usefulness ) ;
568603 this . showOverlay = true ;
604+
605+ // Update URL with activity UUID as fragment
606+ if ( activity . uuid ) {
607+ this . router . navigate ( [ ] , {
608+ relativeTo : this . route ,
609+ fragment : activity . uuid ,
610+ queryParamsHandling : 'preserve'
611+ } ) ;
612+ }
569613 /* eslint-enable */
570614 }
571615
616+ navigateToActivityByUuid ( uuid : string ) {
617+ console . log ( `${ perfNow ( ) } : Heat: Attempting to open activity with UUID: ${ uuid } ` ) ;
618+ if ( ! this . dataStore || ! this . dataStore . activityStore ) {
619+ console . error ( 'Data store is not initialized. Cannot open activity by UUID' ) ;
620+ return ;
621+ }
622+ const activity : Activity = this . dataStore . activityStore . getActivityByUuid ( uuid ) ;
623+ const sector = this . allSectors . find ( s => s . activities . some ( a => a . uuid === uuid ) ) ;
624+ if ( activity && sector ) {
625+ this . selectedSector = sector ;
626+ this . showActivityCard = sector ;
627+ this . openActivityDetails ( activity . uuid ) ;
628+ } else {
629+ // Only close the overlay, do not update the URL
630+ this . showOverlay = false ;
631+ console . warn ( `Heat: Activity with UUID ${ uuid } not found.` ) ;
632+ }
633+ }
634+
572635 closeOverlay ( ) {
636+ // Clear the URL fragment when closing overlay
637+ this . router . navigate ( [ ] , {
638+ relativeTo : this . route ,
639+ fragment : undefined ,
640+ queryParamsHandling : 'preserve' ,
641+ } ) ;
573642 this . showOverlay = false ;
574- // console.log(`${perfNow()}: Heat: Close Overlay: '${this.old_activityDetails.name}'`);
575643 }
576644
577645 toggleFilters ( ) {
0 commit comments