Skip to content

Commit 56e5809

Browse files
jankeromnesroboquat
authored andcommitted
[dashboard] Update Project Configurator UX
1 parent 06d93dc commit 56e5809

15 files changed

+301
-118
lines changed

components/dashboard/src/components/MonacoEditor.tsx

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,46 @@ import { useContext, useEffect, useRef } from "react";
88
import * as monaco from "monaco-editor";
99
import { ThemeContext } from "../theme-context";
1010

11-
export default function MonacoEditor(props: { classes: string, disabled?: boolean, language: string, value: string, onChange: (value: string) => void }) {
11+
monaco.editor.defineTheme('gitpod', {
12+
base: 'vs',
13+
inherit: true,
14+
rules: [],
15+
colors: {},
16+
});
17+
monaco.editor.defineTheme('gitpod-disabled', {
18+
base: 'vs',
19+
inherit: true,
20+
rules: [],
21+
colors: {
22+
'editor.background': '#F5F5F4', // Tailwind's warmGray 100 https://tailwindcss.com/docs/customizing-colors
23+
},
24+
});
25+
monaco.editor.defineTheme('gitpod-dark', {
26+
base: 'vs-dark',
27+
inherit: true,
28+
rules: [],
29+
colors: {
30+
'editor.background': '#292524', // Tailwind's warmGray 800 https://tailwindcss.com/docs/customizing-colors
31+
},
32+
});
33+
monaco.editor.defineTheme('gitpod-dark-disabled', {
34+
base: 'vs-dark',
35+
inherit: true,
36+
rules: [],
37+
colors: {
38+
'editor.background': '#44403C', // Tailwind's warmGray 700 https://tailwindcss.com/docs/customizing-colors
39+
},
40+
});
41+
42+
export interface MonacoEditorProps {
43+
classes: string;
44+
disabled?: boolean;
45+
language: string;
46+
value: string;
47+
onChange: (value: string) => void;
48+
}
49+
50+
export default function MonacoEditor(props: MonacoEditorProps) {
1251
const containerRef = useRef<HTMLDivElement>(null);
1352
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
1453
const { isDark } = useContext(ThemeContext);
@@ -22,10 +61,21 @@ export default function MonacoEditor(props: { classes: string, disabled?: boolea
2261
enabled: false,
2362
},
2463
renderLineHighlight: 'none',
64+
lineNumbers: 'off',
65+
glyphMargin: false,
66+
folding: false,
2567
});
2668
editorRef.current.onDidChangeModelContent(() => {
2769
props.onChange(editorRef.current!.getValue());
2870
});
71+
// 8px top margin: https://github.com/Microsoft/monaco-editor/issues/1333
72+
editorRef.current.changeViewZones(accessor => {
73+
accessor.addZone({
74+
afterLineNumber: 0,
75+
heightInPx: 8,
76+
domNode: document.createElement('div'),
77+
});
78+
});
2979
}
3080
return () => editorRef.current?.dispose();
3181
}, []);
@@ -37,14 +87,13 @@ export default function MonacoEditor(props: { classes: string, disabled?: boolea
3787
}, [ props.value ]);
3888

3989
useEffect(() => {
40-
monaco.editor.setTheme(isDark ? 'vs-dark' : 'vs');
41-
}, [ isDark ]);
42-
43-
useEffect(() => {
90+
monaco.editor.setTheme(props.disabled
91+
? (isDark ? 'gitpod-dark-disabled' : 'gitpod-disabled')
92+
: (isDark ? 'gitpod-dark' : 'gitpod'));
4493
if (editorRef.current) {
4594
editorRef.current.updateOptions({ readOnly: props.disabled });
4695
}
47-
}, [ props.disabled ]);
96+
}, [ props.disabled, isDark ]);
4897

4998
return <div className={props.classes} ref={containerRef} />;
5099
}

components/dashboard/src/components/PrebuildLogs.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import { getGitpodService } from "../service/service";
1111

1212
const WorkspaceLogs = React.lazy(() => import('./WorkspaceLogs'));
1313

