Skip to content

Commit a64647c

Browse files
authored
refactor: 클러스터 모드 관련 불필요한 파일 및 모듈 삭제 (#964)
* refactor: FolderActivityFlow.analyzer.ts 파일 삭제 * refactor: util 파일 사용되지 않는 모듈 제거
1 parent ccd91ee commit a64647c

3 files changed

Lines changed: 1 addition & 313 deletions

File tree

packages/view/src/components/FolderActivityFlow/FolderActivityFlow.analyzer.ts

Lines changed: 0 additions & 86 deletions
This file was deleted.

packages/view/src/components/FolderActivityFlow/FolderActivityFlow.subfolder.ts

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,5 @@
11
import type { ClusterNode } from "types";
22

3-
import type { FolderActivity } from "./FolderActivityFlow.analyzer";
4-
5-
/**
6-
* Extract subfolders for cluster mode navigation
7-
*
8-
* @param totalData - Array of cluster nodes containing commit data
9-
* @param parentPath - Parent folder path to extract subfolders from (empty string for root)
10-
* @returns Array of folder activities sorted by total changes (max 8 items)
11-
*
12-
* @example
13-
* ```ts
14-
* const subFolders = getSubFolders(clusterData, "src/components");
15-
* // Returns: [{ folderPath: "src/components/FolderActivityFlow", totalChanges: 150, ... }, ...]
16-
* ```
17-
*/
18-
export function getSubFolders(totalData: ClusterNode[], parentPath: string): FolderActivity[] {
19-
if (totalData.length === 0) return [];
20-
21-
const subFolderStats = new Map<string, FolderActivity>();
22-
23-
totalData.forEach((cluster) => {
24-
cluster.commitNodeList.forEach((commitNode) => {
25-
const { commit } = commitNode;
26-
27-
Object.entries(commit.diffStatistics.files)
28-
.filter(([filePath]) => parentPath === "" || filePath.startsWith(`${parentPath}/`))
29-
.forEach(([filePath, stats]) => {
30-
const relativePath = parentPath === "" ? filePath : filePath.substring(parentPath.length + 1);
31-
const pathParts = relativePath.split("/");
32-
const subPath = pathParts[0];
33-
34-
if (subPath && subPath !== "." && subPath !== "") {
35-
const fullPath = parentPath === "" ? subPath : `${parentPath}/${subPath}`;
36-
37-
if (!subFolderStats.has(fullPath)) {
38-
subFolderStats.set(fullPath, {
39-
folderPath: fullPath,
40-
totalChanges: 0,
41-
insertions: 0,
42-
deletions: 0,
43-
commitCount: 0,
44-
});
45-
}
46-
47-
const folderActivity = subFolderStats.get(fullPath)!;
48-
folderActivity.insertions += stats.insertions;
49-
folderActivity.deletions += stats.deletions;
50-
folderActivity.totalChanges += stats.insertions + stats.deletions;
51-
}
52-
});
53-
});
54-
});
55-
56-
return Array.from(subFolderStats.values())
57-
.sort((a, b) => b.totalChanges - a.totalChanges)
58-
.slice(0, 8);
59-
}
60-
613
/**
624
* Extract subfolders for release mode navigation
635
*

packages/view/src/components/FolderActivityFlow/FolderActivityFlow.util.ts

Lines changed: 1 addition & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -2,181 +2,13 @@ import type * as d3 from "d3";
22

33
import type { ClusterNode } from "types";
44

5-
import { extractFolderFromPath, type FolderActivity } from "./FolderActivityFlow.analyzer";
65
import {
76
getTopFoldersByRelease,
87
extractReleaseContributorActivities,
98
type ReleaseGroup,
109
type ReleaseFolderActivity,
1110
} from "./FolderActivityFlow.releaseAnalyzer";
12-
import type {
13-
ContributorActivity,
14-
FlowLineData,
15-
ReleaseContributorActivity,
16-
ReleaseFlowLineData,
17-
} from "./FolderActivityFlow.type";
18-
19-
// 기여자 활동 데이터 추출
20-
export function extractContributorActivities(
21-
totalData: ClusterNode[],
22-
topFolders: FolderActivity[],
23-
currentPath: string
24-
): ContributorActivity[] {
25-
const contributorActivities: ContributorActivity[] = [];
26-
27-
totalData.forEach((cluster, clusterIndex) => {
28-
const clusterId = `cluster-${clusterIndex}`;
29-
30-
cluster.commitNodeList.forEach((commitNode) => {
31-
if (commitNode.commit.commitDate) {
32-
const { commit } = commitNode;
33-
const date = new Date(commit.commitDate);
34-
35-
if (commit.author?.names?.[0] && commit.author?.emails?.[0] && commit.diffStatistics?.files) {
36-
const contributorName = commit.author.names[0].trim();
37-
const contributorId = `${contributorName}-${commit.author.emails[0]}`;
38-
39-
const folderChanges = new Map<string, { insertions: number; deletions: number }>();
40-
41-
Object.entries(commit.diffStatistics.files).forEach(
42-
([filePath, stats]: [string, { insertions: number; deletions: number }]) => {
43-
let folderPath: string;
44-
45-
if (currentPath === "") {
46-
folderPath = extractFolderFromPath(filePath, 1);
47-
} else if (filePath.startsWith(`${currentPath}/`)) {
48-
const relativePath = filePath.substring(currentPath.length + 1);
49-
const pathParts = relativePath.split("/");
50-
folderPath = `${currentPath}/${pathParts[0]}`;
51-
} else {
52-
return;
53-
}
54-
55-
if (topFolders.some((f) => f.folderPath === folderPath)) {
56-
if (!folderChanges.has(folderPath)) {
57-
folderChanges.set(folderPath, { insertions: 0, deletions: 0 });
58-
}
59-
const folder = folderChanges.get(folderPath);
60-
if (folder) {
61-
folder.insertions += stats.insertions;
62-
folder.deletions += stats.deletions;
63-
}
64-
}
65-
}
66-
);
67-
68-
folderChanges.forEach((stats, folderPath) => {
69-
contributorActivities.push({
70-
contributorId,
71-
contributorName,
72-
date,
73-
folderPath,
74-
changes: stats.insertions + stats.deletions,
75-
insertions: stats.insertions,
76-
deletions: stats.deletions,
77-
clusterId,
78-
clusterIndex,
79-
});
80-
});
81-
}
82-
}
83-
});
84-
});
85-
86-
return contributorActivities.sort((a, b) => a.date.getTime() - b.date.getTime());
87-
}
88-
89-
// 플로우 라인 데이터 생성
90-
export function generateFlowLineData(contributorActivities: ContributorActivity[]): FlowLineData[] {
91-
const activitiesByContributor = new Map<string, ContributorActivity[]>();
92-
contributorActivities.forEach((activity) => {
93-
if (!activitiesByContributor.has(activity.contributorId)) {
94-
activitiesByContributor.set(activity.contributorId, []);
95-
}
96-
const activities = activitiesByContributor.get(activity.contributorId);
97-
if (activities) {
98-
activities.push(activity);
99-
}
100-
});
101-
102-
const flowLineData: FlowLineData[] = [];
103-
104-
activitiesByContributor.forEach((activities) => {
105-
activities.sort((a, b) => a.clusterIndex - b.clusterIndex || a.date.getTime() - b.date.getTime());
106-
107-
for (let i = 0; i < activities.length - 1; i += 1) {
108-
const current = activities[i];
109-
const next = activities[i + 1];
110-
111-
if (current.clusterIndex !== next.clusterIndex) {
112-
flowLineData.push({
113-
startClusterIndex: current.clusterIndex,
114-
startFolder: current.folderPath,
115-
endClusterIndex: next.clusterIndex,
116-
endFolder: next.folderPath,
117-
contributorName: current.contributorName,
118-
});
119-
}
120-
}
121-
});
122-
123-
return flowLineData;
124-
}
125-
126-
// 클러스터 내 노드 위치 계산
127-
export function calculateNodePosition(
128-
activity: ContributorActivity,
129-
xScale: d3.ScaleBand<string>,
130-
activitiesByCluster: Map<number, ContributorActivity[]>
131-
): number {
132-
const clusterX = (xScale(String(activity.clusterIndex)) || 0) + xScale.bandwidth() / 2;
133-
const clusterActivities = activitiesByCluster.get(activity.clusterIndex) || [];
134-
const activityIndex = clusterActivities.findIndex(
135-
(a) =>
136-
a.contributorId === activity.contributorId &&
137-
a.folderPath === activity.folderPath &&
138-
a.date.getTime() === activity.date.getTime()
139-
);
140-
const offsetRange = xScale.bandwidth() * 0.8;
141-
const offset =
142-
(activityIndex - (clusterActivities.length - 1) / 2) * (offsetRange / Math.max(clusterActivities.length, 1));
143-
return clusterX + offset;
144-
}
145-
146-
// 첫 번째 기여자 노드 찾기
147-
export function findFirstContributorNodes(
148-
contributorActivities: ContributorActivity[]
149-
): Map<string, ContributorActivity> {
150-
const firstNodesByContributor = new Map<string, ContributorActivity>();
151-
const sortedActivities = [...contributorActivities].sort(
152-
(a, b) => a.clusterIndex - b.clusterIndex || a.date.getTime() - b.date.getTime()
153-
);
154-
155-
sortedActivities.forEach((activity) => {
156-
const key = activity.contributorId;
157-
if (!firstNodesByContributor.has(key)) {
158-
firstNodesByContributor.set(key, activity);
159-
}
160-
});
161-
162-
return firstNodesByContributor;
163-
}
164-
165-
// 플로우 라인 경로 생성
166-
export function generateFlowLinePath(
167-
d: FlowLineData,
168-
xScale: d3.ScaleBand<string>,
169-
yScale: d3.ScaleBand<string>
170-
): string {
171-
const x1 = (xScale(String(d.startClusterIndex)) || 0) + xScale.bandwidth() / 2;
172-
const y1 = (yScale(d.startFolder) || 0) + yScale.bandwidth() / 2;
173-
const x2 = (xScale(String(d.endClusterIndex)) || 0) + xScale.bandwidth() / 2;
174-
const y2 = (yScale(d.endFolder) || 0) + yScale.bandwidth() / 2;
175-
const midX = (x1 + x2) / 2;
176-
return `M ${x1},${y1} Q ${midX},${y1} ${midX},${(y1 + y2) / 2} Q ${midX},${y2} ${x2},${y2}`;
177-
}
178-
179-
// === ReleaseTags 기반 유틸리티 함수들 ===
11+
import type { ReleaseContributorActivity, ReleaseFlowLineData } from "./FolderActivityFlow.type";
18012

18113
// 릴리즈 기반 상위 폴더 분석
18214
export function analyzeReleaseBasedFolders(

0 commit comments

Comments
 (0)