forgeplus-react/src/forge/Newfile/cloudIDE.jsx

284 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { Fragment, useState, useMemo, useEffect, useRef } from 'react';
import { Switch ,Checkbox ,Tooltip,Popover,Radio,Icon} from 'antd';
import { EditorRenderer } from 'alex';
import { useLocalStorageState } from 'ahooks';
import html from './extensions/alex-ext-public.html-language-features-worker.js';
import css from './extensions/alex-ext-public.css-language-features-worker.js';
import json from './extensions/alex-ext-public.typescript-language-features-worker.js';
import typescript from './extensions/alex-ext-public.json-language-features-worker.js';
import markdown from './extensions/alex-ext-public.markdown-language-features-worker.js';
import ideTheme from './extensions/alex-ext-public.ide-dark-theme.js';
import CodeBlame from './extensions/alex-ext-public.editor-plugin-blame.js';
import { getUrl, returnbar } from 'educoder';
import changeThemePlugin from './changeTheme';
import IDEPlugin, { ExtensionCommand } from './plugins/idePlugin';
// import { FileOperationArea } from './components/file-operation-area';
import { repoService } from './codeReview/mock/repo.service';
function CloudIDE({ download_url, params: { owner, projectsId, branchName }, filepath , value }) {
function FileContentStore() {
const [loading, setLoading] = useState(true);
const [showIde, setShowIde] = useState(false);
const [fileSize, setFileSize] = useState('0');
const [fileName, setFileName] = useState('');
return {
loading,
setLoading,
showIde,
setShowIde,
fileSize,
setFileSize,
fileName,
setFileName,
};
}
const { fileSize, fileName } = FileContentStore();
const fileCache = new Map();
const copyFile = () => {
console.log('复制文件内容');
};
const [settingTipVisible, setSettingTipVisible] = useLocalStorageState(
'code.file.operation.tip',
true
);
const [lines, setLines] = useState(0);
const [sloc, setSloc] = useState(0);
const [encoding, setEncoding] = useState('UTF-8');
// const [showMdPreview, setShowPreview] = useState(false);
const [fileString, setFileString] = useState('');
const curFilepath = useMemo(() => {
// 仓库默认页是没有path的默认解析到readme
// 当不需要加载文件时,返回空
// const needLoadFile = treeEntry
// ? treeEntry.render === FileShowType.text &&
// treeEntry.size < ReadFileSizeLimit
// : !!fileName;
// return needLoadFile ? path || fileName : '';
}, [branchName, fileName]);
const [blameChecked, setBlameChecked] = useState(false);
// 组件卸载时,清空缓存
// useUnmount(() => {
// fileCache.clear()
// })
// 由于 editor 组件内部有缓存,已经加载过的文件不会再次请求 readFile 方法
// 所以当已经加载过该文件时,直接读取文件内容用于展示
// 暂时前端缓存文件体积有过大保护内存溢出风险较低暂时不做过多设计待后续接入editor api
useEffect(() => {
setBlameChecked(false);
const fileKey = `${branchName}-${curFilepath}`;
const fileInfo = fileCache.get(fileKey);
if (fileInfo) {
setFileString(fileInfo.fileString);
setLines(fileInfo.lines);
setSloc(fileInfo.sloc);
}
}, [curFilepath]);
// 插件
const [pluginActivated, setPluginActivated] = useState(false);
const plugin = useRef(
new IDEPlugin(
() => setPluginActivated(true),
(commitId) => window.open(`/${owner}/${projectsId}/commits/${commitId}`)
)
);
// blame
const onBlame = async (e) => {
setBlameChecked(e.target.checked);
if (!e.target.checked ) {
plugin.current.commands && plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame);
} else {
const res = await repoService.getCodeBlame(projectsId, owner, { sha:decodeURIComponent(branchName), filepath })
plugin.current.commands && plugin.current.commands.executeCommand(ExtensionCommand.toggleBlame, res);
}
};
const [wordWrap, setWordWrap] = useState(false);
const onWordWrapChange = (value) => {
const preference = value ? 'on' : 'off';
localStorage.setItem('code.file.viewer.worlWrap', preference);
plugin.current.setPerference('editor.wordWrap', preference, true);
setWordWrap(value);
};
async function changeStyle(v) {
const commands = changeThemePlugin.commands;
if (commands) {
await commands.executeCommand(
'ChangeThemePlugin.changeTheme',
v ? 'opensumi-light' : 'opensumi-dark'
);
}
}
const content = (
<Fragment>
<div className="flex align-center">
<span className="c-65">{'编码方式'}</span>
<span>
<Radio.Group
onChange={(e) => {
setEncoding(e.target.value);
}}
value={encoding}
size="small"
>
<Radio value="UTF-8">UTF-8</Radio>
<Radio value="GBK">GBK</Radio>
</Radio.Group>
</span>
</div>
<div className="flex align-center">
<span className="c-65">{'自动换行'}</span>
<span>
<Radio.Group
onChange={(e) => {
onWordWrapChange(e.target.value);
}}
value={wordWrap}
size="small"
>
<Radio value={false}>{'不自动换行'}</Radio>
<Radio value={true}>{'自动换行'}</Radio>
</Radio.Group>
</span>
</div>
</Fragment>
);
return (
<Fragment>
<div className="ide-tool-bar">
{onBlame ? (
<Checkbox onChange={onBlame} checked={!!blameChecked}>
Blame
</Checkbox>
) : null}
<Switch checkedChildren="light" unCheckedChildren="dark" defaultChecked onChange={changeStyle}></Switch>
<Tooltip
title={'更改阅读设置'}
defaultVisible={settingTipVisible}
onVisibleChange={setSettingTipVisible}
>
<Popover
content={content}
title={null}
trigger="click"
placement="bottomRight"
arrowPointAtCenter={true}
>
{/* <Icon type="ellipsis" /> */}
<Icon className="read-more" type="read" />
</Popover>
</Tooltip>
</div>
{/* <FileOperationArea
lines={lines}
sloc={sloc}
size={fileSize}
refName={branchName}
path={curFilepath}
encoding={encoding}
setEncoding={setEncoding}
onFileCopy={copyFile}
blameChecked={blameChecked}
onBlame={pluginActivated && onBlame}
wordWrap={wordWrap}
setWordWrap={onWordWrapChange}
/> */}
{
value ?
<EditorRenderer
appConfig={{
// 工作空间目录
plugins: [changeThemePlugin, plugin.current],
workspaceDir: `${owner}/${projectsId}`,
defaultPreferences: {
// 默认主题,如果暗色为 opensumi-dark
// 'general.theme': 'opensumi-light',
'general.theme': 'opensumi-light',
// 编辑器只读
'editor.forceReadOnly': true,
// 最后一行禁止继续滚动
'editor.scrollBeyondLastLine': false,
},
extensionMetadata: [
html,
css,
json,
typescript,
markdown,
ideTheme,
CodeBlame],
}}
runtimeConfig={{
// 业务标识
biz: 'gitlink',
// 在 editor 下推荐传 null此时不会持久化缓存工作空间数据
scenario: null,
// 启动时显示的编辑器editor 下传 none 即可
startupEditor: 'none',
// 隐藏 editor tab
hideEditorTab: true,
}}
editorConfig={{
stretchHeight: true,
disableEditorSearch: true,
}}
// 文档模型,以下数据变更时会更新打开的编辑器
documentModel={{
// 类型code 下为 code保持不变
type: 'code',
// 分支或 tag
ref: branchName,
// 仓库群组和用户
owner: owner,
// 仓库名
name: projectsId,
// 仓库文件路径
filepath: filepath,
// 读取文件接口
readFile: async (filepath) => {
if (!filepath) {
return;
}
// 请求接口
// const res = await fetch('https://gist.githubusercontent.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js');
const res = await fetch(`${getUrl()}/attachments/entries/get_file?download_url=${download_url}`);
setTimeout(()=>{
onWordWrapChange(localStorage.getItem('code.file.viewer.worlWrap') === 'on');
},5000)
return res.arrayBuffer();
},
// 文件编码,和标准工作空间支持编码类型一致,简单场景只传 utf8 或 gbk 即可
// encoding: 'utf8',
encoding,
onFilepathChange: (changedFilepath) => {
if (changedFilepath) {
console.log(`路由跳转到 ${changedFilepath}`)
}
},
// 指定当前选中多少行
// lineNumber: [0, 1],
onLineNumberChange: line => {
if (typeof line === 'number') {
console.log(`#L${line}`)
} else {
console.log(`#L${line[0]}-${line[1]}`)
}
},
}}
/>:
<div className="pl20">空文件</div>
}
</Fragment>
)
}
export default CloudIDE;