feat: update
This commit is contained in:
parent
20481ca406
commit
6511dc8941
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.6 KiB |
@ -7,7 +7,6 @@
|
|||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
<!--
|
||||||
@ -25,7 +24,7 @@
|
|||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<script src="https://cdn-0.plantuml.com/synchro2.min.js"></script>
|
<script src="https://cdn-0.plantuml.com/synchro2.min.js"></script>
|
||||||
<title>React App</title>
|
<title>RingCentral@Workflow Hub</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@ -23,7 +23,7 @@ export const AIBot: FC<{
|
|||||||
Intelligence Admin Portal</a>
|
Intelligence Admin Portal</a>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box>
|
<Box>
|
||||||
<TextField label="AI Robot ID" onChange={handleChange} value={value}
|
<TextField label="AI Robot ID" fullWidth onChange={handleChange} value={value}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
@ -40,7 +40,8 @@ const ChatMessageWrap = styled(Box)<{ isMe: boolean }>(({ isMe }) => ({
|
|||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: isMe ? 'flex-end' : 'flex-start'
|
justifyContent: isMe ? 'flex-end' : 'flex-start',
|
||||||
|
color: isMe ? 'rgba(0, 0, 0, 0.87)' : 'white'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ChatMessage = styled(Box)(() => ({
|
const ChatMessage = styled(Box)(() => ({
|
||||||
|
201
src/Create.tsx
201
src/Create.tsx
@ -12,10 +12,8 @@ import Button from '@mui/material/Button';
|
|||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
import SendIcon from '@mui/icons-material/Send';
|
import SendIcon from '@mui/icons-material/Send';
|
||||||
import List from '@mui/material/List';
|
import List from '@mui/material/List';
|
||||||
import Chip from '@mui/material/Chip';
|
|
||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import { ChatItem } from "./ChatItem";
|
import { ChatItem } from "./ChatItem";
|
||||||
import Stack from '@mui/material/Stack';
|
|
||||||
import { cloneDeep, uniqueId } from 'lodash';
|
import { cloneDeep, uniqueId } from 'lodash';
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||||
@ -29,7 +27,11 @@ import { AIBot } from "./AIBot";
|
|||||||
import { GlipSender } from "./GlipSender";
|
import { GlipSender } from "./GlipSender";
|
||||||
import { ScriptBlock } from "./Script";
|
import { ScriptBlock } from "./Script";
|
||||||
import { message } from 'mui-message';
|
import { message } from 'mui-message';
|
||||||
import { isChatBot } from "./transform";
|
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
|
||||||
|
import InputAdornment from "@mui/material/InputAdornment";
|
||||||
|
import Stack from '@mui/material/Stack';
|
||||||
|
import Switch from '@mui/material/Switch';
|
||||||
|
import { styled } from "@mui/material/styles";
|
||||||
|
|
||||||
const DefaultMessage = [
|
const DefaultMessage = [
|
||||||
'Hello! Please tell me what kind of workflow you want to generate!\n',
|
'Hello! Please tell me what kind of workflow you want to generate!\n',
|
||||||
@ -55,7 +57,7 @@ type PreValue = string | undefined | null
|
|||||||
const preValueObj: { bot: PreValue; script: PreValue; email: PreValue; glip: PreValue } = {
|
const preValueObj: { bot: PreValue; script: PreValue; email: PreValue; glip: PreValue } = {
|
||||||
bot: '',
|
bot: '',
|
||||||
script: '',
|
script: '',
|
||||||
email: '',
|
email: '{"to":"","subject":"","content":"${localData.Desc}"}',
|
||||||
glip: ''
|
glip: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,7 +68,48 @@ interface Message {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SupportedBlock = ['BotMessage', 'Chat', 'GlipSender', 'Script'];
|
interface ActionWithStateName extends Action {
|
||||||
|
stateName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AntSwitch = styled(Switch)(({ theme }) => ({
|
||||||
|
width: 28,
|
||||||
|
height: 16,
|
||||||
|
padding: 0,
|
||||||
|
display: 'flex',
|
||||||
|
'&:active': {
|
||||||
|
'& .MuiSwitch-thumb': {
|
||||||
|
width: 15,
|
||||||
|
},
|
||||||
|
'& .MuiSwitch-switchBase.Mui-checked': {
|
||||||
|
transform: 'translateX(9px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiSwitch-switchBase': {
|
||||||
|
padding: 2,
|
||||||
|
'&.Mui-checked': {
|
||||||
|
transform: 'translateX(12px)',
|
||||||
|
color: '#fff',
|
||||||
|
'& + .MuiSwitch-track': {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'& .MuiSwitch-thumb': {
|
||||||
|
boxShadow: '0 2px 4px 0 rgb(0 35 11 / 20%)',
|
||||||
|
width: 12,
|
||||||
|
height: 12,
|
||||||
|
borderRadius: 6,
|
||||||
|
transition: theme.transitions.create(['width'], {
|
||||||
|
duration: 200,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
'& .MuiSwitch-track': {
|
||||||
|
borderRadius: 16 / 2,
|
||||||
|
opacity: 1,
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@ -88,22 +131,16 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
const flowDefinition = useMemo<Definition | undefined>(() => DSL2Json(workflowContent), [workflowContent]);
|
const flowDefinition = useMemo<Definition | undefined>(() => DSL2Json(workflowContent), [workflowContent]);
|
||||||
const previewImg = useMemo<string>(() => Json2Preview(flowDefinition), [flowDefinition]);
|
const previewImg = useMemo<string>(() => Json2Preview(flowDefinition), [flowDefinition]);
|
||||||
const chatContentRef = useRef<HTMLUListElement>(null);
|
const chatContentRef = useRef<HTMLUListElement>(null);
|
||||||
const actions = useMemo<Array<Action & {
|
const actions = useMemo<ActionWithStateName[]>(() => ((flowDefinition || {}).states || []).reduce<Array<Action & {
|
||||||
stateName: string
|
stateName: string
|
||||||
}>>(() => ((flowDefinition || {}).states || []).reduce<Array<Action & { stateName: string }>>((l, s) => {
|
}>>((l, s) => {
|
||||||
l.push(...s.actions.map(a => ({ ...a, stateName: s.name })));
|
l.push(...s.actions.map(a => ({ ...a, stateName: s.name })));
|
||||||
return l;
|
return l;
|
||||||
}, []), [flowDefinition]);
|
}, []), [flowDefinition]);
|
||||||
const hasEmailSender = useMemo(() => actions.some(a => a.actionType === "EmailSender"), [actions]);
|
const emailSenderAction = useMemo<ActionWithStateName | undefined>(() => actions.find(a => a.actionType === "EmailSender"), [actions]);
|
||||||
const botAddinAction = useMemo<Action & {
|
const botAddinAction = useMemo<ActionWithStateName | undefined>(() => actions.find(a => a.actionType === "Chat"), [actions]);
|
||||||
stateName: string
|
const scriptAction = useMemo<ActionWithStateName | undefined>(() => actions.find(a => a.actionType === "Script"), [actions]);
|
||||||
} | undefined>(() => actions.find(a => a.actionType === "Chat"), [actions]);
|
const glipSenderAction = useMemo<ActionWithStateName | undefined>(() => actions.find(a => a.actionType === "GlipSender"), [actions]);
|
||||||
const scriptAction = useMemo<Action & {
|
|
||||||
stateName: string
|
|
||||||
} | undefined>(() => actions.find(a => a.actionType === "Script"), [actions]);
|
|
||||||
const glipSenderAction = useMemo<Action & {
|
|
||||||
stateName: string
|
|
||||||
} | undefined>(() => actions.find(a => a.actionType === "GlipSender"), [actions]);
|
|
||||||
const [aibot, setAIBot] = useState('');
|
const [aibot, setAIBot] = useState('');
|
||||||
const [script, setScript] = useState('');
|
const [script, setScript] = useState('');
|
||||||
const [emailData, setEmailData] = useState<EmailValue>({
|
const [emailData, setEmailData] = useState<EmailValue>({
|
||||||
@ -112,14 +149,11 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
// eslint-disable-next-line no-template-curly-in-string
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
content: '${localData.Desc}',
|
content: '${localData.Desc}',
|
||||||
});
|
});
|
||||||
const [glipSenderData, setGlipSenderData] = useState({
|
const [glipSenderData, setGlipSenderData] = useState('');
|
||||||
clientId: '',
|
const [isImageMode, setImageMode] = useState(true);
|
||||||
clientSecret: '',
|
const creatorId = '4034902020';
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
|
||||||
message: ''
|
|
||||||
});
|
|
||||||
const [channelId, setChannelId] = useState('78394499078-4034902020');
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const [teamLink, setTeamLink] = useState('');
|
||||||
const debug = useMemo(() => {
|
const debug = useMemo(() => {
|
||||||
return (new URLSearchParams(location.search)).get('debug') === 'true';
|
return (new URLSearchParams(location.search)).get('debug') === 'true';
|
||||||
}, [location]);
|
}, [location]);
|
||||||
@ -148,9 +182,6 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
setChatInput(e.target.value);
|
setChatInput(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickChip = (text: string) => () => {
|
|
||||||
setChatInput(s => s + text);
|
|
||||||
};
|
|
||||||
const handleSend = async () => {
|
const handleSend = async () => {
|
||||||
const rId = uniqueId('r');
|
const rId = uniqueId('r');
|
||||||
|
|
||||||
@ -185,24 +216,15 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (glipSenderAction) {
|
if (glipSenderAction) {
|
||||||
let actionValueString = glipSenderAction.message;
|
let actionValueString = glipSenderAction.message;
|
||||||
let crtValueString = glipSenderData.message;
|
if (actionValueString !== preValueObj.glip && glipSenderData === preValueObj.glip) {
|
||||||
if (actionValueString !== preValueObj.glip && crtValueString === preValueObj.glip) {
|
setGlipSenderData(actionValueString || '');
|
||||||
setGlipSenderData({
|
|
||||||
clientSecret: '',
|
|
||||||
clientId: '',
|
|
||||||
message: actionValueString || '',
|
|
||||||
});
|
|
||||||
preValueObj.glip = actionValueString || '';
|
preValueObj.glip = actionValueString || '';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (preValueObj.glip) {
|
if (preValueObj.glip) {
|
||||||
preValueObj.glip = '';
|
preValueObj.glip = '';
|
||||||
setGlipSenderData({
|
|
||||||
clientSecret: '',
|
|
||||||
clientId: '',
|
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
message: '${localData.Desc}'
|
setGlipSenderData('${localData.Desc}');
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@ -232,7 +254,35 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [botAddinAction]);
|
}, [botAddinAction]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (emailSenderAction) {
|
||||||
|
const newValueStr = JSON.stringify({
|
||||||
|
to: emailSenderAction.to || '',
|
||||||
|
subject: emailSenderAction.subject || '',
|
||||||
|
content: emailSenderAction.content || ''
|
||||||
|
});
|
||||||
|
const crtValueStr = JSON.stringify({
|
||||||
|
to: emailData.to,
|
||||||
|
subject: emailData.subject,
|
||||||
|
content: emailData.content
|
||||||
|
});
|
||||||
|
if (newValueStr !== preValueObj.email && crtValueStr === preValueObj.email) {
|
||||||
|
setEmailData({
|
||||||
|
to: emailSenderAction.to || '',
|
||||||
|
subject: emailSenderAction.subject || '',
|
||||||
|
content: emailSenderAction.content || ''
|
||||||
|
});
|
||||||
|
preValueObj.email = newValueStr || '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setEmailData({
|
||||||
|
to: '',
|
||||||
|
subject: '',
|
||||||
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
|
content: '${localData.Desc}',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [emailSenderAction]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chatContentRef.current) {
|
if (chatContentRef.current) {
|
||||||
chatContentRef.current.scrollTop = chatContentRef.current.scrollHeight - chatContentRef.current.offsetHeight;
|
chatContentRef.current.scrollTop = chatContentRef.current.scrollHeight - chatContentRef.current.offsetHeight;
|
||||||
@ -250,15 +300,7 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
setWorkflowContent('');
|
setWorkflowContent('');
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!hasEmailSender)
|
|
||||||
setEmailData({
|
|
||||||
to: '',
|
|
||||||
subject: '',
|
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
|
||||||
content: '${localData.Desc}',
|
|
||||||
});
|
|
||||||
}, [hasEmailSender]);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!flowDefinition) return;
|
if (!flowDefinition) return;
|
||||||
@ -278,11 +320,14 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
}
|
}
|
||||||
if (action.actionType === 'GlipSender') {
|
if (action.actionType === 'GlipSender') {
|
||||||
// action.url = glipSenderData.url;
|
// action.url = glipSenderData.url;
|
||||||
action.message = glipSenderData.message || '${localData.Desc}';
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
|
action.message = glipSenderData || '${localData.Desc}';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
console.log(Json2Yml(newJson));
|
console.log(Json2Yml(newJson));
|
||||||
|
const channelId = (teamLink.replace(/[^\d]+/, '')) + '-' + creatorId;
|
||||||
|
console.log(channelId);
|
||||||
await axios.put(`/bot/workflow/${id}`, {
|
await axios.put(`/bot/workflow/${id}`, {
|
||||||
name: formJson.name,
|
name: formJson.name,
|
||||||
content: Json2Yml(newJson)
|
content: Json2Yml(newJson)
|
||||||
@ -291,7 +336,7 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
await axios.delete(`/bot/workflow/${id}/bind/${channelId}`);
|
await axios.delete(`/bot/workflow/${id}/bind/${channelId}`);
|
||||||
await axios.post(`/bot/workflow/${id}/bind`, { channelId });
|
await axios.post(`/bot/workflow/${id}/bind`, { channelId });
|
||||||
}
|
}
|
||||||
message.success(`Saved! ${debug ? 'Back to List and go bind your channel!' : ''}`);
|
message.success(`Publish Success! ${debug ? 'Back to List and go bind your channel!' : ''}`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate(`/${debug ? '?debug=true' : ''}`);
|
navigate(`/${debug ? '?debug=true' : ''}`);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
@ -356,6 +401,9 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: <InputAdornment position="start"><AutoAwesomeIcon color="primary"/></InputAdornment>
|
||||||
|
}}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
focused placeholder="Enter your goal ..."
|
focused placeholder="Enter your goal ..."
|
||||||
multiline maxRows={3}
|
multiline maxRows={3}
|
||||||
@ -372,21 +420,56 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<Box sx={{ border: 1, height: 600, borderRadius: 1, p: 2, mt: 4, borderColor: 'rgba(255,255,255,0.23)' }}>
|
<Box sx={{
|
||||||
{!previewImg ? <>👋 The flow chart will be previewed here! <br/>😻 Tell the AI robot what you want to
|
border: 1,
|
||||||
do! </> :
|
height: 600,
|
||||||
<img src={previewImg} style={{ width: '100%', height: '100%' }} alt="preview"/>}
|
borderRadius: 1,
|
||||||
|
mt: 4,
|
||||||
|
borderColor: 'rgba(255,255,255,0.23)',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}>
|
||||||
|
{!previewImg ?
|
||||||
|
<div style={{ padding: 16 }}>👋 The flow chart will be previewed here! <br/>😻 Tell the AI robot what
|
||||||
|
you want to
|
||||||
|
do! </div> :
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
<Stack sx={{ p: 2 }} direction="row" spacing={1} alignItems="center" justifyContent="flex-end">
|
||||||
|
<Typography variant="body2">Raw</Typography>
|
||||||
|
<AntSwitch checked={isImageMode} onChange={(_, checked) => setImageMode(checked)}/>
|
||||||
|
<Typography variant="body2">Image</Typography>
|
||||||
|
</Stack>
|
||||||
|
{isImageMode ?
|
||||||
|
<img src={previewImg} style={{ maxWidth: '100%', maxHeight: '100%' }} alt="preview"/> :
|
||||||
|
<pre style={{ height: 546, overflow: 'auto', marginTop: 0 }}><code style={{
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'left',
|
||||||
|
display: 'block',
|
||||||
|
padding: 16,
|
||||||
|
}}>{workflowContent}</code></pre>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Divider sx={{ mt: 4, mb: 4 }}/>
|
<Divider sx={{ mt: 4, mb: 4 }}/>
|
||||||
{!!scriptAction || hasEmailSender || !!botAddinAction ?
|
{!!scriptAction || !!emailSenderAction || !!botAddinAction || !!glipSenderAction ?
|
||||||
<Typography variant="subtitle2" sx={{ mb: 2 }}>
|
<Typography variant="subtitle2" sx={{ mb: 2 }}>
|
||||||
Please fill in the following information related to your workflow nodes. 👇🏻👇🏻 </Typography> : null}
|
Please fill in the following information related to your workflow nodes. 👇🏻👇🏻 </Typography> : null}
|
||||||
{hasEmailSender && <EmailSender value={emailData} onChange={setEmailData}/>}
|
{!!emailSenderAction && <EmailSender value={emailData} onChange={setEmailData}/>}
|
||||||
{!!botAddinAction && <AIBot name={botAddinAction.stateName} value={aibot} onChange={setAIBot}/>}
|
{!!botAddinAction && <AIBot name={botAddinAction.stateName} value={aibot} onChange={setAIBot}/>}
|
||||||
{!!scriptAction && <ScriptBlock name={scriptAction.stateName} value={script} onChange={setScript}/>}
|
{!!scriptAction && <ScriptBlock name={scriptAction.stateName} value={script} onChange={setScript}/>}
|
||||||
{!!glipSenderAction && <GlipSender debug={debug} value={glipSenderData} onChange={setGlipSenderData}/>}
|
{!!glipSenderAction &&
|
||||||
|
<GlipSender debug={debug} teamLink={teamLink} id={id} edit={edit} value={glipSenderData}
|
||||||
|
onChange={(value, isTeamLink) => {
|
||||||
|
if (isTeamLink) {
|
||||||
|
setTeamLink(value);
|
||||||
|
} else {
|
||||||
|
setGlipSenderData(value);
|
||||||
|
}
|
||||||
|
}}/>}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<div style={{ height: 80 }}></div>
|
<div style={{ height: 80 }}></div>
|
||||||
@ -404,7 +487,7 @@ export const Create: FC<{ edit?: boolean }> = ({ edit }) => {
|
|||||||
borderColor: 'divider',
|
borderColor: 'divider',
|
||||||
display: { xs: 'flex' }, justifyContent: "flex-end"
|
display: { xs: 'flex' }, justifyContent: "flex-end"
|
||||||
}}>
|
}}>
|
||||||
<Button variant="contained" style={{ width: 100 }} onClick={handleSubmit}>Save</Button>
|
<Button variant="contained" style={{ width: 100 }} onClick={handleSubmit}>Publish</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import MonacoEditor from 'react-monaco-editor';
|
import MonacoEditor from 'react-monaco-editor';
|
||||||
|
|
||||||
export const Editor: React.FC<{ value: string; onChange: (value: string) => void }> = ({ value, onChange }) => {
|
export const Editor: React.FC<{ value: string; onChange: (value: string) => void }> = ({ value, onChange }) => {
|
||||||
|
@ -24,15 +24,15 @@ export const EmailSender: FC<{
|
|||||||
<Typography variant="subtitle1" sx={{mb: 1}}>Email Sender</Typography>
|
<Typography variant="subtitle1" sx={{mb: 1}}>Email Sender</Typography>
|
||||||
<Box>
|
<Box>
|
||||||
<TextField label="Send To" placeholder="Please enter your email address" type="email"
|
<TextField label="Send To" placeholder="Please enter your email address" type="email"
|
||||||
value={value} name="to" fullWidth sx={{mb: 4}}
|
value={value.to} name="to" fullWidth sx={{mb: 4}}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<TextField label="Subject" placeholder="Please enter your email subject"
|
<TextField label="Subject" placeholder="Please enter your email subject"
|
||||||
value={value} name="subject" fullWidth sx={{mb: 4}}
|
value={value.subject} name="subject" fullWidth sx={{mb: 4}}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<TextField label="Content" placeholder="Please enter your email content"
|
<TextField label="Content" placeholder="Please enter your email content"
|
||||||
value={value} name="content" fullWidth sx={{mb: 4}}
|
value={value.content} name="content" fullWidth sx={{mb: 4}}
|
||||||
onChange={handleChange} maxRows={8} minRows={3} multiline
|
onChange={handleChange} maxRows={8} minRows={3} multiline
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,41 +1,94 @@
|
|||||||
import React, { ChangeEvent, FC, useEffect, useState } from 'react';
|
import React, { ChangeEvent, FC, useState } from 'react';
|
||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
|
import InputAdornment from "@mui/material/InputAdornment";
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import Visibility from '@mui/icons-material/Visibility';
|
||||||
|
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
||||||
|
import { MenuItem, Select, SelectChangeEvent } from "@mui/material";
|
||||||
|
|
||||||
export const GlipSender: FC<{
|
export const GlipSender: FC<{
|
||||||
|
value: string;
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
value: { clientId: string; clientSecret: string; message: string };
|
edit?: boolean
|
||||||
onChange: (value: {
|
id?: string
|
||||||
clientId: string; clientSecret: string; message: string
|
teamLink: string
|
||||||
}) => void
|
onChange: (value: string, isTeamLink?: boolean) => void
|
||||||
}> = ({ value, debug, onChange }) => {
|
}> = ({ value, id,teamLink, debug, edit, onChange }) => {
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange({
|
onChange(e.target.value);
|
||||||
...value,
|
|
||||||
[e.target.name]: e.target.value
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
const [showPassword, setShowPassword] = React.useState(edit ? false : true);
|
||||||
|
|
||||||
|
const handleClickShowPassword = () => setShowPassword((show) => !show);
|
||||||
|
|
||||||
|
const handleMouseDownPassword = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const [senderType, setSenderType] = useState('default');
|
||||||
|
const handleChangeType = (e: SelectChangeEvent) => {
|
||||||
|
setSenderType(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeTeam = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
onChange(event.target.value, true)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ p: 2, mb: 2 }}>
|
<Paper sx={{ p: 2, mb: 2 }}>
|
||||||
<Typography variant="subtitle1">GlipSender</Typography>
|
<Typography variant="subtitle1" sx={{ mb: 1 }}>GlipSender</Typography>
|
||||||
<Typography variant="caption" component="div" sx={{ mb: 1 }}>
|
|
||||||
WFL Hub will send messages via <a style={{ color: '#f50057' }}
|
|
||||||
href="https://developers.ringcentral.com/guide/team-messaging/bots/walkthrough"
|
|
||||||
target="_blank" rel="noreferrer">RingCentral Bot</a>, please fill in:
|
|
||||||
</Typography>
|
|
||||||
<Box>
|
<Box>
|
||||||
{!debug &&
|
{!debug &&
|
||||||
<>
|
<>
|
||||||
<TextField label="RingCentral Bot Client ID" fullWidth name="clientId" onChange={handleChange}
|
<Select value={senderType} sx={{ mb: 1 }} onChange={handleChangeType}>
|
||||||
value={value.clientId} sx={{ mb: 4 }}/>
|
<MenuItem value="default">Use built-in bot (only supports team message)</MenuItem>
|
||||||
<TextField label="RingCentral Bot Client Secret" sx={{ mb: 4 }}
|
<MenuItem value="custom">Use custom bot</MenuItem>
|
||||||
value={value.clientSecret} name="clientSecret" fullWidth onChange={handleChange}
|
</Select>
|
||||||
|
{senderType === 'default' ? <>
|
||||||
|
<Typography sx={{ mb: 2 }} variant="caption" component="div">
|
||||||
|
WFL Hub will send message via default bot <a style={{ color: '#f50057' }}>@David-Bot</a>
|
||||||
|
</Typography>
|
||||||
|
<TextField label="Team Link" fullWidth name="teamLink" id="teamLink" key="1" sx={{ mb: 4 }} value={teamLink}
|
||||||
|
onChange={handleChangeTeam}
|
||||||
|
defaultValue={edit ? 'https://app.ringcentral.com/l/messages/134751420422' : ''}/>
|
||||||
|
</> :
|
||||||
|
<>
|
||||||
|
<Typography variant="caption" component="div" sx={{ mb: 2 }}>
|
||||||
|
WFL Hub will send messages via your <a style={{ color: '#f50057' }}
|
||||||
|
href="https://developers.ringcentral.com/guide/team-messaging/bots/walkthrough"
|
||||||
|
target="_blank" rel="noreferrer">RingCentral Bot</a>, please
|
||||||
|
fill in:
|
||||||
|
</Typography>
|
||||||
|
<TextField label="RingCentral Bot Client ID" fullWidth name="clientId" key="2" id="clientId" sx={{ mb: 4 }}
|
||||||
|
defaultValue={edit ? '0w3wgTW5dkdfGjdseGDJ2y' : ''}/>
|
||||||
|
<TextField label="RingCentral Bot Client Secret" sx={{ mb: 4 }} key="3" name="clientSecret" id="clientSecret"
|
||||||
|
fullWidth
|
||||||
|
defaultValue={edit ? '6oGJ8Nko0socCF6rzFqKsk7FbNyT33ouDebXsOhACDhp' : ''}
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={handleClickShowPassword}
|
||||||
|
onMouseDown={handleMouseDownPassword}
|
||||||
|
edge="end"
|
||||||
|
>
|
||||||
|
{showPassword ? <VisibilityOff/> : <Visibility/>}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</>}
|
</>}
|
||||||
|
|
||||||
|
</>}
|
||||||
<TextField label="Message format" placeholder="Please enter your message format"
|
<TextField label="Message format" placeholder="Please enter your message format"
|
||||||
value={value.message} name="message" fullWidth
|
value={value} name="message" fullWidth
|
||||||
onChange={handleChange} maxRows={5} minRows={2} multiline
|
onChange={handleChange} maxRows={5} minRows={2} multiline
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
28
src/List.tsx
28
src/List.tsx
@ -39,6 +39,7 @@ interface Workflow {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
lastModifiedTime: string;
|
lastModifiedTime: string;
|
||||||
|
emoji?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const List = () => {
|
export const List = () => {
|
||||||
@ -52,7 +53,10 @@ export const List = () => {
|
|||||||
total: number
|
total: number
|
||||||
workflows: Workflow[]
|
workflows: Workflow[]
|
||||||
}>('/api/public/wf/config/v1/account/10086/workflows').then(({ data }) => {
|
}>('/api/public/wf/config/v1/account/10086/workflows').then(({ data }) => {
|
||||||
setList(data.workflows);
|
setList(data.workflows.map(it => ({
|
||||||
|
...it,
|
||||||
|
emoji: getRandomEmoji()
|
||||||
|
})));
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
@ -84,7 +88,7 @@ export const List = () => {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const formData = new FormData(event.currentTarget);
|
const formData = new FormData(event.currentTarget);
|
||||||
const formJson = Object.fromEntries((formData as any).entries());
|
const formJson = Object.fromEntries((formData as any).entries());
|
||||||
const channelId = formJson.channelId.trim();
|
const channelId = `${formJson.groupId.trim()}-${formJson.creatorId.trim()}`;
|
||||||
await axios.delete(`/bot/workflow/${showBindModal}/bind/${channelId}`);
|
await axios.delete(`/bot/workflow/${showBindModal}/bind/${channelId}`);
|
||||||
await axios.post(`/bot/workflow/${showBindModal}/bind`, { channelId });
|
await axios.post(`/bot/workflow/${showBindModal}/bind`, { channelId });
|
||||||
message.success('Success!');
|
message.success('Success!');
|
||||||
@ -105,7 +109,7 @@ export const List = () => {
|
|||||||
<CardActionArea>
|
<CardActionArea>
|
||||||
<CardContent style={{ height: 100 }}>
|
<CardContent style={{ height: 100 }}>
|
||||||
<Typography gutterBottom variant="h5" component="div">
|
<Typography gutterBottom variant="h5" component="div">
|
||||||
{getRandomEmoji()} {item.name || 'My Workflow'}
|
{item.emoji} {item.name || 'My Workflow'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardActions
|
<CardActions
|
||||||
@ -121,8 +125,8 @@ export const List = () => {
|
|||||||
<Button size="small" onClick={(e: any) => {
|
<Button size="small" onClick={(e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleOpenBind(item.id);
|
handleOpenBind(item.id);
|
||||||
}}>Bind</Button> :
|
}}>Bind</Button> : <Button size="small">Copy</Button>}
|
||||||
<Switch defaultChecked/>}
|
{/*<Switch defaultChecked/>*/}
|
||||||
</CardActions>
|
</CardActions>
|
||||||
</CardActionArea>
|
</CardActionArea>
|
||||||
</Card>
|
</Card>
|
||||||
@ -147,7 +151,6 @@ export const List = () => {
|
|||||||
margin="dense"
|
margin="dense"
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
defaultValue="My workflow"
|
|
||||||
label="Workflow Name"
|
label="Workflow Name"
|
||||||
fullWidth
|
fullWidth
|
||||||
focused
|
focused
|
||||||
@ -169,10 +172,17 @@ export const List = () => {
|
|||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
margin="dense"
|
margin="dense"
|
||||||
id="channelId" focused
|
id="groupId" focused
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
label="Channel Id" fullWidth name="channelId"
|
label="Group Id" fullWidth name="groupId"
|
||||||
helperText="ChannelId is ${groupId}-${creatorId}"
|
helperText="You can get team groupId from team link"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
margin="dense"
|
||||||
|
id="creatorId" focused
|
||||||
|
variant="outlined"
|
||||||
|
label="Creator Id" fullWidth name="creatorId"
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
@ -30,3 +30,7 @@ a {
|
|||||||
.MuiButton-contained:hover {
|
.MuiButton-contained:hover {
|
||||||
background-color: rgb(118, 126, 168) !important;
|
background-color: rgb(118, 126, 168) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Mui-focused .MuiOutlinedInput-notchedOutline {
|
||||||
|
/*color: #aab5f1*/
|
||||||
|
}
|
||||||
|
@ -71,7 +71,6 @@ export interface Definition {
|
|||||||
export function Json2Preview(definition?: Definition): string {
|
export function Json2Preview(definition?: Definition): string {
|
||||||
if (!definition) return '';
|
if (!definition) return '';
|
||||||
try {
|
try {
|
||||||
console.log(transformDSL(definition));
|
|
||||||
return compress(transformDSL(definition), '/svg/');
|
return compress(transformDSL(definition), '/svg/');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { Action, Definition, State } from "./loadYml";
|
import { Action, Definition, State } from "./loadYml";
|
||||||
|
|
||||||
const EVENT_COLOR = "#LightYellow";
|
const EVENT_COLOR = "#IndianRed";
|
||||||
const HTTP_COLOR = "#Peru";
|
const HTTP_COLOR = "#Sienna";
|
||||||
const SCRIPT_COLOR = "#Olive;text:white";
|
const SCRIPT_COLOR = "#Olive";
|
||||||
const BOT_COLOR = "#Blue;text:white";
|
const BOT_COLOR = "#RoyalBlue";
|
||||||
const EMAIL_SENDER_COLOR = "#Red;text:white";
|
const EMAIL_SENDER_COLOR = "#Crimson";
|
||||||
const CHAT_BOT_COLOR = "#Orange;text:white";
|
const CHAT_BOT_COLOR = "#OrangeRed";
|
||||||
const GLIP_COLOR = "#Pink;text:white";
|
const GLIP_COLOR = "#DeepPink";
|
||||||
const DEFAULT_COLOR = '#Grey;text;white';
|
|
||||||
|
|
||||||
const EVENT_NAME = ": Event";
|
const EVENT_NAME = ": Event";
|
||||||
const HTTP_NAME = ": Http";
|
const HTTP_NAME = ": Http";
|
||||||
@ -15,33 +14,28 @@ const SCRIPT_NAME = ": Script";
|
|||||||
const BOT_NAME = ": Chat";
|
const BOT_NAME = ": Chat";
|
||||||
const EMAIL_SENDER_NAME = ": EmailSender";
|
const EMAIL_SENDER_NAME = ": EmailSender";
|
||||||
const GLIP_SENDER_NAME = ': GlipSender';
|
const GLIP_SENDER_NAME = ': GlipSender';
|
||||||
const EXIT_NAME = ": Exit";
|
|
||||||
|
|
||||||
function isHttp(actions: Action[]): boolean {
|
export function isHttp(actions: Action[]): boolean {
|
||||||
return actions
|
return actions
|
||||||
.some((action) => action.actionType === "HttpRequest");
|
.some((action) => action.actionType === "HttpRequest");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isScript(actions: Action[]): boolean {
|
export function isScript(actions: Action[]): boolean {
|
||||||
return actions
|
return actions
|
||||||
.some((action) => action.actionType === "Script");
|
.some((action) => action.actionType === "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isChat(actions: Action[]): boolean {
|
export function isChat(actions: Action[]): boolean {
|
||||||
return actions
|
return actions
|
||||||
.some((action) => action.actionType === 'ChatBot');
|
.some((action) => action.actionType === 'ChatBot');
|
||||||
}
|
}
|
||||||
|
|
||||||
function isGlipSender(actions: Action[]): boolean {
|
export function isGlipSender(actions: Action[]): boolean {
|
||||||
return actions
|
return actions
|
||||||
.some((action) => action.actionType === 'GlipSender');
|
.some((action) => action.actionType === 'GlipSender');
|
||||||
}
|
}
|
||||||
|
|
||||||
function isExit(actions: Action[]): boolean {
|
export function isEmailSender(actions: Action[]): boolean {
|
||||||
return actions.some((action) => action.actionType === 'Exit');
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEmailSender(actions: Action[]): boolean {
|
|
||||||
return actions
|
return actions
|
||||||
.some((action) => action.actionType === "EmailSender");
|
.some((action) => action.actionType === "EmailSender");
|
||||||
}
|
}
|
||||||
@ -188,8 +182,22 @@ export function transformDSL(definition: Definition): string {
|
|||||||
sb += drawStateLine(eventState, state) || '';
|
sb += drawStateLine(eventState, state) || '';
|
||||||
}
|
}
|
||||||
return `@startuml
|
return `@startuml
|
||||||
|
skinparam backgroundColor #242425
|
||||||
|
skinparam state {
|
||||||
|
FontColor white
|
||||||
|
BackgroundColor DimGray
|
||||||
|
BorderColor #AAB5F1
|
||||||
|
ArrowColor #AAB5F1
|
||||||
|
ArrowFontColor #AAB5F1
|
||||||
|
}
|
||||||
|
|
||||||
|
skinparam activity {
|
||||||
|
StartColor Silver
|
||||||
|
EndColor Silver
|
||||||
|
}
|
||||||
|
|
||||||
${sb}
|
${sb}
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user