Add tool edit page

This commit is contained in:
2024-01-31 18:07:16 +08:00
parent d6ff952596
commit 28140543c4
11 changed files with 254 additions and 22 deletions

View File

@@ -0,0 +1,6 @@
[data-component=tools-edit] {
.root-content {
width: 100%;
height: 100%;
}
}

View File

@@ -8,9 +8,18 @@ interface PreviewProps {
files: IFiles
importMap: IImportMap
entryPoint: string
preExpansionCode?: string
postExpansionCode?: string
}
const Preview = ({ iframeKey, files, importMap, entryPoint }: PreviewProps) => {
const Preview = ({
iframeKey,
files,
importMap,
entryPoint,
preExpansionCode = '',
postExpansionCode = ''
}: PreviewProps) => {
const [errorMsg, setErrorMsg] = useState('')
const [compiledCode, setCompiledCode] = useState('')
@@ -19,14 +28,19 @@ const Preview = ({ iframeKey, files, importMap, entryPoint }: PreviewProps) => {
}
useEffect(() => {
if (!Object.keys(files).length || !importMap || !entryPoint.length) {
return
}
Compiler.compile(files, importMap, entryPoint)
.then((result) => {
setCompiledCode(result.outputFiles[0].text)
setCompiledCode(
`${preExpansionCode}\n${result.outputFiles[0].text}\n${postExpansionCode}`
)
})
.catch((e: Error) => {
setErrorMsg(`编译失败:${e.message}`)
})
}, [files, Compiler])
}, [files, Compiler, importMap, entryPoint])
return (
<div data-component={'playground-preview'}>

View File

@@ -3,4 +3,14 @@
position: relative;
width: 100%;
height: 100%;
.playground-error-message {
position: absolute;
bottom: 0;
width: 100%;
color: white;
background-color: #FF4D4FAA;
padding: 5px 10px;
font-size: 1.2em;
}
}

View File

@@ -9,9 +9,18 @@ interface OutputProps {
selectedFileName: string
importMap: IImportMap
entryPoint: string
preExpansionCode?: string
postExpansionCode?: string
}
const Output = ({ files, selectedFileName, importMap, entryPoint }: OutputProps) => {
const Output = ({
files,
selectedFileName,
importMap,
entryPoint,
preExpansionCode,
postExpansionCode
}: OutputProps) => {
const [selectedTab, setSelectedTab] = useState('Preview')
return (
@@ -31,6 +40,8 @@ const Output = ({ files, selectedFileName, importMap, entryPoint }: OutputProps)
files={files}
importMap={importMap}
entryPoint={entryPoint}
preExpansionCode={preExpansionCode}
postExpansionCode={postExpansionCode}
/>
)}
{selectedTab === 'Transform' && <Transform file={files[selectedFileName]} />}

View File

@@ -5,14 +5,4 @@
> * {
width: 0 !important;
}
.playground-error-message {
position: absolute;
bottom: 0;
width: 100%;
color: white;
background-color: #FF4D4FAA;
padding: 5px 10px;
font-size: 1.2em;
}
}

2
src/global.d.ts vendored
View File

@@ -540,7 +540,7 @@ interface ToolVo {
dist: ToolDataVo
entryPoint: string
publish: string
review: 'NONE' | 'PASS' | 'REJECT'
review: 'NONE' | 'PROCESSING' | 'PASS' | 'REJECT'
createTime: string
updateTime: string
}

View File

@@ -1,5 +1,15 @@
import Playground from '@/components/Playground'
import templates from '@/components/Playground/templates'
const Tools = () => {
return <>1</>
const template = templates['base']
return (
<Playground
initFiles={template.files}
initTsconfigRaw={JSON.stringify(template.tsconfig, null, 2)}
initImportMapRaw={JSON.stringify(template.importMap, null, 2)}
/>
)
}
export default Tools

168
src/pages/Tools/Edit.tsx Normal file
View File

