feat(backend): 新增 QuickJS 运行时支持 JavaScript 执行器
refactor(backend): 重构 script_js 执行器实现 JavaScript 文件/内联脚本执行 feat(backend): 变量节点支持表达式/引用快捷语法输入 docs: 添加变量节点使用文档说明快捷语法功能 style(frontend): 调整测试面板样式和布局 fix(frontend): 修复测试面板打开时自动关闭节点编辑侧栏 build(backend): 添加 rquickjs 依赖用于 JavaScript 执行
This commit is contained in:
@ -10,7 +10,8 @@
|
||||
padding: 8px 8px 8px 4px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #7f92cd40;
|
||||
width: 348px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
:global(.cm-editor) {
|
||||
height: 100% !important;
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
}
|
||||
|
||||
.code-editor-container {
|
||||
min-height: 200px;
|
||||
max-height: 400px;
|
||||
min-height: 240px;
|
||||
max-height: 520px;
|
||||
background: #fff;
|
||||
padding: 8px 8px 8px 4px;
|
||||
border-radius: 4px;
|
||||
@ -40,13 +40,13 @@
|
||||
}
|
||||
|
||||
:global(.cm-scroller) {
|
||||
min-height: 200px !important;
|
||||
max-height: 400px !important;
|
||||
min-height: 240px !important;
|
||||
max-height: 520px !important;
|
||||
}
|
||||
|
||||
:global(.cm-content) {
|
||||
min-height: 200px !important;
|
||||
max-height: 400px !important;
|
||||
min-height: 240px !important;
|
||||
max-height: 520px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,9 +67,10 @@
|
||||
|
||||
.button {
|
||||
border-radius: 8px;
|
||||
width: 358px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
margin: 16px;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.running {
|
||||
background-color: rgba(87, 104, 161, 0.08) !important; // override semi style
|
||||
@ -93,6 +94,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.testrun-panel-header {
|
||||
background: var(#fcfcff);
|
||||
@ -129,11 +131,15 @@
|
||||
|
||||
.testrun-panel-footer {
|
||||
border-top: 1px solid rgba(82, 100, 154, 0.13);
|
||||
height: 40px;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
background: #fbfbfb;
|
||||
height: 72px;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: 0 0 8px 8px;
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,10 +102,12 @@ export const TestRunSidePanel: FC<TestRunSidePanelProps> = ({ visible, onCancel
|
||||
onCancel();
|
||||
};
|
||||
|
||||
// sidebar effect
|
||||
// 当测试运行面板打开时,自动关闭右侧节点编辑侧栏,避免两个 SideSheet 重叠
|
||||
useEffect(() => {
|
||||
setNodeId(undefined);
|
||||
}, []);
|
||||
if (visible) {
|
||||
setNodeId(undefined);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
useEffect(() => {
|
||||
if (sidebarNodeId) {
|
||||
@ -177,7 +179,7 @@ export const TestRunSidePanel: FC<TestRunSidePanelProps> = ({ visible, onCancel
|
||||
mask={false}
|
||||
motion={false}
|
||||
onCancel={onClose}
|
||||
width={400}
|
||||
width={500}
|
||||
headerStyle={{
|
||||
display: 'none',
|
||||
}}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
import { FormMeta, FormRenderProps } from '@flowgram.ai/free-layout-editor';
|
||||
import { AssignRows, createInferAssignPlugin, DisplayOutputs } from '@flowgram.ai/form-materials';
|
||||
import { Typography } from '@douyinfe/semi-ui';
|
||||
|
||||
import { FormHeader, FormContent } from '../../form-components';
|
||||
import { VariableNodeJSON } from './types';
|
||||
@ -18,7 +19,17 @@ export const FormRender = ({ form }: FormRenderProps<VariableNodeJSON>) => {
|
||||
<>
|
||||
<FormHeader />
|
||||
<FormContent>
|
||||
{isSidebar ? <AssignRows name="assign" /> : <DisplayOutputs displayFromScope />}
|
||||
{isSidebar ? (
|
||||
<>
|
||||
<Typography.Text type="tertiary" style={{ display: 'block', marginBottom: 8 }}>
|
||||
支持三种取值方式:常量、引用与表达式。快捷语法:
|
||||
1) 直接输入表达式,如 ctx["user_n"], ctx.user.profile.name;2) 使用 {"${path.to.value}"} 作为引用路径(等价于选择“引用”并逐级点选)。
|
||||
</Typography.Text>
|
||||
<AssignRows name="assign" />
|
||||
</>
|
||||
) : (
|
||||
<DisplayOutputs displayFromScope />
|
||||
)}
|
||||
</FormContent>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -31,6 +31,24 @@ function getFlowIdFromUrl(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 新增:针对后端的 design_json 兼容性转换
|
||||
// - 将前端 UI 的 type: 'code' 映射为后端可识别并映射到 script_js 执行器的 'javascript'
|
||||
// - 其余字段保持不变
|
||||
function transformDesignJsonForBackend(json: any): any {
|
||||
try {
|
||||
const clone = JSON.parse(JSON.stringify(json));
|
||||
clone.nodes = (clone.nodes || []).map((n: any) => {
|
||||
if (n && n.type === 'code') {
|
||||
return { ...n, type: 'javascript' };
|
||||
}
|
||||
return n;
|
||||
});
|
||||
return clone;
|
||||
} catch {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class CustomService {
|
||||
@inject(FreeLayoutPluginContext) ctx!: FreeLayoutPluginContext;
|
||||
@ -52,7 +70,9 @@ export class CustomService {
|
||||
}
|
||||
const json = this.document.toJSON() as any;
|
||||
const yaml = stringifyFlowDoc(json);
|
||||
const design_json = JSON.stringify(json);
|
||||
// 使用转换后的 design_json,以便后端将 code 节点识别为 javascript 并选择 script_js 执行器
|
||||
const designForBackend = transformDesignJsonForBackend(json);
|
||||
const design_json = JSON.stringify(designForBackend);
|
||||
const { data } = await api.put<ApiResp<{ saved: boolean }>>(`/flows/${id}`, { yaml, design_json });
|
||||
if (data?.code === 0) {
|
||||
if (!silent) Toast.success(I18n.t('Saved'));
|
||||
|
||||
Reference in New Issue
Block a user