Skip to content

Commit f5f33ed

Browse files
authored
Add real-time dashboard for viewing connected peripherals on the EV3 (#2229)
* Add optimised assets for SVG peripherals * Add customisable SVG assets * Mock up EV3 status UI * Update sling client dependency version * Add types for EV3 peripherals state * Prototype stateful update of EV3 peripherals status * Update EV3 type definitions * Refactor remote execution logic * Update UI for EV3 dashboard * Only show dashboard when connected * Remove hardcoding * Support multiple sensor measurement modes * Improve abstraction * Fix incorrectly displayed sensor value * Update imports * Remove log statement * Hide dashboard when nothing is plugged in for backwards compatibility * Update lockfile
1 parent 27f8de0 commit f5f33ed

15 files changed

Lines changed: 1864 additions & 65 deletions

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"@octokit/rest": "^19.0.3",
3333
"@sentry/browser": "^7.8.0",
3434
"@sourceacademy/sharedb-ace": "^2.0.2",
35-
"@sourceacademy/sling-client": "^0.0.1",
35+
"@sourceacademy/sling-client": "^0.1.0",
3636
"@types/react-syntax-highlighter": "^15.5.3",
3737
"@types/uuid": "^8.3.4",
3838
"ace-builds": "^1.4.14",
@@ -83,6 +83,7 @@
8383
},
8484
"devDependencies": {
8585
"@craco/craco": "^6.4.5",
86+
"@svgr/webpack": "^6.3.1",
8687
"@testing-library/react": "^12.1.2",
8788
"@testing-library/user-event": "^14.3.0",
8889
"@types/acorn": "^6.0.0",

src/assets/BrickSvg.tsx

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
const BrickSvg = () => (
2+
<div style={{ margin: '2em 1em' }}>
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
id="board-Layer_1"
6+
data-name="Layer 1"
7+
viewBox="0 0 110.73 170.04"
8+
width="138.92260644554224"
9+
height="213.33333333333334"
10+
>
11+
<defs>
12+
<linearGradient
13+
id="board-linear-gradient"
14+
x1="-374.89"
15+
y1="432.9"
16+
x2="-374.89"
17+
y2="432.82"
18+
gradientTransform="matrix(110.73 0 0 -106.94 41567.45 46425.3)"
19+
gradientUnits="userSpaceOnUse"
20+
>
21+
<stop offset="0" stopColor="#f1f1f1" />
22+
<stop offset="1" stopColor="#7a7a7a" />
23+
</linearGradient>
24+
<linearGradient
25+
id="board-linear-gradient-2"
26+
x1="-376"
27+
y1="450.74"
28+
x2="-376"
29+
y2="450.72"
30+
gradientTransform="matrix(100.11 0 0 -79.18 37697.19 35762.28)"
31+
gradientUnits="userSpaceOnUse"
32+
>
33+
<stop offset="0" stopColor="#a8aaa8" />
34+
<stop offset="1" stopColor="gray" />
35+
</linearGradient>
36+
<linearGradient
37+
id="board-linear-gradient-3"
38+
x1="-376.21"
39+
y1="614.94"
40+
x2="-376.21"
41+
y2="614.75"
42+
gradientTransform="matrix(98.29 0 0 -23.36 37033.43 14529.9)"
43+
gradientUnits="userSpaceOnUse"
44+
>
45+
<stop offset="0" stopColor="#a8aaa8" />
46+
<stop offset="1" stopColor="#535453" />
47+
</linearGradient>
48+
<linearGradient
49+
id="board-linear-gradient-black"
50+
x1="-382.07"
51+
y1="493.36"
52+
x2="-382.07"
53+
y2="494.25"
54+
gradientTransform="matrix(65.53 0 0 -48.84 25091.11 24228.69)"
55+
gradientUnits="userSpaceOnUse"
56+
>
57+
<stop offset="0" stopColor="#6a6a6a" />
58+
<stop offset=".52" stopColor="#6a6a6a" />
59+
<stop offset="1" stopColor="#6a6a6a" />
60+
</linearGradient>
61+
<linearGradient
62+
id="board-linear-gradient-green"
63+
x2="145"
64+
y2="48"
65+
gradientUnits="userSpaceOnUse"
66+
>
67+
<stop offset="0" stopColor="#6a6a6a" />
68+
<stop offset=".52" stopColor="#8CE300" />
69+
<stop offset="1" stopColor="#6a6a6a" />
70+
</linearGradient>
71+
<linearGradient
72+
id="board-linear-gradient-red"
73+
x2="145"
74+
y2="48"
75+
gradientUnits="userSpaceOnUse"
76+
>
77+
<stop offset="0" stopColor="#6a6a6a" />
78+
<stop offset=".52" stopColor="#D02E26" />
79+
<stop offset="1" stopColor="#6a6a6a" />
80+
</linearGradient>
81+
<linearGradient
82+
id="board-linear-gradient-orange"
83+
x2="145"
84+
y2="48"
85+
gradientUnits="userSpaceOnUse"
86+
>
87+
<stop offset="0" stopColor="#6a6a6a" />
88+
<stop offset=".52" stopColor="#F8D039" />
89+
<stop offset="1" stopColor="#6a6a6a" />
90+
</linearGradient>
91+
<linearGradient
92+
id="board-linear-gradient-5"
93+
x1="-743.87"
94+
y1="1256.85"
95+
x2="-743.87"
96+
y2="1257.21"
97+
gradientTransform="matrix(3.03 0 0 -6.22 2312.41 7891.56)"
98+
gradientUnits="userSpaceOnUse"
99+
>
100+
<stop offset="0" stopColor="#757575" />
101+
<stop offset="1" stopColor="#393939" />
102+
</linearGradient>
103+
<clipPath id="board-clip-path">
104+
<path fill="none" d="M86.48 149.58h12.38v12.38H86.48z" />
105+
</clipPath>
106+
</defs>
107+
<g id="board-EV3">
108+
<g id="board-brick">
109+
<path
110+
id="board-ev3_body_2"
111+
data-name="ev3 body 2"
112+
d="M2 31.7h106.76a2 2 0 0 1 2 2v103a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-103a2 2 0 0 1 2-2z"
113+
fill="url(#board-linear-gradient)"
114+
/>
115+
<path
116+
id="board-ev3_body_1"
117+
data-name="ev3 body 1"
118+
d="M8.19 127.57h94.35a2 2 0 0 1 2 2v38.53a2 2 0 0 1-2 2H8.19a2 2 0 0 1-2-2v-38.56a2 2 0 0 1 2-2z"
119+
fill="#f1f1f1"
120+
/>
121+
<path
122+
id="board-ev3_screen_grey"
123+
data-name="ev3 screen grey"
124+
d="M7.28 0h96.17a2 2 0 0 1 2 2v75.21a2 2 0 0 1-2 2H7.28a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2z"
125+
fill="url(#board-linear-gradient-2)"
126+
/>
127+
<path
128+
id="board-ev3_screenborder"
129+
data-name="ev3 screenborder"
130+
d="M18.2 10.47h74.48a3.79 3.79 0 0 1 3.79 3.79v41.86a3.8 3.8 0 0 1-3.79 3.8H18.2a3.8 3.8 0 0 1-3.79-3.8V14.26a3.79 3.79 0 0 1 3.79-3.79z"
131+
fill="#393939"
132+
/>
133+
<path
134+
id="board-ev3_screen"
135+
data-name="ev3 screen"
136+
d="M24 12.44h63.22A2.73 2.73 0 0 1 90 15.17v40.35a2.73 2.73 0 0 1-2.73 2.73H24a2.73 2.73 0 0 1-2.73-2.73V15.17A2.73 2.73 0 0 1 24 12.44z"
137+
fill="#97b5a6"
138+
/>
139+
<path
140+
id="board-ev3_grey_buttom"
141+
data-name="ev3 grey buttom"
142+
d="M6.22 146.68h98.29v21.39a2 2 0 0 1-2 2H8.19a2 2 0 0 1-2-2z"
143+
fill="url(#board-linear-gradient-3)"
144+
/>
145+
</g>
146+
<g id="board-buttons">
147+
<path
148+
id="board-btn_grey"
149+
data-name="btn grey"
150+
d="M48.69 133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27 8.27 0 1 1 0-16.53h3.41V99.5l14.13-14.41h14.11C69 91.61 76.75 99.2 76.75 99.2v2.13H80a8.27 8.27 0 1 1 0 16.53h-3.25v1.82c-7.51 7.73-14 14.26-14 14.26z"
151+
fill="#6a6a6a"
152+
/>
153+
<path
154+
id="board-btn_color"
155+
data-name="btn color"
156+
d="M48.69 133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27 8.27 0 1 1 0-16.53h3.41V99.5l14.13-14.41h14.11C69 91.61 76.75 99.2 76.75 99.2v2.13H80a8.27 8.27 0 1 1 0 16.53h-3.25v1.82c-7.51 7.73-14 14.26-14 14.26z"
157+
fill="url(#board-linear-gradient-black)"
158+
style={{ fill: 'url("#board-linear-gradient-black")' }}
159+
/>
160+
<path
161+
id="board-btn_left"
162+
data-name="btn left"
163+
d="M30.87 103.3h10.39v12.28H30.87a6.14 6.14 0 0 1-6.14-6.14 6.14 6.14 0 0 1 6.14-6.14z"
164+
fill="#a8aaa8"
165+
className="sim-button"
166+
/>
167+
<path
168+
id="board-btn_right"
169+
data-name="btn right"
170+
d="M80 115.58H69.62V103.3H80a6.14 6.14 0 0 1 6.15 6.14 6.14 6.14 0 0 1-6.15 6.14z"
171+
fill="#a8aaa8"
172+
className="sim-button"
173+
/>
174+
<path
175+
id="board-btn_enter"
176+
data-name="btn enter"
177+
d="M49.45 103.3h12a.46.46 0 0 1 .46.45v11.38a.46.46 0 0 1-.46.45h-12a.46.46 0 0 1-.46-.45v-11.38a.46.46 0 0 1 .46-.45z"
178+
fill="#393939"
179+
className="sim-button"
180+
/>
181+
<path
182+
id="board-btn_up"
183+
data-name="btn up"
184+
d="M49.15 87.37l12.74-.15 9.55 9.86L67.5 101v7.13h-3.64v-4.1a3 3 0 0 0-3-3H49.78a2.47 2.47 0 0 0-2.58 2.35v4.77h-3.67V101l-3.94-4z"
185+
fill="#a8aaa8"
186+
className="sim-button"
187+
/>
188+
<path
189+
id="board-btn_down"
190+
data-name="btn down"
191+
d="M61.83 131.54l-12.66.1-9.58-9.85 4-3.91v-7.17h3.6v4.11a3.06 3.06 0 0 0 3 3.06c3 .05 11 0 11 0a2.6 2.6 0 0 0 2.65-2.55v-4.62h3.67v7.17l3.91 3.91z"
192+
fill="#a8aaa8"
193+
className="sim-button"
194+
/>
195+
<path
196+
id="board-btn_part_4"
197+
data-name="btn part 4"
198+
fill="#393939"
199+
d="M54 59.76h3.03v13.8H54z"
200+
/>
201+
<path
202+
id="board-btn_part_3"
203+
data-name="btn part 3"
204+
fill="#9a9a9a"
205+
d="M54 72.96h3.03v6.07H54z"
206+
/>
207+
<path
208+
id="board-btn_part_2"
209+
data-name="btn part 2"
210+
fill="url(#board-linear-gradient-5)"
211+
d="M54 72.96h3.03v6.22H54z"
212+
/>
213+
<path
214+
id="board-btn_part_1"
215+
data-name="btn part 1"
216+
fill="gray"
217+
d="M54 79.18h3.03v5.92H54z"
218+
/>
219+
<path
220+
id="board-btn_back"
221+
data-name="btn back"
222+
d="M13.2 79.18h23.66v5.71c-2.62 2.64-6 6-6 6H15.17a2 2 0 0 1-2-2z"
223+
fill="#a8aaa8"
224+
className="sim-button"
225+
/>
226+
</g>
227+
<g id="board-LEGO_logo" data-name="LEGO logo">
228+
<path
229+
id="board-logo_white_bg"
230+
data-name="logo white bg"
231+
fill="#fff"
232+
d="M86.56 149.66h12.21v12.21H86.56z"
233+
/>
234+
<g id="board-lego">
235+
<g clipPath="url(#board-clip-path)">
236+
<g id="board-logo_part_5" data-name="logo part 5">
237+
<path
238+
id="board-Path_18"
239+
data-name="Path 18"
240+
d="M86.56 161.87h12.21v-12.21H86.56zM98 154.73a4.76 4.76 0 0 1-.24 1.18c-.43 1.27-.91 2.07-2.07 2.07a1.12 1.12 0 0 1-1.16-.7v-.15l-.09.11a1.86 1.86 0 0 1-1.46.72 1.29 1.29 0 0 1-1-.43l-.07-.09-.06.06a1.6 1.6 0 0 1-1.16.42 1.32 1.32 0 0 1-1-.37h-.09l-.07.07a1.55 1.55 0 0 1-1.11.37.87.87 0 0 1-.95-.79.37.37 0 0 1 0-.11 8.15 8.15 0 0 1 1.09-3.1 1 1 0 0 1 .92-.52.78.78 0 0 1 .57.17c.11.11.11.2.13.42v.28l.16-.24a1.6 1.6 0 0 1 1.52-.65 1 1 0 0 1 .9.37v.09l.06-.07a1.8 1.8 0 0 1 1.2-.39 1.53 1.53 0 0 1 1.12.37.69.69 0 0 1 .13.2l.07.11.08-.11a1.59 1.59 0 0 1 1.31-.57 1.27 1.27 0 0 1 1 .35 1.37 1.37 0 0 1 .26 1"
241+
fill="#ffed00"
242+
/>
243+
</g>
244+
</g>
245+
<g clipPath="url(#board-clip-path)">
246+
<g id="board-logo_part_4" data-name="logo part 4">
247+
<path
248+
id="board-Path_19"
249+
data-name="Path 19"
250+
d="M86.56 161.87h12.21v-12.21H86.56zm11.75-6.66a6.73 6.73 0 0 1-.52 1.59 2.28 2.28 0 0 1-2.1 1.55 1.67 1.67 0 0 1-1.36-.54 2.18 2.18 0 0 1-1.48.54 1.73 1.73 0 0 1-1.09-.35 2.12 2.12 0 0 1-1.22.35 1.8 1.8 0 0 1-1-.3 2.19 2.19 0 0 1-1.18.3 1.28 1.28 0 0 1-1.36-1.21 8.26 8.26 0 0 1 1.18-3.34 1.37 1.37 0 0 1 1.22-.8c.59 0 .79.17.9.37a2.24 2.24 0 0 1 1.46-.4 1.51 1.51 0 0 1 1 .33A2.4 2.4 0 0 1 94 153a1.74 1.74 0 0 1 1.36.45 2 2 0 0 1 1.33-.43 1.53 1.53 0 0 1 1.37.61 1.79 1.79 0 0 1 .29 1.55"
251+
fill="#d42715"
252+
/>
253+
</g>
254+
</g>
255+
<g clipPath="url(#board-clip-path)">
256+
<g id="board-logo_part_3" data-name="logo part 3">
257+
<path
258+
id="board-Path_20"
259+
data-name="Path 20"
260+
d="M86.48 162h12.38v-12.42H86.48zm12.2-.18h-12v-12h12z"
261+
fill="#171714"
262+
/>
263+
</g>
264+
</g>
265+
<g clipPath="url(#board-clip-path)">
266+
<g id="board-logo_part_2" data-name="logo part 2">
267+
<path
268+
id="board-Path_21"
269+
data-name="Path 21"
270+
d="M98.25 153.29v-.09h.06s.07 0 .07.05 0 0-.07 0zm.2.17v-.06c0-.05 0-.07-.06-.07a.09.09 0 0 0 .08-.09.07.07 0 0 0-.07-.08h-.17v.3h.07v-.13.07zm-.16-.39a.24.24 0 0 1 0 .48.24.24 0 0 1-.24-.24.26.26 0 0 1 .24-.24m0-.07a.31.31 0 0 0 0 .62.31.31 0 0 0 .31-.31.32.32 0 0 0-.31-.31"
271+
fill="#171714"
272+
/>
273+
</g>
274+
</g>
275+
<g clipPath="url(#board-clip-path)">
276+
<g id="board-logo_part_1" data-name="logo part 1">
277+
<path
278+
id="board-Path_22"
279+
data-name="Path 22"
280+
d="M96.7 153.33a1.73 1.73 0 0 0-1.38.61.66.66 0 0 0-.15-.22 1.47 1.47 0 0 0-1.16-.41 1.87 1.87 0 0 0-1.25.41 1.1 1.1 0 0 0-1-.41 1.7 1.7 0 0 0-1.6.7.52.52 0 0 0-.15-.46.87.87 0 0 0-.63-.2 1.1 1.1 0 0 0-1 .57 8.73 8.73 0 0 0-1.13 3.17 1 1 0 0 0 1 1h.08a1.53 1.53 0 0 0 1.18-.39 1.35 1.35 0 0 0 1 .39 1.61 1.61 0 0 0 1.23-.46 1.36 1.36 0 0 0 1.09.46 1.92 1.92 0 0 0 1.53-.77 1.2 1.2 0 0 0 1.24.75c1.2 0 1.73-.83 2.16-2.12a4.54 4.54 0 0 0 .27-1.2 1.21 1.21 0 0 0-1-1.37 1.29 1.29 0 0 0-.34 0m-8 3.28c.62-.11.79.11.77.33-.07.61-.63.76-1.12.74a.62.62 0 0 1-.69-.55 8.47 8.47 0 0 1 1.07-3 .72.72 0 0 1 .68-.39c.31 0 .37.15.37.33a14.2 14.2 0 0 1-1.07 2.55m2-.57c0 .11-.11.35-.17.59a3.1 3.1 0 0 1 .61-.09c.31 0 .48.14.48.38 0 .59-.66.76-1.11.76a.85.85 0 0 1-.94-.75v-.08a6 6 0 0 1 .67-2.27 1.36 1.36 0 0 1 1.53-.9c.31 0 .68.13.68.44s-.35.56-.68.59h-.5a3.58 3.58 0 0 0-.24.48c.64-.09.9 0 .79.41s-.59.52-1.12.44m3.13-1.55a.46.46 0 0 0-.37.21 6.33 6.33 0 0 0-.64 1.73c0 .28.09.35.22.35s.46-.24.55-.61c0 0-.42 0-.31-.37s.33-.44.68-.46c.7 0 .63.48.57.76a1.81 1.81 0 0 1-1.7 1.6.9.9 0 0 1-1-.79v-.18a5 5 0 0 1 .4-1.55c.37-.87.76-1.48 1.77-1.48.59 0 1.07.22 1 .76a.67.67 0 0 1-.64.68c-.11 0-.52 0-.39-.42 0-.13 0-.24-.15-.24m3.75.75a7.06 7.06 0 0 1-.59 1.61 1.41 1.41 0 0 1-1.37.86.82.82 0 0 1-.94-.86 5.11 5.11 0 0 1 .39-1.63c.31-.83.63-1.51 1.66-1.49s.94 1.05.85 1.51m-.85-.52a9.84 9.84 0 0 1-.63 1.85.33.33 0 0 1-.31.22c-.13 0-.17-.09-.2-.2a7.75 7.75 0 0 1 .7-1.94c.09-.13.18-.16.26-.13s.18.11.18.2"
281+
fill="#171714"
282+
/>
283+
</g>
284+
</g>
285+
</g>
286+
</g>
287+
<g id="board-EV3_logo" data-name="EV3 logo" fill="#f1f1f1">
288+
<path
289+
id="board-ev3_3"
290+
data-name="ev3 3"
291+
d="M36 155a.18.18 0 0 1 .2.16v.84a.16.16 0 0 1-.17.14H34a.36.36 0 0 0-.38.33v1.14a.34.34 0 0 0 .38.3h2c.19 0 .17.14.17.14v.82c0 .08-.06.14-.17.14h-3.43a.2.2 0 0 1-.2-.19v-.05a.38.38 0 0 0-.38-.38h-1.12a.38.38 0 0 0-.38.38v1.64a.37.37 0 0 0 .38.33h6.75a.36.36 0 0 0 .39-.3v-6.89a.36.36 0 0 0-.39-.3H30.9a.34.34 0 0 0-.38.3v1.67a.38.38 0 0 0 .35.38H32a.36.36 0 0 0 .35-.36v-.05a.17.17 0 0 1 .16-.19H36z"
292+
/>
293+
<path
294+
id="board-ev3_v"
295+
data-name="ev3 v"
296+
d="M29.29 153.2H27.7c-.24 0-.33.17-.44.38L25.32 158a.27.27 0 0 1-.19.11.23.23 0 0 1-.19-.14L23 153.58c-.11-.21-.22-.38-.46-.38h-1.62c-.35 0-.41.19-.3.41l3.2 6.73c.17.32.28.38.58.38h1.42a.55.55 0 0 0 .57-.38l3.22-6.73c.11-.22 0-.41-.32-.41"
297+
/>
298+
<path
299+
id="board-ev3_e"
300+
data-name="ev3 e"
301+
d="M19.39 156.1a.34.34 0 0 1 .38.3v1.17a.33.33 0 0 1-.38.3h-5.05c-.11 0-.2.06-.2.14v.82c0 .08.09.14.2.14h5.05a.33.33 0 0 1 .38.3v1.15a.33.33 0 0 1-.35.3h-6.75a.35.35 0 0 1-.38-.3v-6.89a.34.34 0 0 1 .38-.3h6.75a.31.31 0 0 1 .35.28v1.17a.31.31 0 0 1-.33.3h-5.08c-.11 0-.22 0-.22.13v.89c0 .08.09.14.19.14z"
302+
/>
303+
</g>
304+
</g>
305+
</svg>
306+
</div>
307+
);
308+
309+
export default BrickSvg;

src/assets/PortSvg.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
type Props = {
2+
port: string;
3+
};
4+
5+
const PortSvg = ({ port }: Props) => (
6+
<svg
7+
xmlns="http://www.w3.org/2000/svg"
8+
id="port-svg6348"
9+
viewBox="0 0 49.96 58.93"
10+
// width="50.28571428571429"
11+
// height="59.31419421251287"
12+
>
13+
<g id="port-icn_port" data-name="icn port">
14+
<path
15+
id="port-port_2"
16+
data-name="port 2"
17+
d="M4.48 0h50v58.93h-50z"
18+
transform="translate(-4.48)"
19+
fill="#eaeaea"
20+
/>
21+
<path
22+
id="port-port_1"
23+
data-name="port 1"
24+
d="M9.74 46.49V18.66h17.11v-6.91h4.72V2.59h12.92v8.82h5.06v35.08h-8v7.43H38.9v-7.51h-2v7.5h-2.19v-7.5h-2.16v7.5h-2.1v-7.5H28.6v7.5h-2.1v-7.5h-1.82v7.5h-2.46v-7.5h-1.68v7.5H18v-7.45z"
25+
transform="translate(-4.48)"
26+
fill="#a8aaa8"
27+
/>
28+
<g id="port-text10060" style={{ isolation: 'isolate' }}>
29+
<text
30+
id="port-port_text"
31+
transform="translate(22.21 40.2)"
32+
style={{ isolation: 'isolate', userSelect: 'none' }}
33+
fontSize="16"
34+
fill="#fff"
35+
fontFamily="ArialMT,Arial"
36+
>
37+
{port}
38+
</text>
39+
</g>
40+
</g>
41+
</svg>
42+
);
43+
44+
export default PortSvg;

0 commit comments

Comments
 (0)