@@ -0,0 +1,168 @@
import '@/assets/css/pages/tools/edit.scss'
import { r_tool_detail } from '@/services/tool.tsx'
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
import { useEffect, useState } from 'react'
import Playground from '@/components/Playground'
import FitFullscreen from '@/components/common/FitFullscreen.tsx'
import FlexBox from '@/components/common/FlexBox.tsx'
import { IFiles, IImportMap, ITsconfig } from '@/components/Playground/shared.ts'
import {
base64ToFiles,
base64ToStr,
IMPORT_MAP_FILE_NAME,
TS_CONFIG_FILE_NAME
} from '@/components/Playground/files.ts'
import LoadingMask from '@/components/common/LoadingMask.tsx'
const Edit = () => {
const navigate = useNavigate()
const { toolId } = useParams()
const [loading, setLoading] = useState(false)
const [toolData, setToolData] = useState<ToolVo>()
const [files, setFiles] = useState<IFiles>({})
const [selectedFileName, setSelectedFileName] = useState('')
const [importMapRaw, setImportMapRaw] = useState<string>('')
const [importMap, setImportMap] = useState<IImportMap>()
const [tsconfigRaw, setTsconfigRaw] = useState<string>('')
const [tsconfig, setTsconfig] = useState<ITsconfig>()
const [entryPoint, setEntryPoint] = useState('')
const [baseDist, setBaseDist] = useState('')
const handleOnChangeFileContent = (content: string, fileName: string, files: IFiles) => {
if (fileName === IMPORT_MAP_FILE_NAME) {
setImportMapRaw(content)
return
}
if (fileName === TS_CONFIG_FILE_NAME) {
setTsconfigRaw(content)
return
}
delete files[IMPORT_MAP_FILE_NAME]
delete files[TS_CONFIG_FILE_NAME]
setFiles(files)
}
const getTool = () => {
if (loading) {
return
}
setLoading(true)
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
void r_tool_detail('!', toolId!, 'latest')
.then((res) => {
const response = res.data
switch (response.code) {
case DATABASE_SELECT_SUCCESS:
switch (response.data!.review) {
case 'NONE':
case 'REJECT':
setToolData(response.data!)
break
case 'PROCESSING':
void message.warning('工具审核中,请勿修改')
navigate('/')
break
default:
void message.warning('请先创建新版本后编辑工具')
navigate('/')
}
break
case DATABASE_NO_RECORD_FOUND:
void message.error('未找到指定工具')
navigate('/')
break
default:
void message.error('获取工具信息失败,请稍后重试')
}
})
.finally(() => {
setLoading(false)
message.destroy('LOADING')
})
}
useEffect(() => {
try {
setImportMap(JSON.parse(importMapRaw) as IImportMap)
} catch (e) {
/* empty */
}
}, [importMapRaw])
useEffect(() => {
setTimeout(() => {
try {
setTsconfig(JSON.parse(tsconfigRaw) as ITsconfig)
} catch (e) {
/* empty */
}
}, 1000)
}, [tsconfigRaw])
useEffect(() => {
if (!toolData) {
return
}
try {
setBaseDist(base64ToStr(toolData.base.dist.data!))
const files = base64ToFiles(toolData.source.data!)
setFiles(files)
setImportMapRaw(files[IMPORT_MAP_FILE_NAME].value)
setTsconfigRaw(files[TS_CONFIG_FILE_NAME].value)
setEntryPoint(toolData.entryPoint)
setTimeout(() => {
setSelectedFileName(toolData.entryPoint)
}, 100)
} catch (e) {
console.error(e)
void message.error('载入工具失败')
}
}, [toolData])
useEffect(() => {
getTool()
}, [])
return (
<FitFullscreen data-component={'tools-edit'}>
<FlexBox direction={'horizontal'} className={'root-content'}>
<LoadingMask hidden={!loading}>
<Playground.CodeEditor
tsconfig={tsconfig}
files={{
...files,
[IMPORT_MAP_FILE_NAME]: {
name: IMPORT_MAP_FILE_NAME,
language: 'json',
value: importMapRaw
},
[TS_CONFIG_FILE_NAME]: {
name: TS_CONFIG_FILE_NAME,
language: 'json',
value: tsconfigRaw
}
}}
notRemovable={[entryPoint]}
selectedFileName={selectedFileName}
onAddFile={(_, files) => setFiles(files)}
onRemoveFile={(_, files) => setFiles(files)}
onRenameFile={(_, __, files) => setFiles(files)}
onChangeFileContent={handleOnChangeFileContent}
onSelectedFileChange={setSelectedFileName}
/>
<Playground.Output
files={files}
selectedFileName={selectedFileName}
importMap={importMap!}
entryPoint={entryPoint}
postExpansionCode={baseDist}
/>
</LoadingMask>
</FlexBox>
</FitFullscreen>
)
}
export default Edit

