setup(frontend): rename frontend-react
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import Box from '@mui/material/Box';
|
||||
// import EditIcon from '@mui/icons-material/Edit';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { IRichSentence } from '@/storage/plan';
|
||||
import { globalStorage } from '@/storage';
|
||||
|
||||
interface IAgentDetailCardProps {
|
||||
id: string;
|
||||
node: IRichSentence;
|
||||
render: () => void;
|
||||
}
|
||||
|
||||
export default observer(({ id, node, render }: IAgentDetailCardProps) => {
|
||||
const editContentRef = React.useRef('');
|
||||
const [edit, setEdit] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
render();
|
||||
}, [edit]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
marginRight: '4px',
|
||||
userSelect: 'none',
|
||||
transition: 'all 200ms ease-out',
|
||||
borderRadius: '0',
|
||||
display: edit ? 'flex' : 'inline',
|
||||
flexDirection: 'column',
|
||||
border: edit ? '2px solid' : undefined,
|
||||
'& .edit-button': {
|
||||
display: 'none',
|
||||
},
|
||||
'&:hover': {
|
||||
filter: edit ? undefined : 'brightness(1.1)',
|
||||
backgroundColor: edit
|
||||
? undefined
|
||||
: ((node?.style ?? { borderColor: '#0003' }) as any)!.borderColor,
|
||||
'& .edit-button': {
|
||||
display: edit ? 'none' : 'inline-flex',
|
||||
},
|
||||
},
|
||||
'&:active': {
|
||||
filter: edit ? undefined : 'brightness(1)',
|
||||
backgroundColor: edit
|
||||
? undefined
|
||||
: ((node?.style ?? { borderColor: '#0003' }) as any)!.borderColor,
|
||||
},
|
||||
lineHeight: '1.4rem',
|
||||
padding: edit ? '6px' : undefined,
|
||||
marginBottom: edit ? '6px' : undefined,
|
||||
marginTop: edit ? '6px' : undefined,
|
||||
borderBottom: `2px solid ${(node.style as any).borderColor}`,
|
||||
backgroundImage: edit
|
||||
? 'linear-gradient(0deg, #FFF7, #FFF7)'
|
||||
: undefined,
|
||||
...(edit ? node.whoStyle ?? {} : node.style),
|
||||
}}
|
||||
onDoubleClick={() => {
|
||||
editContentRef.current = node.content;
|
||||
setEdit(true);
|
||||
}}
|
||||
title="Double click to edit"
|
||||
>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
userSelect: 'none',
|
||||
padding: edit ? '0 6px' : '0 2px',
|
||||
borderRadius: '14px',
|
||||
border: '2px solid #0005',
|
||||
transition: 'filter 100ms',
|
||||
fontWeight: edit ? 800 : undefined,
|
||||
...node.whoStyle,
|
||||
}}
|
||||
>
|
||||
{node.who}
|
||||
</Box>
|
||||
{edit ? (
|
||||
<>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
multiline
|
||||
inputRef={ref => {
|
||||
if (ref) {
|
||||
ref.value = editContentRef.current;
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
'& > .MuiInputBase-root': {
|
||||
padding: '6px',
|
||||
'& > fieldset': {
|
||||
border: 'none',
|
||||
},
|
||||
background: '#FFF8',
|
||||
borderRadius: '12px',
|
||||
},
|
||||
borderRadius: '12px',
|
||||
border: '2px solid #0002',
|
||||
marginTop: '4px',
|
||||
'*': {
|
||||
fontSize: '14px',
|
||||
},
|
||||
}}
|
||||
onChange={event => (editContentRef.current = event.target.value)}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'end',
|
||||
paddingTop: '4px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
onClick={() => {
|
||||
if (!editContentRef.current) {
|
||||
return;
|
||||
}
|
||||
setEdit(false);
|
||||
const t = editContentRef.current;
|
||||
globalStorage.updateAgentActionNodeContent(
|
||||
id,
|
||||
t[0].toUpperCase() + t.slice(1),
|
||||
);
|
||||
}}
|
||||
title="Save change"
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: '#3ec807',
|
||||
borderRadius: '6px',
|
||||
marginLeft: '4px',
|
||||
padding: '0 4px',
|
||||
'&:hover': {
|
||||
filter: 'contrast(1.3)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CheckIcon sx={{ fontSize: '18px', color: 'white' }} />
|
||||
</Box>
|
||||
<Box
|
||||
onClick={() => setEdit(false)}
|
||||
title="Cancel change"
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: '#d56464',
|
||||
borderRadius: '6px',
|
||||
marginLeft: '4px',
|
||||
padding: '0 4px',
|
||||
'&:hover': {
|
||||
filter: 'contrast(1.3)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CloseIcon sx={{ fontSize: '18px', color: 'white' }} />
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
// <> {node.content}</>
|
||||
<span> {node.content}</span>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
import React from 'react';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import Box from '@mui/material/Box';
|
||||
import AgentDetailCard from './AgentDetailCard';
|
||||
import { globalStorage } from '@/storage';
|
||||
import { StepTaskNode } from '@/storage/plan';
|
||||
import { useResize } from '@/utils/resize-hook';
|
||||
import BranchIcon from '@/icons/BranchIcon';
|
||||
|
||||
export default observer(({ step }: { step: StepTaskNode }) => {
|
||||
const card = step.descriptionCard;
|
||||
const [expand, setExpand] = React.useState(false);
|
||||
const expandRef = React.useRef(expand);
|
||||
React.useEffect(() => {
|
||||
globalStorage.renderLines({ delay: 1, repeat: 20 });
|
||||
}, [expand]);
|
||||
const render = React.useMemo(
|
||||
() =>
|
||||
throttle(
|
||||
() =>
|
||||
requestAnimationFrame(() => {
|
||||
if (refDetail.current) {
|
||||
refDetail.current.style.height = expandRef.current
|
||||
? `${
|
||||
refDetail.current.querySelector('.description-detail')!
|
||||
.scrollHeight + 12
|
||||
}px`
|
||||
: '0px';
|
||||
}
|
||||
}),
|
||||
5,
|
||||
{
|
||||
leading: false,
|
||||
trailing: true,
|
||||
},
|
||||
),
|
||||
[],
|
||||
);
|
||||
React.useEffect(() => {
|
||||
expandRef.current = expand;
|
||||
render();
|
||||
}, [expand]);
|
||||
React.useEffect(() => {
|
||||
setExpand(globalStorage.focusingStepTaskId === step.id);
|
||||
}, [globalStorage.focusingStepTaskId]);
|
||||
const refDetail = useResize<HTMLDivElement>(render);
|
||||
return (
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
fontSize: '14px',
|
||||
flexDirection: 'column',
|
||||
background: '#F6F6F6',
|
||||
borderRadius: '8px',
|
||||
padding: '8px 4px',
|
||||
margin: '2px 0',
|
||||
cursor: 'pointer',
|
||||
border: '2px solid #E5E5E5',
|
||||
transition: 'all 80ms ease-in-out',
|
||||
'&:hover': {
|
||||
border: '2px solid #cdcdcd',
|
||||
backgroundImage: 'linear-gradient(0, #00000008, #00000008)',
|
||||
},
|
||||
display: step.brief.template ? 'flex' : 'none',
|
||||
}}
|
||||
ref={card.ref}
|
||||
onClick={() => globalStorage.setFocusingStepTaskId(step.id)}
|
||||
>
|
||||
<Box sx={{ marginLeft: '4px' }}>
|
||||
{card.brief.map(({ text, style }, index) =>
|
||||
style ? (
|
||||
<Box
|
||||
component="span"
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
sx={{
|
||||
userSelect: 'none',
|
||||
padding: '0 4px',
|
||||
fontWeight: 600,
|
||||
transition: 'filter 100ms',
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
component="span"
|
||||
key={index}
|
||||
sx={{ userSelect: 'none', lineHeight: '1.43rem' }}
|
||||
>
|
||||
{text}
|
||||
</Box>
|
||||
),
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
ref={refDetail}
|
||||
sx={{
|
||||
overflow: 'hidden',
|
||||
transition: 'height 200ms ease-out', // 添加过渡效果
|
||||
}}
|
||||
>
|
||||
{expand ? (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: '5px',
|
||||
borderRadius: '12px',
|
||||
padding: '4px 8px',
|
||||
background: '#E4F0F0',
|
||||
border: '3px solid #A9C6C5',
|
||||
cursor: 'auto',
|
||||
}}
|
||||
className="description-detail"
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
color: '#4F8A87',
|
||||
fontWeight: 800,
|
||||
fontSize: '16px',
|
||||
marginBottom: '4px',
|
||||
}}
|
||||
>
|
||||
Specification:
|
||||
</Box>
|
||||
{card.detail.map((node, index) => (
|
||||
<AgentDetailCard
|
||||
key={index}
|
||||
node={node[0] as any}
|
||||
id={node[1] as any}
|
||||
render={render}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
{globalStorage.focusingStepTaskId === step.id ? (
|
||||
<Box
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
position: 'absolute',
|
||||
right: '-4px',
|
||||
bottom: '2px',
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
bgcolor: 'primary.main',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '10px 0 0 0',
|
||||
'&:hover': {
|
||||
filter: 'brightness(0.9)',
|
||||
},
|
||||
}}
|
||||
onClick={() => (globalStorage.taskProcessModificationWindow = true)}
|
||||
>
|
||||
<BranchIcon />
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
fontSize: '12px',
|
||||
position: 'absolute',
|
||||
right: '3px',
|
||||
bottom: 0,
|
||||
color: 'white',
|
||||
fontWeight: 800,
|
||||
textAlign: 'right',
|
||||
}}
|
||||
>
|
||||
{step.agentSelection?.leaves?.length ?? 0}
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
57
frontend-react/src/components/ProcessDiscription/index.tsx
Normal file
57
frontend-react/src/components/ProcessDiscription/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { SxProps } from '@mui/material';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import DescriptionCard from './DescriptionCard';
|
||||
import { globalStorage } from '@/storage';
|
||||
import LoadingMask from '@/components/LoadingMask';
|
||||
import Title from '@/components/Title';
|
||||
|
||||
export default observer(({ style = {} }: { style?: SxProps }) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
background: '#FFF',
|
||||
border: '3px solid #E1E1E1',
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flexDirection: 'column',
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
<Title title="Task Process" />
|
||||
<Stack
|
||||
spacing={1}
|
||||
sx={{
|
||||
position: 'relative',
|
||||
padding: '6px 12px',
|
||||
paddingBottom: '44px',
|
||||
borderRadius: '10px',
|
||||
height: 0,
|
||||
flexGrow: 1,
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
onScroll={() => {
|
||||
globalStorage.renderLines({ delay: 0, repeat: 2 });
|
||||
}}
|
||||
>
|
||||
{globalStorage.planManager.currentPlan.map(step => (
|
||||
<DescriptionCard key={step.name} step={step} />
|
||||
))}
|
||||
{globalStorage.api.planGenerating ? (
|
||||
<LoadingMask
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user