feat: replace react-codemirror2 with @uiw/react-codemirror (#3577)

Signed-off-by: WindSpiritSR <simon343riley@gmail.com>
This commit is contained in:
WindSpiritSR
2025-02-14 00:10:33 +08:00
committed by GitHub
parent 9c39179849
commit 81b336b37a
11 changed files with 871 additions and 122 deletions

View File

@ -34,14 +34,8 @@ import PromptPage from "./auth/PromptPage";
import copy from "copy-to-clipboard";
import ThemeEditor from "./common/theme/ThemeEditor";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
import SigninTable from "./table/SigninTable";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/htmlmixed/htmlmixed");
require("codemirror/mode/xml/xml");
require("codemirror/mode/css/css");
import Editor from "./common/Editor";
const {Option} = Select;
@ -629,13 +623,9 @@ class ApplicationEditPage extends React.Component {
<Col span={22} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
value={this.state.application.signupHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateApplicationField("signupHtml", value);
}}
/>
<Editor value={this.state.application.signupHtml} lang="html" fillHeight dark onChange={value => {
this.updateApplicationField("signupHtml", value);
}} />
</div>
} title={i18next.t("provider:Signup HTML - Edit")} trigger="click">
<Input value={this.state.application.signupHtml} style={{marginBottom: "10px"}} onChange={e => {
@ -651,13 +641,9 @@ class ApplicationEditPage extends React.Component {
<Col span={22} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
value={this.state.application.signinHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateApplicationField("signinHtml", value);
}}
/>
<Editor value={this.state.application.signinHtml} lang="html" fillHeight dark onChange={value => {
this.updateApplicationField("signinHtml", value);
}} />
</div>
} title={i18next.t("provider:Signin HTML - Edit")} trigger="click">
<Input value={this.state.application.signinHtml} style={{marginBottom: "10px"}} onChange={e => {
@ -758,11 +744,7 @@ class ApplicationEditPage extends React.Component {
{Setting.getLabel(i18next.t("application:SAML metadata"), i18next.t("application:SAML metadata - Tooltip"))} :
</Col>
<Col span={22}>
<CodeMirror
value={this.state.samlMetadata}
options={{mode: "xml", theme: "default"}}
onBeforeChange={(editor, data, value) => {}}
/>
<Editor value={this.state.samlMetadata?.toString() ?? ""} lang="xml" readOnly />
<br />
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
copy(`${window.location.origin}/api/saml/metadata?application=admin/${encodeURIComponent(this.state.applicationName)}&enablePostBinding=${this.state.application.enableSamlPostBinding}`);
@ -829,9 +811,12 @@ class ApplicationEditPage extends React.Component {
<Col span={22}>
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={this.state.application.formCss === "" ? template : this.state.application.formCss}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
<Editor
value={this.state.application.formCss === "" ? template : this.state.application.formCss}
lang="css"
fillHeight
dark
onChange={value => {
this.updateApplicationField("formCss", value);
}}
/>
@ -850,9 +835,12 @@ class ApplicationEditPage extends React.Component {
<Col span={22}>
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={this.state.application.formCssMobile === "" ? template : this.state.application.formCssMobile}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
<Editor
value={this.state.application.formCssMobile === "" ? template : this.state.application.formCssMobile}
lang="css"
fillHeight
dark
onChange={value => {
this.updateApplicationField("formCssMobile", value);
}}
/>
@ -887,9 +875,12 @@ class ApplicationEditPage extends React.Component {
<Col span={21} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={this.state.application.formSideHtml === "" ? sideTemplate : this.state.application.formSideHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
<Editor
value={this.state.application.formSideHtml === "" ? sideTemplate : this.state.application.formSideHtml}
lang="html"
fillHeight
dark
onChange={value => {
this.updateApplicationField("formSideHtml", value);
}}
/>
@ -936,10 +927,12 @@ class ApplicationEditPage extends React.Component {
<Col span={22} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
<Editor
value={this.state.application.headerHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
lang="html"
fillHeight
dark
onChange={value => {
this.updateApplicationField("headerHtml", value);
}}
/>
@ -958,10 +951,12 @@ class ApplicationEditPage extends React.Component {
<Col span={22} >
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
<Editor
value={this.state.application.footerHtml}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
lang="html"
fillHeight
dark
onChange={value => {
this.updateApplicationField("footerHtml", value);
}}
/>

View File

@ -13,13 +13,11 @@
// limitations under the License.
import React, {useCallback, useEffect, useRef, useState} from "react";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
import "codemirror/mode/properties/properties";
import * as Setting from "./Setting";
import IframeEditor from "./IframeEditor";
import {Tabs} from "antd";
import i18next from "i18next";
import Editor from "./common/Editor";
const {TabPane} = Tabs;
@ -81,11 +79,10 @@ const CasbinEditor = ({model, onModelTextChange}) => {
style={{width: "100%", height: "100%"}}
/>
) : (
<CodeMirror
<Editor
value={localModelText}
className="full-height-editor no-horizontal-scroll-editor"
options={{mode: "properties", theme: "default"}}
onBeforeChange={(editor, data, value) => {
readOnly={Setting.builtInObject(model)}
onChange={value => {
handleModelTextChange(value);
}}
/>

View File

@ -13,7 +13,7 @@
// limitations under the License.
import React from "react";
import {Controlled as CodeMirror} from "react-codemirror2";
import {Link} from "react-router-dom";
import {Button, Popover, Table} from "antd";
import moment from "moment";
@ -22,6 +22,7 @@ import * as ModelBackend from "./backend/ModelBackend";
import i18next from "i18next";
import BaseListPage from "./BaseListPage";
import PopconfirmModal from "./common/modal/PopconfirmModal";
import Editor from "./common/Editor";
const rbacModel = `[request_definition]
r = sub, obj, act
@ -148,11 +149,7 @@ class ModelListPage extends BaseListPage {
return (
<Popover placement="topRight" content={() => {
return (
<CodeMirror
value={text}
options={{mode: "properties", theme: "default"}}
onBeforeChange={(editor, data, value) => {}}
/>
<Editor value={text} />
);
}} title="" trigger="hover">
{

View File

@ -28,14 +28,7 @@ import copy from "copy-to-clipboard";
import {CaptchaPreview} from "./common/CaptchaPreview";
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
import * as Web3Auth from "./auth/Web3Auth";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/htmlmixed/htmlmixed");
require("codemirror/mode/xml/xml");
require("codemirror/mode/css/css");
import Editor from "./common/Editor";
const {Option} = Select;
const {TextArea} = Input;
@ -1127,10 +1120,12 @@ class ProviderEditPage extends React.Component {
<Row>
<Col span={Setting.isMobile() ? 22 : 11}>
<div style={{height: "300px", margin: "10px"}}>
<CodeMirror
<Editor
value={this.state.provider.content}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
fillHeight
dark
lang="html"
onChange={value => {
this.updateProviderField("content", value);
}}
/>

View File

@ -21,11 +21,8 @@ import * as Setting from "./Setting";
import i18next from "i18next";
import SyncerTableColumnTable from "./table/SyncerTableColumnTable";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
import * as CertBackend from "./backend/CertBackend";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/javascript/javascript");
import Editor from "./common/Editor";
const {Option} = Select;
@ -512,10 +509,13 @@ class SyncerEditPage extends React.Component {
</Col>
<Col span={22} >
<div style={{width: "100%", height: "300px"}} >
<CodeMirror
<Editor
value={this.state.syncer.errorText}
options={{mode: "javascript", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
fillHeight
readOnly
dark
lang="js"
onChange={value => {
this.updateSyncerField("errorText", value);
}}
/>

View File

@ -21,10 +21,7 @@ import * as Setting from "./Setting";
import i18next from "i18next";
import WebhookHeaderTable from "./table/WebhookHeaderTable";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/javascript/javascript");
import Editor from "./common/Editor";
const {Option} = Select;
@ -304,11 +301,7 @@ class WebhookEditPage extends React.Component {
</Col>
<Col span={22} >
<div style={{width: "900px", height: "300px"}} >
<CodeMirror
value={previewText}
options={{mode: "javascript", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {}}
/>
<Editor value={previewText} lang="js" fillHeight readOnly dark />
</div>
</Col>
</Row>

55
web/src/common/Editor.js Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import React from "react";
import CodeMirror from "@uiw/react-codemirror";
import {materialDark} from "@uiw/codemirror-theme-material";
import {langs} from "@uiw/codemirror-extensions-langs";
export const Editor = (props) => {
const fillHeight = props.fillHeight ? {
height: "100%",
style: {height: "100%"},
} : {};
let extensions = [];
switch (props.lang) {
case "javascript":
case "js":
extensions = [langs.javascript()];
break;
case "html":
extensions = [langs.html()];
break;
case "css":
extensions = [langs.css()];
break;
case "xml":
extensions = [langs.xml()];
break;
}
return (
<CodeMirror
value={props.value}
height={props.height}
{...fillHeight}
readOnly={props.readOnly}
theme={props.dark ? materialDark : "light"}
extensions={extensions}
onChange={props.onChange}
/>
);
};
export default Editor;

View File

@ -17,12 +17,7 @@ import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Popover, Row, Select, Space, Switch, Table, Tooltip} from "antd";
import * as Setting from "../Setting";
import i18next from "i18next";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/htmlmixed/htmlmixed");
import Editor from "../common/Editor";
const {Option} = Select;
@ -175,12 +170,9 @@ class SigninTable extends React.Component {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={text}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateField(table, index, "label", value);
}}
/>
<Editor value={text} lang="html" fillHeight dark onChange={value => {
this.updateField(table, index, "label", value);
}} />
</div>
} title={i18next.t("signup:Label HTML")} trigger="click">
<Input value={text} style={{marginBottom: "10px"}} onChange={e => {
@ -206,9 +198,12 @@ class SigninTable extends React.Component {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={text?.replaceAll("<style>", "").replaceAll("</style>", "")}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
<Editor
value={text?.replaceAll("<style>", "").replaceAll("</style>", "")}
lang="css"
fillHeight
dark
onChange={value => {
this.updateField(table, index, "customCss", value);
}}
/>

View File

@ -17,12 +17,7 @@ import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Popover, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "../Setting";
import i18next from "i18next";
import {Controlled as CodeMirror} from "react-codemirror2";
import "codemirror/lib/codemirror.css";
require("codemirror/theme/material-darker.css");
require("codemirror/mode/htmlmixed/htmlmixed");
import Editor from "../common/Editor";
const EmailCss = ".signup-email{}\n.signup-email-input{}\n.signup-email-code{}\n.signup-email-code-input{}\n";
const PhoneCss = ".signup-phone{}\n.signup-phone-input{}\n.phone-code{}\n.signup-phone-code-input{}";
@ -234,12 +229,9 @@ class SignupTable extends React.Component {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}} >
<CodeMirror value={text}
options={{mode: "htmlmixed", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
this.updateField(table, index, "label", value);
}}
/>
<Editor value={text} lang="html" fillHeight dark onChange={value => {
this.updateField(table, index, "label", value);
}} />
</div>
} title={i18next.t("signup:Label HTML")} trigger="click">
<Input value={text} style={{marginBottom: "10px"}} onChange={e => {
@ -265,9 +257,12 @@ class SignupTable extends React.Component {
return (
<Popover placement="right" content={
<div style={{width: "900px", height: "300px"}}>
<CodeMirror value={text ? text : SignupTableDefaultCssMap[record.name]}
options={{mode: "css", theme: "material-darker"}}
onBeforeChange={(editor, data, value) => {
<Editor
value={text ? text : SignupTableDefaultCssMap[record.name]}
lang="css"
fillHeight
dark
onChange={value => {
this.updateField(table, index, "customCss", value ? value : SignupTableDefaultCssMap[record.name]);
}}
/>