View File

@@ -11,8 +11,8 @@ import Card from '@/components/common/Card'
const View = () => {
const navigate = useNavigate()
const [loading, setLoading] = useState(false)
const { username, toolId, ver } = useParams()
const [loading, setLoading] = useState(false)
const [compiledCode, setCompiledCode] = useState('')
const render = (toolVo: ToolVo) => {

View File

@@ -25,6 +25,7 @@ interface CommonCardProps
onOpen?: () => void
onEdit?: () => void
onPublish?: () => void
onCancelReview?: () => void
onDelete?: () => void
}
@@ -46,6 +47,7 @@ const CommonCard = ({
onOpen,
onEdit,
onPublish,
onCancelReview,
onDelete,
children,
...props
@@ -80,14 +82,19 @@ const CommonCard = ({
</AntdButton>
)}
{onEdit && (
{onEdit && onPublish && (
<div className={'edit'}>
<AntdButton.Group size={'small'}>
<AntdButton onClick={onEdit}></AntdButton>
{onPublish && <AntdButton onClick={onPublish}></AntdButton>}
<AntdButton onClick={onPublish}></AntdButton>
</AntdButton.Group>
</div>
)}
{onCancelReview && (
<AntdButton size={'small'} onClick={onCancelReview}>
</AntdButton>
)}
{onDelete && (
<AntdButton size={'small'} danger onClick={onDelete}>
@@ -119,13 +126,21 @@ const ToolCard = ({ tools, onDelete, onUpgrade }: ToolCardProps) => {
}
const handleOnEditTool = () => {
if (selectedTool.publish === '0') {
return () => {}
if (selectedTool.publish === '0' && ['NONE', 'REJECT'].includes(selectedTool.review)) {
return () => {
navigate(`/edit/${tools[0].toolId}`)
}
}
}
const handleOnPublishTool = () => {
if (selectedTool.publish === '0') {
if (selectedTool.publish === '0' && ['NONE', 'REJECT'].includes(selectedTool.review)) {
return () => {}
}
}
const handleOnCancelReview = () => {
if (selectedTool.publish === '0' && selectedTool.review === 'PROCESSING') {
return () => {}
}
}
@@ -146,6 +161,7 @@ const ToolCard = ({ tools, onDelete, onUpgrade }: ToolCardProps) => {
onOpen={handleOnOpenTool}
onEdit={handleOnEditTool()}
onPublish={handleOnPublishTool()}
onCancelReview={handleOnCancelReview()}
onDelete={handleOnDeleteTool}
>
<AntdSelect

View File

@@ -45,6 +45,13 @@ export const tools: RouteJsonObject[] = [
component: lazy(() => import('@/pages/Tools/View')),
name: '查看'
},
{
path: 'edit/:toolId',
absolutePath: '/edit',
id: 'tools-edit',
component: lazy(() => import('@/pages/Tools/Edit')),
name: '查看'
},
{
path: '*',
absolutePath: '*',