mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-03 12:30:19 +08:00
feat: replace react-codemirror2 with @uiw/react-codemirror (#3577)
Signed-off-by: WindSpiritSR <simon343riley@gmail.com>
This commit is contained in:
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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">
|
||||
{
|
||||
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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
55
web/src/common/Editor.js
Normal 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;
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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]);
|
||||
}}
|
||||
/>
|
||||
|
Reference in New Issue
Block a user