Skip to content

Commit 949f34c

Browse files
authored
Merge pull request #938 from nxnaxx/refactor/#900_extract-process-message
refactor(view): processMessage 함수 공통화 및 리팩토링
2 parents 0f35ed7 + 32e6552 commit 949f34c

12 files changed

Lines changed: 207 additions & 131 deletions

File tree

packages/view/src/components/@common/GithubIssueLink/GithubIssueLink.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@import "styles/app";
22

3-
.commit-message__issue-link {
3+
.github-issue-link {
44
color: var(--color-primary);
55
text-decoration: none;
66
font-weight: 500;

packages/view/src/components/@common/GithubIssueLink/GithubIssueLink.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const GithubIssueLink = ({ owner, repo, issueNumber, className, ...rest }: Githu
1111
href={issueLink}
1212
target="_blank"
1313
rel="noopener noreferrer"
14-
className={cn("commit-message__issue-link", className)}
14+
className={cn("github-issue-link", className)}
1515
title={`GitHub Issue #${issueNumber}`}
1616
{...rest}
1717
>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export { default as GithubIssueLink } from "./GithubIssueLink";
2+
export { renderIssueLinkedNodes } from "./renderIssueLinkedNodes";
3+
export type { IssueLinkedMessage } from "./types";
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { splitMessageByIssueRefs } from "utils/commitMessage";
2+
3+
import GithubIssueLink from "./GithubIssueLink";
4+
5+
export function renderIssueLinkedNodes(message: string, owner: string, repo: string) {
6+
return splitMessageByIssueRefs(message).map((part) => {
7+
if (part.type === "issue") {
8+
const issueNumber = part.value.substring(1);
9+
return (
10+
<GithubIssueLink
11+
key={`issue-${issueNumber}-${part.index}`}
12+
owner={owner}
13+
repo={repo}
14+
issueNumber={issueNumber}
15+
/>
16+
);
17+
}
18+
return part.value;
19+
});
20+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { ReactNode } from "react";
2+
3+
export type IssueLinkedMessage = {
4+
title: ReactNode[];
5+
body?: ReactNode[] | null;
6+
};

packages/view/src/components/Detail/Detail.tsx

Lines changed: 18 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect } from "react";
1+
import { useMemo } from "react";
22
import dayjs from "dayjs";
33
import {
44
AddCircleRounded,
@@ -13,26 +13,25 @@ import { Tooltip } from "@mui/material";
1313

1414
import { useGithubInfo, useDataStore } from "store";
1515
import { Author } from "components/@common/Author";
16-
import { GithubIssueLink } from "components/@common/GithubIssueLink";
16+
import type { IssueLinkedMessage } from "components/@common/GithubIssueLink";
17+
import { renderIssueLinkedNodes } from "components/@common/GithubIssueLink";
1718

1819
import { useCommitListHide } from "./Detail.hook";
1920
import { getCommitListDetail } from "./Detail.util";
2021
import { FIRST_SHOW_NUM } from "./Detail.const";
21-
import type { DetailProps, DetailSummaryProps, DetailSummaryItem, CommitItemProps, LinkedMessage } from "./Detail.type";
22+
import type { DetailProps, DetailSummaryProps, DetailSummaryItem, CommitItemProps } from "./Detail.type";
2223

2324
import "./Detail.scss";
2425

2526
const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
2627
const selectedData = useDataStore((state) => state.selectedData);
27-
const [linkedMessage, setLinkedMessage] = useState<LinkedMessage>({
28-
title: [],
29-
body: null,
30-
});
31-
3228
const { owner, repo } = useGithubInfo();
3329

34-
const commitNodeListInCluster =
35-
selectedData?.filter((selected) => selected.commitNodeList[0].clusterId === clusterId)[0].commitNodeList ?? [];
30+
const commitNodeListInCluster = useMemo(
31+
() =>
32+
selectedData?.filter((selected) => selected.commitNodeList[0].clusterId === clusterId)[0].commitNodeList ?? [],
33+
[selectedData, clusterId]
34+
);
3635
const { commitNodeList, toggle, handleToggle } = useCommitListHide(commitNodeListInCluster);
3736

3837
const isShow = commitNodeListInCluster.length > FIRST_SHOW_NUM;
@@ -41,63 +40,17 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
4140
navigator.clipboard.writeText(id);
4241
};
4342

44-
useEffect(() => {
45-
const processMessage = (message: string) => {
46-
// GitHub 이슈 번호 패턴: #123 또는 (#123)
47-
const regex = /(?:^|\s)(#\d+)(?:\s|$)/g;
48-
const parts: React.ReactNode[] = [];
49-
let lastIndex = 0;
50-
let match: RegExpExecArray | null;
51-
52-
while (true) {
53-
match = regex.exec(message);
54-
if (match === null) break;
55-
56-
// 이슈 번호 앞의 텍스트 추가
57-
if (match.index > lastIndex) {
58-
parts.push(message.slice(lastIndex, match.index));
59-
}
60-
61-
const issueNumber = match[1].substring(1);
43+
const issueLinkedMessage: IssueLinkedMessage = useMemo(() => {
44+
const message = commitNodeListInCluster?.[0]?.commit?.message;
45+
if (!message) return { title: [], body: null };
6246

63-
parts.push(
64-
<GithubIssueLink
65-
key={`issue-${issueNumber}-${match.index}`}
66-
owner={owner}
67-
repo={repo}
68-
issueNumber={issueNumber}
69-
/>
70-
);
47+
const [title, ...rest] = message.split("\n");
48+
const body = rest.filter((line) => line.trim()).join("\n");
7149

72-
lastIndex = match.index + match[0].length;
73-
}
74-
75-
// 마지막 부분 추가
76-
if (lastIndex < message.length) {
77-
parts.push(message.slice(lastIndex));
78-
}
79-
80-
return parts.length > 0 ? parts : [message];
50+
return {
51+
title: renderIssueLinkedNodes(title, owner, repo),
52+
body: body ? renderIssueLinkedNodes(body, owner, repo) : null,
8153
};
82-
83-
if (commitNodeListInCluster?.[0]?.commit?.message) {
84-
const { message } = commitNodeListInCluster[0].commit;
85-
const messageLines = message.split("\n");
86-
const title = messageLines[0];
87-
const body = messageLines
88-
.slice(1)
89-
.filter((line: string) => line.trim())
90-
.join("\n");
91-
92-
// 제목과 본문을 각각 처리
93-
const processedTitle = processMessage(title);
94-
const processedBody = body ? processMessage(body) : null;
95-
96-
setLinkedMessage({
97-
title: processedTitle,
98-
body: processedBody,
99-
});
100-
}
10154
}, [commitNodeListInCluster, owner, repo]);
10255

10356
if (!selectedData || selectedData.length === 0) return null;
@@ -114,7 +67,7 @@ const Detail = ({ clusterId, authSrcMap }: DetailProps) => {
11467
repo={repo}
11568
authSrcMap={authSrcMap}
11669
handleCommitIdCopy={handleCommitIdCopy}
117-
linkedMessage={linkedMessage}
70+
linkedMessage={issueLinkedMessage}
11871
/>
11972
))}
12073
</ul>

packages/view/src/components/Detail/Detail.type.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ import type { ReactNode } from "react";
33
import type { ClusterNode } from "types";
44
import type { Commit } from "types/Commit";
55
import type { AuthSrcMap } from "components/VerticalClusterList/Summary/Summary.type";
6-
7-
export type LinkedMessage = {
8-
title: ReactNode[];
9-
body: ReactNode[] | null;
10-
};
6+
import type { IssueLinkedMessage } from "components/@common/GithubIssueLink";
117

128
export type DetailProps = {
139
clusterId: number;
@@ -29,5 +25,5 @@ export interface CommitItemProps {
2925
repo: string;
3026
authSrcMap: AuthSrcMap | null;
3127
handleCommitIdCopy: (id: string) => () => Promise<void>;
32-
linkedMessage: LinkedMessage;
28+
linkedMessage: IssueLinkedMessage;
3329
}

packages/view/src/components/VerticalClusterList/Summary/Content/Content.tsx

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,17 @@
1-
import React, { useEffect, useState } from "react";
1+
import { useMemo } from "react";
22
import ArrowDropDownCircleRoundedIcon from "@mui/icons-material/ArrowDropDownCircleRounded";
33

44
import { useGithubInfo } from "store";
5-
import { GithubIssueLink } from "components/@common/GithubIssueLink";
5+
import type { IssueLinkedMessage } from "components/@common/GithubIssueLink";
6+
import { renderIssueLinkedNodes } from "components/@common/GithubIssueLink";
67

78
import type { ContentProps } from "../Summary.type";
89

9-
type LinkedMessage = {
10-
title: React.ReactNode[];
11-
};
12-
1310
const Content = ({ content, clusterId, selectedClusterIds }: ContentProps) => {
1411
const { owner, repo } = useGithubInfo();
15-
const [linkedMessage, setLinkedMessage] = useState<LinkedMessage>({
16-
title: [],
17-
});
18-
19-
useEffect(() => {
20-
const processMessage = (message: string) => {
21-
// GitHub 이슈 번호 패턴: #123 또는 (#123)
22-
const regex = /(?:^|\s)(#\d+)(?:\s|$)/g;
23-
const parts: React.ReactNode[] = [];
24-
let lastIndex = 0;
25-
let match: RegExpExecArray | null;
26-
27-
while (true) {
28-
match = regex.exec(message);
29-
if (match === null) break;
30-
31-
// 이슈 번호 앞의 텍스트 추가
32-
if (match.index > lastIndex) {
33-
parts.push(message.slice(lastIndex, match.index));
34-
}
35-
36-
const issueNumber = match[1].substring(1);
37-
38-
parts.push(
39-
<GithubIssueLink
40-
key={`issue-${issueNumber}-${match.index}`}
41-
owner={owner}
42-
repo={repo}
43-
issueNumber={issueNumber}
44-
/>
45-
);
46-
47-
lastIndex = match.index + match[0].length;
48-
}
49-
50-
// 마지막 부분 추가
51-
if (lastIndex < message.length) {
52-
parts.push(message.slice(lastIndex));
53-
}
54-
55-
return parts.length > 0 ? parts : [message];
56-
};
57-
58-
const messageLines = content.message.split("\n");
59-
const title = messageLines[0];
60-
61-
// 제목만 처리
62-
const processedTitle = processMessage(title);
6312

64-
setLinkedMessage({
65-
title: processedTitle,
66-
});
13+
const issueLinkedMessage: IssueLinkedMessage = useMemo(() => {
14+
return { title: renderIssueLinkedNodes(content.message.split("\n")[0], owner, repo) };
6715
}, [content.message, owner, repo]);
6816

6917
const messageLines = content.message.split("\n");
@@ -73,7 +21,9 @@ const Content = ({ content, clusterId, selectedClusterIds }: ContentProps) => {
7321
<>
7422
<div className="summary__content">
7523
<div className="summary__commit-message">
76-
<div className="summary__commit-title">{linkedMessage.title.length > 0 ? linkedMessage.title : title}</div>
24+
<div className="summary__commit-title">
25+
{issueLinkedMessage.title.length > 0 ? issueLinkedMessage.title : title}
26+
</div>
7727
</div>
7828
{content.count > 0 && <span className="summary__more-commit">+ {content.count} more</span>}
7929
</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type TextPart = { type: "text"; value: string };
2+
type IssueRefPart = { type: "issue"; value: string; index: number };
3+
4+
export type CommitMessagePart = TextPart | IssueRefPart;

packages/view/src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from "./Nodes";
33
export * from "./IDESentEvents";
44
export * from "./IDEMessage";
55
export * from "./Author";
6+
export * from "./CommitMessageParts";

0 commit comments

Comments
 (0)