-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add pro component MonacoEditor
#112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: dc9c77b The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Summary of ChangesHello @Col0ring, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new MonacoEditor component and its diff editor variant. The implementation looks good overall, with both Python backend and Svelte/React frontend parts. I've found a few issues related to documentation, code design, and a potential bug in the React component. My review includes suggestions to add docstrings, provide example values, refactor a circular import, fix inconsistencies, correct a typo in the documentation, and resolve a stale closure bug in the diff editor component.
| render=render, | ||
| elem_style=elem_style, | ||
| **kwargs) | ||
| from .. import ModelScopeProMonacoEditor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The local import from .. import ModelScopeProMonacoEditor inside the __init__ method is used to work around a circular dependency. This is a code smell and can lead to confusion and maintenance issues. A better approach would be to refactor the code to break the circular dependency. For example, you could move the shared LOADER configuration to a separate file that both modules can import from without creating a cycle.
Example refactor:
- Create a new file
backend/modelscope_studio/components/pro/monaco_editor/config.pywith theLOADERconfig. - Import
LOADERfromconfig.pyin bothmonaco_editor/__init__.pyandmonaco_editor/diff_editor/__init__.py.
| const beforeMountFunction = useFunction(beforeMount); | ||
| const afterMountFunction = useFunction(afterMount); | ||
| const disposablesRef = useRef<IDisposable[]>([]); | ||
| const editorRef = useRef<editor.IStandaloneDiffEditor | null>(null); | ||
| const [isEditorReady, setIsEditorReady] = React.useState(false); | ||
| const [value, setValue] = useValueChange({ | ||
| onValueChange, | ||
| value: valueProp, | ||
| }); | ||
| const handleEditorMount: MonacoDiffEditorProps['onMount'] = ( | ||
| editor, | ||
| monaco | ||
| ) => { | ||
| editorRef.current = editor; | ||
| if (isNumber(line)) { | ||
| editor.revealLine(line); | ||
| } | ||
| setIsEditorReady(true); | ||
| const modifiedEditor = editor.getModifiedEditor(); | ||
| const mountDisposable = modifiedEditor.onDidChangeModelContent((e) => { | ||
| const newValue = modifiedEditor.getValue(); | ||
| setValue(newValue); | ||
| onChange?.(newValue, e); | ||
| }); | ||
|
|
||
| const validateDisposable = monaco.editor.onDidChangeMarkers((uris) => { | ||
| const editorUri = modifiedEditor.getModel()?.uri; | ||
| if (editorUri) { | ||
| const currentEditorHasMarkerChanges = uris.find( | ||
| (uri) => uri.path === editorUri.path | ||
| ); | ||
| if (currentEditorHasMarkerChanges) { | ||
| const markers = monaco.editor.getModelMarkers({ | ||
| resource: editorUri, | ||
| }); | ||
| onValidate?.(markers); | ||
| } | ||
| } | ||
| }); | ||
| disposablesRef.current.push(mountDisposable, validateDisposable); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The onChange and onValidate props are used inside handleEditorMount, which is only called once when the component mounts. This creates a stale closure, meaning if these props change, the editor will continue to use the old functions from the initial render. To fix this, you should wrap them with the useFunction hook, similar to how beforeMount and afterMount are handled.
const beforeMountFunction = useFunction(beforeMount);
const afterMountFunction = useFunction(afterMount);
const onChangeFunction = useFunction(onChange);
const onValidateFunction = useFunction(onValidate);
const disposablesRef = useRef<IDisposable[]>([]);
const editorRef = useRef<editor.IStandaloneDiffEditor | null>(null);
const [isEditorReady, setIsEditorReady] = React.useState(false);
const [value, setValue] = useValueChange({
onValueChange,
value: valueProp,
});
const handleEditorMount: MonacoDiffEditorProps['onMount'] = (
editor,
monaco
) => {
editorRef.current = editor;
if (isNumber(line)) {
editor.revealLine(line);
}
setIsEditorReady(true);
const modifiedEditor = editor.getModifiedEditor();
const mountDisposable = modifiedEditor.onDidChangeModelContent((e) => {
const newValue = modifiedEditor.getValue();
setValue(newValue);
onChangeFunction?.(newValue, e);
});
const validateDisposable = monaco.editor.onDidChangeMarkers((uris) => {
const editorUri = modifiedEditor.getModel()?.uri;
if (editorUri) {
const currentEditorHasMarkerChanges = uris.find(
(uri) => uri.path === editorUri.path
);
if (currentEditorHasMarkerChanges) {
const markers = monaco.editor.getModelMarkers({
resource: editorUri,
});
onValidateFunction?.(markers);
}
}
});
disposablesRef.current.push(mountDisposable, validateDisposable);
};
| """ | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return None | ||
|
|
||
| def example_value(self) -> Any: | ||
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| """ | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| before_mount: str | None = None, | ||
| after_mount: str | None = None, | ||
| override_services: dict | None = None, | ||
| loading: str | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The loading parameter has a default value of None, which is inconsistent with the MonacoEditor component where it defaults to "Editor is loading...". For consistency and better user experience, it's recommended to use the same default value.
| loading: str | None = None, | |
| loading: str | None = "Editor is loading...", |
| return None | ||
|
|
||
| def example_value(self) -> Any: | ||
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| | original | `str\| None` | None | 原始源的值(左侧)。 | | ||
| | language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 | | ||
| | original_language | `str\| None` | None | 单独指定原始源的语言。否则,它将获取 language 属性的值。 | | ||
| | modified_Language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the property name modified_Language. It should be modified_language to match the actual parameter name in the component's implementation.
| | modified_Language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 | | |
| | modified_language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 | |
| | original | `str\| None` | None | The original source (left one) value. | | ||
| | language | `str\| None` | None | The language of the editor (all languages [supported](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages) by monaco-editor). | | ||
| | original_language | `str\| None` | None | Specifies the language of the original source separately. Otherwise, it will take the value of the language property. | | ||
| | modified_Language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the property name modified_Language. It should be modified_language to match the actual parameter name in the component's implementation.
| | modified_Language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. | | |
| | modified_language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. | |
No description provided.