Skip to content

Commit

Permalink
Add Monaco for RedisGears panel editor (#39)
Browse files Browse the repository at this point in the history
* Add monaco editor for gears panel

* Update dashboard

* Add @monaco-editor/react package

* Format

* Update language

Co-authored-by: Mikhail <[email protected]>
  • Loading branch information
asimonok and Mikhail authored Jan 31, 2021
1 parent c3ad065 commit 9cfa659
Show file tree
Hide file tree
Showing 10 changed files with 243 additions and 28 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@grafana/runtime": "7.3.6",
"@grafana/toolkit": "7.3.6",
"@grafana/ui": "7.3.6",
"@monaco-editor/react": "^4.0.9",
"@types/enzyme": "^3.10.8",
"@types/enzyme-adapter-react-16": "^1.0.6",
"emotion": "10.0.27",
Expand Down
25 changes: 5 additions & 20 deletions src/dashboards/redis-gears.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"type": "panel",
"id": "redis-gears-panel",
"name": "RedisGears",
"version": "1.3.1"
"version": "1.1.0"
},
{
"type": "panel",
Expand All @@ -49,7 +49,7 @@
"gnetId": null,
"graphTooltip": 0,
"id": null,
"iteration": 1611706223976,
"iteration": 1612064044040,
"links": [],
"panels": [
{
Expand Down Expand Up @@ -200,10 +200,6 @@
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
Expand Down Expand Up @@ -293,18 +289,6 @@
}
]
},
{
"matcher": {
"id": "byName",
"options": "Last Error"
},
"properties": [
{
"id": "custom.width",
"value": 99
}
]
},
{
"matcher": {
"id": "byName",
Expand Down Expand Up @@ -360,7 +344,8 @@
"command": "rg.dumpregistrations",
"query": "",
"refId": "A",
"streaming": false,
"streaming": true,
"streamingDataType": "DataFrame",
"type": "gears"
}
],
Expand Down Expand Up @@ -462,5 +447,5 @@
"timezone": "",
"title": "RedisGears",
"uid": "xFPiNzLMz",
"version": 2
"version": 1
}
90 changes: 90 additions & 0 deletions src/redis-gears-panel/components/code-editor/code-editor.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { shallow } from 'enzyme';
import Editor from '@monaco-editor/react';
import { UnthemedCodeEditor } from './code-editor';

/**
* Unthemed Code Editor
*/
describe('UnthemedCodeEditor', () => {
it('Should pass correct props', () => {
const onChange = jest.fn();
const wrapper = shallow(
<UnthemedCodeEditor width={100} height={200} value="hello" onChange={onChange} theme={{ isDark: true } as any} />
);
const component = wrapper.find(Editor);
expect(component.prop('width')).toEqual(100);
expect(component.prop('height')).toEqual(200);
expect(component.prop('value')).toEqual('hello');
expect(component.prop('theme')).toEqual('vs-dark');
expect(component.prop('onChange')).toEqual(onChange);
expect(component.prop('options')).toEqual({
wordWrap: 'off',
codeLens: false,
minimap: {
enabled: undefined,
renderCharacters: false,
},
readOnly: false,
overviewRulerBorder: false,
automaticLayout: true,
glyphMargin: false,
folding: false,
lineNumbers: 'off',
lineDecorationsWidth: 5,
lineNumbersMinChars: 0,
});
});

it('Should pass correct props when lineNumbers are shown', () => {
const onChange = jest.fn();
const value =
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
const wrapper = shallow(
<UnthemedCodeEditor
width={100}
height={200}
value={value}
onChange={onChange}
theme={{ isDark: false } as any}
language="python"
showMiniMap
showLineNumbers
/>
);
const component = wrapper.find(Editor);
expect(component.prop('theme')).toEqual('vs-light');
expect(component.prop('language')).toEqual('python');
expect(component.prop('options')).toEqual({
wordWrap: 'off',
codeLens: false,
minimap: {
enabled: true,
renderCharacters: false,
},
readOnly: false,
overviewRulerBorder: false,
automaticLayout: true,
lineDecorationsWidth: 0,
lineNumbersMinChars: 4,
});
});

it('Should use correctly if value is undefined', () => {
const onChange = jest.fn();
const wrapper = shallow(
<UnthemedCodeEditor
width={100}
height={200}
value={undefined}
onChange={onChange}
theme={{ isDark: false } as any}
language="python"
showMiniMap
showLineNumbers
/>
);
const component = wrapper.find(Editor);
expect(component.prop('value')).toEqual('');
});
});
115 changes: 115 additions & 0 deletions src/redis-gears-panel/components/code-editor/code-editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { PureComponent } from 'react';
import { Themeable, withTheme } from '@grafana/ui';
import Editor from '@monaco-editor/react';

/**
* Properties
*/
interface Props {
/**
* Width
*
* @type {number}
*/
width: number;

/**
* Height
*
* @type {number}
*/
height: number;

/**
* Value
*
* @type {string}
*/
value?: string;

/**
* Show Mini map
*
* @type {boolean}
*/
showMiniMap?: boolean;

/**
* Show Line numbers
*
* @type {boolean}
*/
showLineNumbers?: boolean;

/**
* Language
*
* @type {string}
*/
language?: string;

/**
* Read-only
*
* @type {boolean}
*/
readOnly?: boolean;

/**
* On Change
*/
onChange: (value?: string) => void;
}

