Skip to content

Commit 998e7f0

Browse files
committed
feat: add editor to benchmark detail
1 parent df301a7 commit 998e7f0

File tree

1 file changed

+231
-61
lines changed

1 file changed

+231
-61
lines changed
Lines changed: 231 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,231 @@
1-
import React, { useEffect, useState } from 'react';
2-
import { Redirect } from 'react-router-dom';
3-
import { BenchmarkServices } from '../../api/BenchmarkServices';
4-
import Header from '../Page/Header';
5-
import Page from '../Page/Page';
6-
7-
// @ts-ignore
8-
const BenchmarkDetail = (props) => {
9-
const [benchmark, setBenchmark] = useState();
10-
11-
useEffect(() => {
12-
let isMounted = true;
13-
BenchmarkServices.getBenchmarkById(props.match.params.id)
14-
.then((response) => {
15-
if (isMounted) {
16-
// @ts-ignore
17-
setBenchmark(response);
18-
}
19-
return () => {
20-
isMounted = false;
21-
};
22-
})
23-
.catch((e) => {
24-
// @ts-ignore
25-
setBenchmark('');
26-
console.log('Error : ' + e);
27-
});
28-
}, [setBenchmark, props.match.params.id]);
29-
30-
if (benchmark === ''|| undefined) {
31-
return <Redirect to="/404" />;
32-
}
33-
34-
return (
35-
<Page>
36-
<Header title={
37-
// @ts-ignore
38-
benchmark === undefined ? '' : benchmark.title}
39-
button='Back' navTo='/benchmarks'
40-
/>
41-
<div className="flex p-4">
42-
<div className="flex-1 mx-auto border-4 border-dashed border-gray-200 rounded-lg h-96">
43-
<div className="pl-8 pr-8">
44-
<h1 className="text-2xl pb-3">Subject</h1>
45-
<p>
46-
{
47-
// @ts-ignore
48-
benchmark === undefined ? '' : benchmark.subject
49-
}
50-
</p>
51-
</div>
52-
</div>
53-
<div className="flex-1 border-4 border-dashed border-gray-200 rounded-lg h-96">
54-
<h1>Here the editor</h1>
55-
</div>
56-
</div>
57-
</Page>
58-
);
59-
};
60-
61-
export default BenchmarkDetail;
1+
import React, { Fragment, useEffect, useRef, useState } from 'react';
2+
import { Redirect } from 'react-router-dom';
3+
import { BenchmarkServices } from '../../api/BenchmarkServices';
4+
import Header from '../Page/Header';
5+
import Page from '../Page/Page';
6+
import Editor from '@monaco-editor/react';
7+
import useProcessInterval from '../../hooks/submissions';
8+
import Result from '../Dashboard/Result';
9+
import { Listbox, Transition } from '@headlessui/react';
10+
import { CheckIcon, SelectorIcon } from '@heroicons/react/solid';
11+
12+
const languages = [
13+
{
14+
id: 1,
15+
name: 'python',
16+
avatar:
17+
'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Python-logo-notext.svg/768px-Python-logo-notext.svg.png',
18+
},
19+
{
20+
id: 2,
21+
name: 'go',
22+
avatar:
23+
'https://blog.engineering.publicissapient.fr/wp-content/uploads/2016/10/gopher.png',
24+
},
25+
{
26+
id: 3,
27+
name: 'c++',
28+
avatar:
29+
'https://upload.wikimedia.org/wikipedia/commons/1/18/ISO_C%2B%2B_Logo.svg',
30+
},
31+
];
32+
33+
// @ts-ignore
34+
const BenchmarkDetail = (props) => {
35+
const [benchmark, setBenchmark] = useState();
36+
const [selected, setSelected] = useState(languages[0]);
37+
38+
//Get monaco instance to access code later
39+
const editorRef: any = useRef<null>(null);
40+
41+
function handleEditorDidMount(editor: any, monaco: any) {
42+
editorRef.current = editor;
43+
}
44+
45+
// Handle code submission and job result polling
46+
const {
47+
mutate,
48+
data: jobData,
49+
isLoading: isProcessing,
50+
} = useProcessInterval({
51+
onSuccess: (data: any) => console.log('Process finished', data),
52+
onError: (err: any) => console.log('Error with process', err),
53+
});
54+
55+
let result;
56+
if (isProcessing) {
57+
result = 'Processing...';
58+
}
59+
if (jobData) {
60+
result = <Result status={jobData.status} output={jobData.output} />;
61+
}
62+
63+
useEffect(() => {
64+
let isMounted = true;
65+
BenchmarkServices.getBenchmarkById(props.match.params.id)
66+
.then((response) => {
67+
if (isMounted) {
68+
// @ts-ignore
69+
setBenchmark(response);
70+
}
71+
return () => {
72+
isMounted = false;
73+
};
74+
})
75+
.catch((e) => {
76+
// @ts-ignore
77+
setBenchmark('');
78+
console.log('Error : ' + e);
79+
});
80+
}, [setBenchmark, props.match.params.id]);
81+
82+
if (benchmark === '' || undefined) {
83+
return <Redirect to="/404" />;
84+
}
85+
86+
return (
87+
<Page>
88+
<Header
89+
title={
90+
// @ts-ignore
91+
benchmark === undefined ? '' : benchmark.title
92+
}
93+
button="Back"
94+
navTo="/benchmarks"
95+
/>
96+
<div className="flex p-4">
97+
<div className="flex-1 mx-auto border-4 border-dashed border-gray-200 rounded-lg h-96">
98+
<div className="pl-8 pr-8">
99+
<div className="flex justify-between">
100+
<h1 className="text-2xl pb-3">Subject</h1>
101+
<div className="">
102+
<Listbox value={selected} onChange={setSelected}>
103+
{({ open }) => (
104+
<>
105+
<Listbox.Label className="block text-sm font-medium text-gray-700">
106+
Languages
107+
</Listbox.Label>
108+
<div className="mt-1 relative">
109+
<Listbox.Button className="relative w-full bg-white border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
110+
<span className="flex items-center">
111+
<img
112+
src={selected.avatar}
113+
alt=""
114+
className="flex-shrink-0 h-6 w-6 rounded-full"
115+
/>
116+
<span className="ml-3 block truncate">
117+
{selected.name}
118+
</span>
119+
</span>
120+
<span className="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
121+
<SelectorIcon
122+
className="h-5 w-5 text-gray-400"
123+
aria-hidden="true"
124+
/>
125+
</span>
126+
</Listbox.Button>
127+
128+
<Transition
129+
show={open}
130+
as={Fragment}
131+
leave="transition ease-in duration-100"
132+
leaveFrom="opacity-100"
133+
leaveTo="opacity-0"
134+
>
135+
<Listbox.Options
136+
static
137+
className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
138+
>
139+
{languages.map((language) => (
140+
<Listbox.Option
141+
key={language.id}
142+
className={({ active }) => {
143+
return active
144+
? 'text-white bg-indigo-600'
145+
: 'text-gray-900' +
146+
'cursor-default select-none relative py-2 pl-3 pr-9';
147+
}}
148+
value={language}
149+
>
150+
{({ selected, active }) => (
151+
<>
152+
<div className="flex items-center">
153+
<img
154+
src={language.avatar}
155+
alt=""
156+
className="flex-shrink-0 h-6 w-6 rounded-full"
157+
/>
158+
<span
159+
className={
160+
selected
161+
? 'font-semibold'
162+
: 'font-normal' +
163+
'ml-3 block truncate'
164+
}
165+
>
166+
{language.name}
167+
</span>
168+
</div>
169+
170+
{selected ? (
171+
<span
172+
className={
173+
active
174+
? 'text-white'
175+
: 'text-indigo-600' +
176+
'absolute inset-y-0 right-0 flex items-center pr-4'
177+
}
178+
>
179+
<CheckIcon
180+
className="h-5 w-5"
181+
aria-hidden="true"
182+
/>
183+
</span>
184+
) : null}
185+
</>
186+
)}
187+
</Listbox.Option>
188+
))}
189+
</Listbox.Options>
190+
</Transition>
191+
</div>
192+
</>
193+
)}
194+
</Listbox>
195+
</div>
196+
</div>
197+
<p>
198+
{
199+
// @ts-ignore
200+
benchmark === undefined ? '' : benchmark.subject
201+
}
202+
</p>
203+
</div>
204+
</div>
205+
<div className="grid flex-1">
206+
<div className="border-4 border-dashed border-gray-200 rounded-lg h-96">
207+
<Editor
208+
onMount={handleEditorDidMount}
209+
height="100%"
210+
defaultLanguage="python"
211+
defaultValue={`print('hey!')`}
212+
/>
213+
</div>
214+
<div className="justify-self-start">{result && result}</div>
215+
<div className="justify-self-end flex-1">
216+
<button
217+
className="bg-blue-500 hover:bg-blue-700 text-white font-bold mt-2 py-2 px-4 rounded"
218+
onClick={() => {
219+
mutate(editorRef.current.getValue());
220+
}}
221+
>
222+
Run code
223+
</button>
224+
</div>
225+
</div>
226+
</div>
227+
</Page>
228+
);
229+
};
230+
231+
export default BenchmarkDetail;

0 commit comments

Comments
 (0)