1- import { Button , Editable , EditableInput , EditablePreview } from "@chakra-ui/react" ;
1+ import { Button , Editable , EditableInput , EditablePreview , useEditableControls } from "@chakra-ui/react" ;
2+ import { css } from "@emotion/react" ;
23import styled from "@emotion/styled" ;
3- import { FC } from "react" ;
4+ import { FC , ReactNode } from "react" ;
5+ import { MdDelete , MdEdit , MdPlayArrow } from "react-icons/md" ;
46import { useRecoilValue } from "recoil" ;
57
68import useTestcaseCommand from "@/commands/useTestcaseCommand" ;
79import useTestcaseRunner from "@/commands/useTestcaseRunner" ;
810import { testcaseFamily } from "@/states/testcase" ;
11+ import { TestcaseResult , testcaseResultFamily } from "@/states/testcaseResult" ;
12+
13+ import { getResultColor , getResultDescription } from "../common/renderResultUtil" ;
914
1015interface TestcaseInfoProps {
1116 testcaseId : string ;
@@ -15,29 +20,110 @@ const TestcaseInfo: FC<TestcaseInfoProps> = ({ testcaseId }) => {
1520 const command = useTestcaseCommand ( ) ;
1621 const runner = useTestcaseRunner ( ) ;
1722 const testcase = useRecoilValue ( testcaseFamily ( testcaseId ) ) ;
23+ const result = useRecoilValue ( testcaseResultFamily ( testcaseId ) ) ;
1824
1925 return (
2026 < StyledTestcaseInfo >
21- < Name value = { testcase . name } onChange = { ( name ) => command . changeValue ( testcaseId , { name } ) } fontSize = { 20 } >
22- < EditablePreview />
23- < EditableInput />
24- </ Name >
25- < Button onClick = { ( ) => runner . run ( testcaseId ) } > Run</ Button >
26- < Button onClick = { ( ) => command . remove ( testcaseId ) } > 삭제</ Button >
27+ < NameBox >
28+ < Name
29+ value = { testcase . name }
30+ placeholder = "이름 없음"
31+ onChange = { ( name ) => command . changeValue ( testcaseId , { name } ) }
32+ fontSize = { 20 } >
33+ < WithEditButton >
34+ < EditablePreview
35+ overflow = "hidden"
36+ textOverflow = "ellipsis"
37+ whiteSpace = "nowrap"
38+ display = "block"
39+ justifySelf = "normal"
40+ />
41+ </ WithEditButton >
42+ < EditableInput />
43+ </ Name >
44+ </ NameBox >
45+ < ActionBox >
46+ < ActionBoxLeft >
47+ < Button
48+ onClick = { ( ) => runner . run ( testcaseId ) }
49+ variant = "outline"
50+ size = "sm"
51+ leftIcon = { < MdPlayArrow /> }
52+ colorScheme = "teal"
53+ isLoading = { result === "running" } >
54+ 실행
55+ </ Button >
56+ < Result status = { result } > { getResultDescription ( result ) } </ Result >
57+ </ ActionBoxLeft >
58+ < Spacer />
59+ < Button
60+ onClick = { ( ) => command . remove ( testcaseId ) }
61+ variant = "outline"
62+ size = "sm"
63+ leftIcon = { < MdDelete /> }
64+ colorScheme = "red" >
65+ 삭제
66+ </ Button >
67+ </ ActionBox >
2768 </ StyledTestcaseInfo >
2869 ) ;
2970} ;
3071
3172export default TestcaseInfo ;
3273
33- const StyledTestcaseInfo = styled . div `
74+ const StyledTestcaseInfo = styled . div `` ;
75+
76+ const NameBox = styled . div `
77+ margin-top: 10px;
78+ height: 40px;
79+ ` ;
80+
81+ const ActionBox = styled . div `
3482 display: flex;
35- height: 3.5rem ;
83+ margin: 0 8px ;
3684` ;
3785
38- const Name = styled ( Editable ) `
86+ const ActionBoxLeft = styled . div `
87+ display: flex;
88+ align-items: center;
89+ ` ;
90+
91+ const Result = styled . div < { status : TestcaseResult } > `
92+ margin-left: 0.8rem;
93+ font-size: 0.85rem;
94+
95+ ${ ( props ) => css `
96+ color: ${ getResultColor ( props . status ) } ;
97+ ` }
98+ ` ;
99+
100+ const Spacer = styled . div `
39101 flex-grow: 1;
102+ ` ;
103+
104+ const Name = styled ( Editable ) `
40105 font-weight: 500;
41106 align-self: center;
42107 margin: 0 10px;
43108` ;
109+
110+ const WithEditButton = ( { children } : { children : ReactNode } ) => {
111+ const { isEditing, getEditButtonProps } = useEditableControls ( ) ;
112+
113+ return isEditing ? (
114+ < > </ >
115+ ) : (
116+ < StyledWithEditButton >
117+ { children }
118+ < Button size = "sm" variant = "link" { ...getEditButtonProps ( ) } >
119+ < MdEdit />
120+ </ Button >
121+ </ StyledWithEditButton >
122+ ) ;
123+ } ;
124+
125+ const StyledWithEditButton = styled . div `
126+ display: grid;
127+ grid-template-columns: max-content 20px 1fr;
128+ align-items: center;
129+ ` ;
0 commit comments