14-
export default function PrebuildLogs(props: { workspaceId?: string }) {
14+
export interface PrebuildLogsProps {
15+
workspaceId?: string;
16+
onInstanceUpdate?: (instance: WorkspaceInstance) => void;
17+
}
18+
19+
export default function PrebuildLogs(props: PrebuildLogsProps) {
1520
const [ workspace, setWorkspace ] = useState<Workspace | undefined>();
1621
const [ workspaceInstance, setWorkspaceInstance ] = useState<WorkspaceInstance | undefined>();
1722
const [ error, setError ] = useState<Error | undefined>();
@@ -54,6 +59,9 @@ export default function PrebuildLogs(props: { workspaceId?: string }) {
5459
}, [ props.workspaceId ]);
5560

5661
useEffect(() => {
62+
if (props.onInstanceUpdate && workspaceInstance) {
63+
props.onInstanceUpdate(workspaceInstance);
64+
}
5765
switch (workspaceInstance?.status.phase) {
5866
// unknown indicates an issue within the system in that it cannot determine the actual phase of
5967
// a workspace. This phase is usually accompanied by an error.
@@ -107,16 +115,9 @@ export default function PrebuildLogs(props: { workspaceId?: string }) {
107115
}
108116
}, [ workspaceInstance?.status.phase ]);
109117

110-
return <>
111-
<Suspense fallback={<div />}>
112-
<WorkspaceLogs classes="h-64 w-full" logsEmitter={logsEmitter} errorMessage={error?.message} />
113-
</Suspense>
114-
<div className="mt-2 flex justify-center space-x-2">
115-
{workspaceInstance?.status.phase === 'stopped'
116-
? <a href={workspace?.contextURL ? '/#' + workspace.contextURL.replace(/^prebuild/, '') : undefined}><button>Open Workspace</button></a>
117-
: <button className="secondary disabled" disabled={true}>Open Workspace</button> }
118-
</div>
119-
</>;
118+
return <Suspense fallback={<div />}>
119+
<WorkspaceLogs classes="h-full w-full" logsEmitter={logsEmitter} errorMessage={error?.message} />
120+
</Suspense>;
120121
}
121122

122123
export function watchHeadlessLogs(instanceId: string, onLog: (chunk: string) => void, checkIsDone: () => Promise<boolean>): DisposableCollection {

components/dashboard/src/components/WorkspaceLogs.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@
55
*/
66

77
import EventEmitter from 'events';
8-
import { useEffect, useRef } from 'react';
8+
import { useContext, useEffect, useRef } from 'react';
99
import { Terminal, ITerminalOptions, ITheme } from 'xterm';
1010
import { FitAddon } from 'xterm-addon-fit'
1111
import 'xterm/css/xterm.css';
12+
import { ThemeContext } from '../theme-context';
13+
14+
const darkTheme: ITheme = {
15+
background: '#292524', // Tailwind's warmGray 800 https://tailwindcss.com/docs/customizing-colors
16+
};
17+
const lightTheme: ITheme = {
18+
background: '#F5F5F4', // Tailwind's warmGray 100 https://tailwindcss.com/docs/customizing-colors
19+
foreground: '#78716C', // Tailwind's warmGray 500 https://tailwindcss.com/docs/customizing-colors
20+
cursor: '#78716C', // Tailwind's warmGray 500 https://tailwindcss.com/docs/customizing-colors
21+
}
1222

1323
export interface WorkspaceLogsProps {
1424
logsEmitter: EventEmitter;
@@ -20,25 +30,25 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
2030
const xTermParentRef = useRef<HTMLDivElement>(null);
2131
const terminalRef = useRef<Terminal>();
2232
const fitAddon = new FitAddon();
33+
const { isDark } = useContext(ThemeContext);
2334

2435
useEffect(() => {
2536
if (!xTermParentRef.current) {
2637
return;
2738
}
28-
const theme: ITheme = {};
2939
const options: ITerminalOptions = {
3040
cursorBlink: false,
3141
disableStdin: true,
3242
fontSize: 14,
33-
theme,
43+
theme: darkTheme,
3444
scrollback: 9999999,
3545
};
3646
const terminal = new Terminal(options);
3747
terminalRef.current = terminal;
3848
terminal.loadAddon(fitAddon);
3949
terminal.open(xTermParentRef.current);
4050
props.logsEmitter.on('logs', logs => {
41-
if (fitAddon && terminal && logs) {
51+
if (terminal && logs) {
4252
terminal.write(logs);
4353
}
4454
});
@@ -53,7 +63,7 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
5363
let timeout: NodeJS.Timeout | undefined;
5464
const onWindowResize = () => {
5565
clearTimeout(timeout!);
56-
timeout = setTimeout(() => fitAddon!.fit(), 20);
66+
timeout = setTimeout(() => fitAddon.fit(), 20);
5767
};
5868
window.addEventListener('resize', onWindowResize);
5969
return function cleanUp() {
@@ -68,7 +78,14 @@ export default function WorkspaceLogs(props: WorkspaceLogsProps) {
6878
}
6979
}, [ terminalRef.current, props.errorMessage ]);
7080

71-
return <div className={`mt-6 ${props.classes || 'h-72 w-11/12 lg:w-3/5'} rounded-xl bg-black relative`}>
81+
useEffect(() => {
82+
if (!terminalRef.current) {
83+
return;
84+
}
85+
terminalRef.current.setOption('theme', isDark ? darkTheme : lightTheme);
86+
}, [ terminalRef.current, isDark ]);
87+
88+
return <div className={`${props.classes || 'mt-6 h-72 w-11/12 lg:w-3/5 rounded-xl overflow-hidden'} bg-gray-100 dark:bg-gray-800 relative`}>
7289
<div className="absolute top-0 left-0 bottom-0 right-0 m-6" ref={xTermParentRef}></div>
7390
</div>;
7491
}
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)