/**
* Unthemed Code Editor
*
* @see https://github.com/suren-atoyan/monaco-react
*/
export class UnthemedCodeEditor extends PureComponent<Props & Themeable, {}> {
render() {
const { width, height, theme, showMiniMap, showLineNumbers, language = 'python', onChange, readOnly } = this.props;

/**
* Options similar to Grafana
*/
const options: any = {
wordWrap: 'off',
codeLens: false, // not included in the bundle
minimap: {
enabled: showMiniMap,
renderCharacters: false,
},
readOnly: !!readOnly,
lineNumbersMinChars: 4,
lineDecorationsWidth: 0,
overviewRulerBorder: false,
automaticLayout: true,
};

/**
* Line numbers similar to Grafana
*/
if (!showLineNumbers) {
options.glyphMargin = false;
options.folding = false;
options.lineNumbers = 'off';
options.lineDecorationsWidth = 5; // left margin when not showing line numbers
options.lineNumbersMinChars = 0;
}

return (
<Editor
width={width}
height={height}
theme={theme.isDark ? 'vs-dark' : 'vs-light'}
onChange={onChange}
language={language}
options={options}
value={this.props.value ?? ''}
/>
);
}
}

export const CodeEditor = withTheme(UnthemedCodeEditor);
1 change: 1 addition & 0 deletions src/redis-gears-panel/components/code-editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CodeEditor } from './code-editor';
1 change: 1 addition & 0 deletions src/redis-gears-panel/components/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './code-editor';
export * from './redis-gears-panel';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from 'react';
import { shallow } from 'enzyme';
import { Observable } from 'rxjs';
import { FieldType, LoadingState, toDataFrame } from '@grafana/data';
import { Alert, Button, CodeEditor, Input, Switch, Table } from '@grafana/ui';
import { Alert, Button, Input, Switch, Table } from '@grafana/ui';
import { CodeEditor } from '../code-editor';
import { RedisGearsPanel } from './redis-gears-panel';

/**
Expand Down Expand Up @@ -52,7 +53,7 @@ describe('RedisGearsPanel', () => {
it('Should update script', () => {
const wrapper = shallow<RedisGearsPanel>(getComponent());
const component = wrapper.find(CodeEditor);
component.simulate('blur', 'myscript');
component.simulate('change', 'myscript');
expect(wrapper.state().script).toEqual('myscript');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
toDataFrame,
} from '@grafana/data';
import { getDataSourceSrv, toDataQueryError } from '@grafana/runtime';
import { Alert, Button, CodeEditor, InlineField, InlineFormLabel, Input, Switch, Table } from '@grafana/ui';
import { Alert, Button, InlineField, InlineFormLabel, Input, Switch, Table } from '@grafana/ui';
import { PanelOptions } from '../../types';
import { CodeEditor } from '../code-editor';

/**
* Properties
Expand Down Expand Up @@ -117,7 +118,7 @@ export class RedisGearsPanel extends PureComponent<Props, State> {
*
* @param script
*/
onChangeScript = (script: string) => {
onChangeScript = (script = '') => {
this.setState({
script,
});
Expand Down Expand Up @@ -293,9 +294,8 @@ export class RedisGearsPanel extends PureComponent<Props, State> {
language="python"
width={width}
height={height - footerHeight}
onBlur={this.onChangeScript}
onSave={this.onChangeScript}
showMiniMap={false}
onChange={this.onChangeScript}
showMiniMap={true}
showLineNumbers={true}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/redis-gears-panel/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
* Default script
*/
export const DefaultScript = 'GB().run()';
export const DefaultScript = 'gb = GearsBuilder()';
21 changes: 21 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,22 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"

"@monaco-editor/loader@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.0.0.tgz#c7ea78ef07cebcae83d92bbfe2bddab563468102"
integrity sha512-CA35bf5Y7wFWfeJZfkLslOxiatln3oTBKkfbdo+TF5H+UdPP96qHvhOUjjd1DeQ2NWsRkVPSnoSYek7NE5B26w==
dependencies:
state-local "^1.0.6"

"@monaco-editor/react@^4.0.9":
version "4.0.9"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.0.9.tgz#77f3170c6c8409efe6b450467748f0df4f64d6b2"
integrity sha512-mTDqf47FsPnud/Ct3ekKqSFxmytkk4oMVIPUFMJF9iJcKH5AoqXs1oobXtPoVWiL9uWePatBNVCFv1pg4AqZuA==
dependencies:
"@monaco-editor/loader" "^1.0.0"
prop-types "^15.7.2"
state-local "^1.0.7"

"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
Expand Down Expand Up @@ -11612,6 +11628,11 @@ stack-utils@^1.0.1:
dependencies:
escape-string-regexp "^2.0.0"

state-local@^1.0.6, state-local@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==

static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
Expand Down

0 comments on commit 9cfa659

Please sign in to comment.