Skip to content

Commit

Permalink
Move GUI to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanBluefox committed Dec 11, 2024
1 parent 853d290 commit e635d14
Show file tree
Hide file tree
Showing 111 changed files with 17,953 additions and 12,873 deletions.
1,216 changes: 666 additions & 550 deletions src-editor/src/App.tsx

Large diffs are not rendered by default.

569 changes: 368 additions & 201 deletions src-editor/src/Components/BlocklyEditor.tsx

Large diffs are not rendered by default.

189 changes: 112 additions & 77 deletions src-editor/src/Components/Debugger/Console.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Box, IconButton } from '@mui/material';

Expand All @@ -9,18 +8,18 @@ import {
MdVerticalAlignBottom as IconBottom,
} from 'react-icons/md';

import { I18n, Utils } from '@iobroker/adapter-react-v5';
import { I18n, type IobTheme, Utils } from '@iobroker/adapter-react-v5';

const TOOLBOX_WIDTH = 34;

const styles = {
const styles: Record<string, any> = {
logBox: {
width: '100%',
height: '100%',
position: 'relative',
overflow: 'hidden',
},
logBoxInner: theme => ({
logBoxInner: (theme: IobTheme): React.CSSProperties => ({
display: 'inline-block',
color: theme.palette.mode === 'dark' ? 'white' : 'black',
width: `calc(100% - ${TOOLBOX_WIDTH}px)`,
Expand All @@ -30,24 +29,24 @@ const styles = {
position: 'relative',
verticalAlign: 'top',
}),
info: theme => ({
info: (theme: IobTheme): React.CSSProperties => ({
background: theme.palette.mode === 'dark' ? 'darkgrey' : 'lightgrey',
color: theme.palette.mode === 'dark' ? 'black' : 'black',
color: theme.palette.mode === 'dark' ? 'black' : 'black',
}),
error: theme => ({
error: (theme: IobTheme): React.CSSProperties => ({
background: '#FF0000',
color: theme.palette.mode === 'dark' ? 'black' : 'white',
color: theme.palette.mode === 'dark' ? 'black' : 'white',
}),
warn: theme => ({
warn: (theme: IobTheme): React.CSSProperties => ({
background: '#FF8000',
color: theme.palette.mode === 'dark' ? 'black' : 'white',
color: theme.palette.mode === 'dark' ? 'black' : 'white',
}),
debug: theme => ({
debug: (theme: IobTheme): React.CSSProperties => ({
background: 'gray',
opacity: 0.8,
color: theme.palette.mode === 'dark' ? 'black' : 'white',
color: theme.palette.mode === 'dark' ? 'black' : 'white',
}),
silly: theme => ({
silly: (theme: IobTheme): React.CSSProperties => ({
background: 'gray',
opacity: 0.6,
color: theme.palette.mode === 'dark' ? 'black' : 'white',
Expand All @@ -63,7 +62,8 @@ const styles = {
//marginLeft: 2,
width: TOOLBOX_WIDTH,
height: '100%',
boxShadow: '2px 0px 4px -1px rgba(0, 0, 0, 0.2), 4px 0px 5px 0px rgba(0, 0, 0, 0.14), 1px 0px 10px 0px rgba(0, 0, 0, 0.12)',
boxShadow:
'2px 0px 4px -1px rgba(0, 0, 0, 0.2), 4px 0px 5px 0px rgba(0, 0, 0, 0.14), 1px 0px 10px 0px rgba(0, 0, 0, 0.12)',
display: 'inline-block',
verticalAlign: 'top',
overflow: 'hidden',
Expand All @@ -82,9 +82,9 @@ const styles = {
},
};

function getTimeString(d) {
function getTimeString(d: Date): string {
let text;
let i = d.getHours();
let i: string | number = d.getHours();
if (i < 10) {
i = `0${i.toString()}`;
}
Expand All @@ -94,7 +94,7 @@ function getTimeString(d) {
if (i < 10) {
i = `0${i.toString()}`;
}
text += i + ':';
text += `${i}:`;
i = d.getSeconds();
if (i < 10) {
i = `0${i.toString()}`;
Expand All @@ -110,88 +110,123 @@ function getTimeString(d) {
return text;
}

class Console extends React.Component {
constructor(props) {
interface ConsoleProps {
onClearAllLogs: () => void;
console: { ts: number; text: string; severity: ioBroker.LogLevel }[];
}

interface ConsoleState {
goBottom: boolean;
}

class Console extends React.Component<ConsoleProps, ConsoleState> {
private readonly messagesEnd: React.RefObject<HTMLDivElement>;

constructor(props: ConsoleProps) {
super(props);
this.state = {
lines: {},
goBottom: true,
};
this.messagesEnd = React.createRef();
}
generateLine(message) {
return <Box
component="tr"
key={`tr_${message.ts}_${message.text.substr(-10)}`}
sx={styles[message.severity]}
>
<td style={styles.trTime}>{getTimeString(new Date(message.ts))}</td>
<td style={styles.trSeverity}>{message.severity}</td>
<td>{message.text}</td>
</Box>;

static generateLine(message: { ts: number; text: string; severity: ioBroker.LogLevel }): React.JSX.Element {
return (
<Box
component="tr"
key={`tr_${message.ts}_${message.text.substring(message.text.length - 10, message.text.length)}`}
sx={styles[message.severity]}
>
<td style={styles.trTime}>{getTimeString(new Date(message.ts))}</td>
<td style={styles.trSeverity}>{message.severity}</td>
<td>{message.text}</td>
</Box>
);
}
renderLogList(lines) {
if (lines && lines.length) {
return <Box sx={styles.logBoxInner} key="logList">
<table key="logTable" style={styles.table}>
<tbody>
{lines.map(line => this.generateLine(line))}
</tbody>
</table>
<div key="logScrollPoint" ref={this.messagesEnd} style={{ float: 'left', clear: 'both' }}/>
</Box>;

renderLogList(lines: { ts: number; text: string; severity: ioBroker.LogLevel }[]): React.JSX.Element {
if (lines?.length) {
return (
<Box
sx={styles.logBoxInner}
key="logList"
>
<table
key="logTable"
style={styles.table}
>
<tbody>{lines.map(line => Console.generateLine(line))}</tbody>
</table>
<div
key="logScrollPoint"
ref={this.messagesEnd}
style={{ float: 'left', clear: 'both' }}
/>
</Box>
);
}
return <Box key="logList" sx={styles.logBoxInner} style={{ paddingLeft: 10 }}>{I18n.t('Log outputs')}</Box>;
return (
<Box
key="logList"
sx={styles.logBoxInner}
style={{ paddingLeft: 10 }}
>
{I18n.t('Log outputs')}
</Box>
);
}

onCopy() {
onCopy(): void {
Utils.copyToClipboard(this.props.console.join('\n'));
}

scrollToBottom() {
this.messagesEnd && this.messagesEnd.current && this.messagesEnd.current.scrollIntoView({behavior: 'smooth'});
scrollToBottom(): void {
this.messagesEnd?.current?.scrollIntoView({ behavior: 'smooth' });
}

componentDidUpdate() {
componentDidUpdate(): void {
this.state.goBottom && this.scrollToBottom();
}

render() {
render(): React.JSX.Element {
const lines = this.props.console;
return <div style={styles.logBox}>
<div style={styles.toolbox} key="toolbox">
<IconButton
style={styles.iconButtons}
onClick={() => this.setState({ goBottom: !this.state.goBottom })}
color={this.state.goBottom ? 'secondary' : ''}
size="medium"
>
<IconBottom />
</IconButton>
{lines && lines.length ? <IconButton
style={styles.iconButtons}
onClick={() => this.props.onClearAllLogs()}
size="medium"
return (
<div style={styles.logBox}>
<div
style={styles.toolbox}
key="toolbox"
>
<IconDelete />
</IconButton> : null}
{lines && lines.length ? <IconButton
style={styles.iconButtons}
onClick={() => this.onCopy()}
size="medium"
>
<IconCopy />
</IconButton> : null}
<IconButton
style={styles.iconButtons}
onClick={() => this.setState({ goBottom: !this.state.goBottom })}
color={this.state.goBottom ? 'secondary' : undefined}
size="medium"
>
<IconBottom />
</IconButton>
{lines?.length ? (
<IconButton
style={styles.iconButtons}
onClick={() => this.props.onClearAllLogs()}
size="medium"
>
<IconDelete />
</IconButton>
) : null}
{lines?.length ? (
<IconButton
style={styles.iconButtons}
onClick={() => this.onCopy()}
size="medium"
>
<IconCopy />
</IconButton>
) : null}
</div>
{this.renderLogList(lines)}
</div>
{this.renderLogList(lines)}
</div>;
);
}
}

Console.propTypes = {
theme: PropTypes.object,
onClearAllLogs: PropTypes.func,
console: PropTypes.array,
};

export default Console;
94 changes: 49 additions & 45 deletions src-editor/src/Components/Debugger/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,69 @@
import React from 'react';
import PropTypes from 'prop-types';
import ScriptEditorComponent from '../ScriptEditorVanilaMonaco';
import type { AdminConnection, ThemeName, ThemeType } from '@iobroker/adapter-react-v5';

const styles = {
import type { DebuggerLocation, SetBreakpointParameterType } from './types';

const styles: Record<string, React.CSSProperties> = {
editorDiv: {
height: '100%',
width: '100%',
overflow: 'hidden',
position: 'relative'
position: 'relative',
},
};

class Editor extends React.Component {
constructor(props) {
interface EditorProps {
runningInstances: Record<string, boolean>;
socket: AdminConnection;
sourceId: string | null;
script: string;
scriptName: string;
adapterName: string;
paused: boolean;
breakpoints: SetBreakpointParameterType[];
location: DebuggerLocation | null;
themeType: ThemeType;
themeName: ThemeName;
onToggleBreakpoint: (i: number) => void;
}

interface EditorState {
lines: string[];
}

class Editor extends React.Component<EditorProps, EditorState> {
constructor(props: EditorProps) {
super(props);

this.state = {
lines: (this.props.script || '').split(/\r\n|\n/)
lines: (this.props.script || '').split(/\r\n|\n/),
};
}

editorDidMount(editor, monaco) {
this.monaco = monaco;
this.editor = editor;
editor.focus();
}

render() {
return <div style={styles.editorDiv} key="scriptEditorDiv2">
<ScriptEditorComponent
key="scriptEditor2"
name={this.props.scriptName}
adapterName={this.props.adapterName}
readOnly
code={this.props.script || ''}
isDark={this.props.themeType === 'dark'}
socket={this.props.socket}
runningInstances={this.props.runningInstances}
language={'javascript'}

breakpoints={this.props.breakpoints}
location={this.props.paused ? this.props.location : null}
onToggleBreakpoint={i => this.props.onToggleBreakpoint(i)}
/>
</div>;
render(): React.JSX.Element {
return (
<div
style={styles.editorDiv}
key="scriptEditorDiv2"
>
<ScriptEditorComponent
key="scriptEditor2"
name={this.props.scriptName}
adapterName={this.props.adapterName}
readOnly
code={this.props.script || ''}
isDark={this.props.themeType === 'dark'}
socket={this.props.socket}
runningInstances={this.props.runningInstances}
language={'javascript'}
breakpoints={this.props.breakpoints}
location={this.props.paused ? this.props.location : null}
onToggleBreakpoint={i => this.props.onToggleBreakpoint(i)}
/>
</div>
);
}
}

Editor.propTypes = {
runningInstances: PropTypes.object,
socket: PropTypes.object,
sourceId: PropTypes.string,
script: PropTypes.string,
scriptName: PropTypes.string,
adapterName: PropTypes.string,
paused: PropTypes.bool,
breakpoints: PropTypes.array,
location: PropTypes.object,
themeType: PropTypes.string,
themeName: PropTypes.string,
onToggleBreakpoint: PropTypes.func,
};

export default Editor;
Loading

0 comments on commit e635d14

Please sign in to comment.