diff --git a/.detective/hash b/.detective/hash index 8c8ec7b..8db5d73 100644 --- a/.detective/hash +++ b/.detective/hash @@ -1 +1 @@ -01d56f87bc03708a2aa60ad75afeeaa3ac7c27ea, v1.1.2 \ No newline at end of file +481ca3c1072dd8cfcae952014df2a772701e1d5e, v1.1.2 \ No newline at end of file diff --git a/.detective/log b/.detective/log index fb75a26..9fcde86 100644 --- a/.detective/log +++ b/.detective/log @@ -1,3 +1,15 @@ +"Manfred Steyer ,Sat Sep 28 18:41:26 2024 +0200 fdc6882e65fb7a88afd40fb0850399808c6ed1d6,feat: add signal store to hotspot and team alignment analysis" +1 1 .detective/hash +3 2 .detective/log +1 1 .husky/pre-commit +7 3 apps/frontend/src/app/features/hotspot/hotspot.component.html +64 142 apps/frontend/src/app/features/hotspot/hotspot.component.ts +123 0 apps/frontend/src/app/features/hotspot/hotspot.store.ts +6 1 apps/frontend/src/app/features/team-alignment/team-alignment.component.html +25 46 apps/frontend/src/app/features/team-alignment/team-alignment.component.ts +56 0 apps/frontend/src/app/features/team-alignment/team-alignment.store.ts +1 1 apps/frontend/src/app/ui/graph/graph.ts + "Manfred Steyer ,Sat Sep 28 10:48:17 2024 +0200 854bde8ff89203de89c8a8f667162cfb93f6a2c4,chore: configure vscode to use single quotes" 1 1 .detective/hash 11 0 .detective/log diff --git a/apps/frontend/src/app/features/hotspot/hotspot.component.html b/apps/frontend/src/app/features/hotspot/hotspot.component.html index d265151..7f3b147 100644 --- a/apps/frontend/src/app/features/hotspot/hotspot.component.html +++ b/apps/frontend/src/app/features/hotspot/hotspot.component.html @@ -5,8 +5,7 @@ @@ -14,10 +13,7 @@ Complexity Metric - + @for (option of metricOptions; track option.id) { {{ option.label }} } diff --git a/apps/frontend/src/app/features/hotspot/hotspot.component.ts b/apps/frontend/src/app/features/hotspot/hotspot.component.ts index 65c7a42..db1e66a 100644 --- a/apps/frontend/src/app/features/hotspot/hotspot.component.ts +++ b/apps/frontend/src/app/features/hotspot/hotspot.component.ts @@ -31,8 +31,9 @@ import { LimitsComponent } from '../../ui/limits/limits.component'; import { debounceTimeSkipFirst } from '../../utils/debounce'; import { EventService } from '../../utils/event.service'; import { lastSegments } from '../../utils/segments'; +import { mirror } from '../../utils/signal-helpers'; -import { HotspotFilter, HotspotStore } from './hotspot.store'; +import { HotspotStore } from './hotspot.store'; interface Option { id: ComplexityMetric; @@ -80,9 +81,9 @@ export class HotspotComponent { totalCommits = this.statusStore.commits; limits = this.limitsStore.limits; - minScore = this.hotspotStore.filter.minScore; - metric = this.hotspotStore.filter.metric; - selectedModule = this.hotspotStore.filter.selectedModule; + minScore = mirror(this.hotspotStore.filter.minScore); + metric = mirror(this.hotspotStore.filter.metric); + selectedModule = mirror(this.hotspotStore.filter.module); loadingAggregated = this.hotspotStore.loadingAggregated; loadingHotspots = this.hotspotStore.loadingHotspots; @@ -97,21 +98,23 @@ export class HotspotComponent { formattedHotspots = computed(() => formatHotspots( this.hotspotResult().hotspots, - untracked(() => this.selectedModule()) + untracked(() => this.selectedModule().value()) ) ); constructor() { const loadAggregatedEvents = { filterChanged: this.eventService.filterChanged.pipe(startWith(null)), - minScore: toObservable(this.minScore).pipe(debounceTimeSkipFirst(300)), + minScore: toObservable(this.minScore().value).pipe( + debounceTimeSkipFirst(300) + ), limits: toObservable(this.limits).pipe(debounceTimeSkipFirst(300)), - metric: toObservable(this.metric), + metric: toObservable(this.metric().value), }; const loadHotspotEvent = { ...loadAggregatedEvents, - selectedModule: toObservable(this.selectedModule), + selectedModule: toObservable(this.selectedModule().value), }; const loadAggregatedOptions$ = combineLatest(loadAggregatedEvents).pipe( @@ -142,20 +145,15 @@ export class HotspotComponent { this.limitsStore.updateLimits(limits); } - updateFilter(filter: Partial): void { - this.hotspotStore.updateFilter(filter); - } - selectRow(row: AggregatedHotspot, index: number) { const selectedModule = this.aggregatedResult().aggregated[index].module; - this.hotspotStore.updateFilter({ - selectedModule, - }); + this.selectedModule().value.set(selectedModule); } isSelected(index: number) { const module = this.aggregatedResult().aggregated[index].module; - return module === this.selectedModule(); + const result = module === this.selectedModule().value(); + return result; } } diff --git a/apps/frontend/src/app/features/hotspot/hotspot.store.ts b/apps/frontend/src/app/features/hotspot/hotspot.store.ts index b0cd1fc..bc17081 100644 --- a/apps/frontend/src/app/features/hotspot/hotspot.store.ts +++ b/apps/frontend/src/app/features/hotspot/hotspot.store.ts @@ -18,7 +18,7 @@ import { injectShowError } from '../../utils/error-handler'; export type HotspotFilter = { minScore: number; metric: ComplexityMetric; - selectedModule: string; + module: string; }; export type LoadAggregateOptions = { @@ -37,7 +37,7 @@ export const HotspotStore = signalStore( filter: { minScore: 1, metric: 'Length', - selectedModule: '', + module: '', } as HotspotFilter, aggregatedResult: initAggregatedHotspotsResult, hotspotResult: initHotspotResult, @@ -53,13 +53,23 @@ export const HotspotStore = signalStore( _loadAggregated( options: LoadAggregateOptions ): Observable { - const criteria: HotspotCriteria = { + const filter = { metric: options.metric, minScore: options.minScore, + }; + + const criteria: HotspotCriteria = { + ...filter, module: '', }; - patchState(store, { loadingAggregated: true }); + patchState(store, (state) => ({ + loadingAggregated: true, + filter: { + ...state.filter, + ...filter, + }, + })); return hotspotService.loadAggregated(criteria, options.limits).pipe( tap(() => { @@ -80,7 +90,10 @@ export const HotspotStore = signalStore( module: options.selectedModule, }; - patchState(store, { loadingHotspots: true }); + patchState(store, { + loadingHotspots: true, + filter: criteria, + }); return hotspotService.load(criteria, options.limits).pipe( tap(() => { diff --git a/apps/frontend/src/app/ui/graph/graph.ts b/apps/frontend/src/app/ui/graph/graph.ts index bc0f397..56afa3b 100644 --- a/apps/frontend/src/app/ui/graph/graph.ts +++ b/apps/frontend/src/app/ui/graph/graph.ts @@ -111,7 +111,7 @@ function createGraph(container: HTMLElement, graph: Graph): cytoscape.Core { 'font-size': '14px', 'font-weight': 'bold', color: 'black', - }, + } as never, }, ], elements: { diff --git a/apps/frontend/src/app/utils/effects.ts b/apps/frontend/src/app/utils/signal-helpers.ts similarity index 51% rename from apps/frontend/src/app/utils/effects.ts rename to apps/frontend/src/app/utils/signal-helpers.ts index 13e5632..2e2e0bf 100644 --- a/apps/frontend/src/app/utils/effects.ts +++ b/apps/frontend/src/app/utils/signal-helpers.ts @@ -1,4 +1,4 @@ -import { Signal, effect, untracked } from '@angular/core'; +import { Signal, computed, effect, signal, untracked } from '@angular/core'; export function explicitEffect( source: Signal, @@ -20,3 +20,16 @@ export function onceEffect(action: () => void) { }); }); } + +export function mirror(source: Signal) { + const value = signal(source()); + return computed(() => { + untracked(() => { + value.set(source()); + }); + return { + source: source(), + value: value, + }; + }); +}