chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
@@ -52,8 +52,8 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
||||
},
|
||||
ParamsTypeDefine: {},
|
||||
PluginMockDataGenerateMode: {
|
||||
MANUAL: 0, // 手动创建
|
||||
RANDOM: 1, // 随机生成
|
||||
MANUAL: 0, // create manually
|
||||
RANDOM: 1, // random generation
|
||||
LLM: 2,
|
||||
},
|
||||
}));
|
||||
@@ -61,21 +61,21 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
||||
vi.mock('@coze-arch/bot-hooks', () => ({
|
||||
SceneType: {
|
||||
BOT__VIEW__WORKFLOW: 'botViewWorkflow',
|
||||
/** bot 详情页查看 workflow,或新建 workflow 但未发布,点击返回 */
|
||||
/** View the workflow on the bot details page, or create a new workflow but not published, click Return */
|
||||
WORKFLOW__BACK__BOT: 'workflowBackBot',
|
||||
/** bot 详情页创建 workflow,在 workflow 发布后返回 */
|
||||
/** The bot details page creates a workflow and returns it after the workflow is published */
|
||||
WORKFLOW_PUBLISHED__BACK__BOT: 'workflowPublishedBackBot',
|
||||
/** bot 详情页进入 mock data 页面 */
|
||||
/** Bot details page Enter the mock data page */
|
||||
BOT__TO__PLUGIN_MOCK_DATA: 'botToPluginMockData',
|
||||
/** workflow 详情页进入 mock data 页面 */
|
||||
/** Workflow details page Enter the mock data page */
|
||||
WORKFLOW__TO__PLUGIN_MOCK_DATA: 'workflowToPluginMockData',
|
||||
/** mock set 页进入 mock data 页面 */
|
||||
/** Mock set page Enter the mock data page */
|
||||
PLUGIN_MOCK_SET__TO__PLUGIN_MOCK_DATA: 'pluginMockSetToPluginMockData',
|
||||
/** bot 详情页进入 knowledge 页面 */
|
||||
/** Bot details page Enter the knowledge page */
|
||||
BOT__VIEW__KNOWLEDGE: 'botViewKnowledge',
|
||||
/** knowledge 页面点击退出返回 bot 详情页(未点击添加) */
|
||||
/** Knowledge page Click Exit to return to bot details page (not clicked Add) */
|
||||
KNOWLEDGE__BACK__BOT: 'knowledgeBackBot',
|
||||
/** knowledge 页面点击返回 bot 详情页,并添加到 bot */
|
||||
/** Knowledge page Click to return to bot details page and add to bot */
|
||||
KNOWLEDGE__ADD_TO__BOT: 'knowledgeAddToBot',
|
||||
},
|
||||
usePageJumpService: vi.fn().mockReturnValue({
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// 引入我们的被测方法
|
||||
// Introducing our test method
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -23,39 +23,39 @@ import { getEnv } from '@/util/get-env';
|
||||
describe('getEnv function', () => {
|
||||
it('should return "cn-boe" when not in production', () => {
|
||||
vi.stubGlobal('IS_PROD', undefined);
|
||||
// 不设置IS_PROD,默认为非生产环境
|
||||
// Do not set IS_PROD, default to non-production environment
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-boe');
|
||||
});
|
||||
|
||||
it('should return "cn-release" when in production, not overseas, and is release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', false); // 不是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // 是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', false); // Not overseas.
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // Is the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-release');
|
||||
});
|
||||
|
||||
it('should return "cn-inhouse" when in production, not overseas, and is not release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', false); // 不是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // 不是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', false); // Not overseas.
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // Not the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-inhouse');
|
||||
});
|
||||
|
||||
it('should return "oversea-release" when in production, overseas, and is release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', true); // 是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // 是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', true); // Is overseas
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // Is the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('oversea-release');
|
||||
});
|
||||
|
||||
it('should return "oversea-inhouse" when in production, overseas, and is not release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', true); // 是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // 不是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', true); // Is overseas
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // Not the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('oversea-inhouse');
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ export const PluginModal: React.FC<PluginModalProps> = ({
|
||||
return openMode === OpenModeType.OnlyOnceAdd ? [] : pluginApis;
|
||||
};
|
||||
const { sider, filter, content } = usePluginModalParts({
|
||||
// 如果是仅添加一次,清空默认选中
|
||||
// If it is added only once, clear the default selection.
|
||||
pluginApiList: getPluginApiList(),
|
||||
onPluginApiListChange: updateSkillPluginApis,
|
||||
openMode,
|
||||
|
||||
@@ -36,7 +36,7 @@ export const usePluginApisModal = (props?: PluginModalModeProps) => {
|
||||
const _initQuery = isNumber(params) ? undefined : params?.initQuery;
|
||||
setVisible(true);
|
||||
setInitQuery(_initQuery);
|
||||
// 0 也有效
|
||||
// 0 is also valid
|
||||
if (isNumber(openType)) {
|
||||
setType(openType);
|
||||
}
|
||||
|
||||
@@ -54,17 +54,17 @@ export interface ToolDetailPageProps
|
||||
onDebugSuccessCallback?: () => void;
|
||||
}
|
||||
|
||||
// 页面-编辑插件API
|
||||
// Page - Edit Plugin API
|
||||
export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
toolID,
|
||||
onDebugSuccessCallback,
|
||||
renderDescComponent,
|
||||
renderParamsComponent,
|
||||
}) => {
|
||||
//捕获错误信息,跳转统一落地页
|
||||
//Capture error messages and jump to the unified landing page
|
||||
const capture = useErrorHandler();
|
||||
const [editVersion, setEditVersion] = useState<number>();
|
||||
//插件-API详情
|
||||
//Plugin-API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>();
|
||||
const [debugApiInfo, setDebugApiInfo] = useState<PluginAPIInfo>();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
@@ -104,7 +104,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
// 重置 request 参数
|
||||
// Reset request parameters
|
||||
const resetRequestParams = (data: PluginAPIInfo) => {
|
||||
const requestParams = cloneDeep(data.request_params as APIParameter[]);
|
||||
if (
|
||||
@@ -120,7 +120,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
return requestParams;
|
||||
};
|
||||
|
||||
// 设置接口信息(回显和置空)
|
||||
// Set interface information (echo and empty)
|
||||
const handleInit = async (useloading = false) => {
|
||||
setApiInfo({
|
||||
...apiInfo,
|
||||
@@ -140,12 +140,12 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
|
||||
if (api_info.length > 0) {
|
||||
const apiInfoTemp = api_info.length > 0 ? api_info[0] : {};
|
||||
// debug 的数据 如果有 example 需要回显 入参数据额外处理
|
||||
// Debug data, if there is an example, the imported parameter data needs to be echoed for additional processing
|
||||
setDebugApiInfo({
|
||||
...apiInfoTemp,
|
||||
request_params: resetRequestParams(apiInfoTemp),
|
||||
});
|
||||
// 给对象增加层级标识
|
||||
// Adding hierarchical identifiers to objects
|
||||
addDepthAndValue(apiInfoTemp.request_params);
|
||||
addDepthAndValue(apiInfoTemp.response_params);
|
||||
setApiInfo(apiInfoTemp);
|
||||
@@ -170,7 +170,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
useloading && setLoading(false);
|
||||
};
|
||||
|
||||
// 1.基本信息
|
||||
// 1. Basic information
|
||||
const {
|
||||
isBaseInfoDisabled,
|
||||
header: baseInfoHeader,
|
||||
@@ -190,7 +190,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
renderDescComponent,
|
||||
});
|
||||
|
||||
// 2 更多设置
|
||||
// 2 more settings
|
||||
const {
|
||||
isBaseMoreDisabled,
|
||||
header: baseMoreHeader,
|
||||
@@ -211,7 +211,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
onSuccess: handleSuccess,
|
||||
});
|
||||
|
||||
// 3.设置 request
|
||||
// 3. Set request
|
||||
const {
|
||||
isRequestParamsDisabled,
|
||||
itemKey: requestItemKey,
|
||||
@@ -233,7 +233,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
renderParamsComponent,
|
||||
});
|
||||
|
||||
// 4.设置 response
|
||||
// 4. Set up the response
|
||||
const {
|
||||
isResponseParamsDisabled,
|
||||
itemKey: responseItemKey,
|
||||
@@ -298,7 +298,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 预览状态解锁,如果有一步为编辑态,则不解锁
|
||||
// The preview state is unlocked. If there is an edit state, it will not be unlocked.
|
||||
useUpdateEffect(() => {
|
||||
if (
|
||||
!isBaseInfoDisabled ||
|
||||
|
||||
@@ -69,7 +69,7 @@ const ToolHeader: FC<ToolHeaderProps> = ({
|
||||
unlockPlugin();
|
||||
};
|
||||
|
||||
// 管理模拟集
|
||||
// management simulation set
|
||||
const handleManageMockset = () => {
|
||||
resourceNavigate.mocksetList?.(tool_id);
|
||||
};
|
||||
@@ -119,7 +119,7 @@ const ToolHeader: FC<ToolHeaderProps> = ({
|
||||
/>
|
||||
<span className={s.title}>{I18n.t('plugin_edit_tool_title')}</span>
|
||||
<OauthButtonAction />
|
||||
{/* 即将支持,敬请期待 */}
|
||||
{/* Support soon, so stay tuned. */}
|
||||
{FLAGS['bot.devops.plugin_mockset'] ? (
|
||||
<Tooltip
|
||||
style={{ display: mocksetDisabled ? 'block' : 'none' }}
|
||||
|
||||
@@ -54,12 +54,12 @@ export const useContentBaseMore = ({
|
||||
editVersion,
|
||||
onSuccess,
|
||||
}: UseContentBaseInfoProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isBaseMoreDisabled, setIsBaseMoreDisabled] = useState(true);
|
||||
|
||||
// 基本信息
|
||||
// Basic information
|
||||
const { baseInfoNode, submitBaseInfo } = useBaseMore({
|
||||
pluginId: plugin_id || '',
|
||||
pluginMeta: pluginInfo?.meta_info || {},
|
||||
@@ -101,7 +101,7 @@ export const useContentBaseMore = ({
|
||||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitBaseInfo();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
}
|
||||
|
||||
@@ -48,12 +48,12 @@ export const useContentBaseInfo = ({
|
||||
editVersion,
|
||||
renderDescComponent,
|
||||
}: UseContentBaseInfoProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isBaseInfoDisabled, setIsBaseInfoDisabled] = useState(true);
|
||||
|
||||
// 基本信息
|
||||
// Basic information
|
||||
const { baseInfoNode, submitBaseInfo } = useBaseInfo({
|
||||
pluginId: plugin_id || '',
|
||||
apiId: tool_id,
|
||||
@@ -93,7 +93,7 @@ export const useContentBaseInfo = ({
|
||||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitBaseInfo();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export const useContentDebug = ({
|
||||
debugApiInfo && tool_id ? (
|
||||
<Debug
|
||||
pluginType={pluginInfo?.plugin_type}
|
||||
disabled={false} // 是否可调试
|
||||
disabled={false} // Is it debuggable?
|
||||
setDebugStatus={setDebugStatus}
|
||||
pluginId={String(plugin_id)}
|
||||
apiId={String(tool_id)}
|
||||
@@ -113,7 +113,7 @@ export const useContentDebug = ({
|
||||
>
|
||||
<Debug
|
||||
pluginType={pluginInfo?.plugin_type}
|
||||
disabled={false} // 是否可调试
|
||||
disabled={false} // Is it debuggable?
|
||||
setDebugStatus={setDebugStatus}
|
||||
pluginId={String(plugin_id)}
|
||||
apiId={String(tool_id)}
|
||||
|
||||
@@ -58,11 +58,11 @@ export const useContentRequest = ({
|
||||
onSuccess,
|
||||
renderParamsComponent,
|
||||
}: UseContentRequestProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isRequestParamsDisabled, setIsRequestParamsDisabled] = useState(true);
|
||||
// 设置请求参数
|
||||
// Set request parameters
|
||||
const { requestParamsNode, submitRequestParams, nlTool } = useRequestParams({
|
||||
apiInfo,
|
||||
pluginId: plugin_id || '',
|
||||
@@ -107,7 +107,7 @@ export const useContentRequest = ({
|
||||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitRequestParams();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
setIsRequestParamsDisabled(true);
|
||||
|
||||
@@ -66,12 +66,12 @@ export const useContentResponse = ({
|
||||
onSuccess,
|
||||
renderParamsComponent,
|
||||
}: UseContentResponseProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isResponseParamsDisabled, setIsResponseParamsDisabled] =
|
||||
useState(true);
|
||||
// 第三步,设置相应参数的hooks组件
|
||||
// The third step is to set the corresponding parameters of the hooks component
|
||||
const { responseParamsNode, submitResponseParams, extra } = useResponseParams(
|
||||
{
|
||||
apiInfo,
|
||||
@@ -94,7 +94,7 @@ export const useContentResponse = ({
|
||||
},
|
||||
);
|
||||
|
||||
// 处理 debug 时 example数据先显示后隐藏的问题
|
||||
// When dealing with debugging, the example data is displayed first and then hidden
|
||||
useEffect(() => {
|
||||
if (!isResponseParamsDisabled) {
|
||||
setDebugApiInfo({
|
||||
@@ -133,7 +133,7 @@ export const useContentResponse = ({
|
||||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitResponseParams();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
setIsResponseParamsDisabled(true);
|
||||
|
||||
@@ -78,8 +78,8 @@ const useAuthForApiTool = () => {
|
||||
|
||||
return {
|
||||
canEdit,
|
||||
needAuth, // 需要 auth 授权
|
||||
isHasAuth, // 是否完成了授权
|
||||
needAuth, // Requires auth authorization
|
||||
isHasAuth, // Has the authorization been completed?
|
||||
doCancelOauth,
|
||||
isUpdateLoading,
|
||||
doOauth,
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
& svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
/* stylelint-disable-next-line declaration-no-important -- 覆盖icon颜色 */
|
||||
/* stylelint-disable-next-line declaration-no-important -- Override icon color */
|
||||
color: var(--semi-color-text-2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ enum PageSource {
|
||||
}
|
||||
|
||||
enum PageMode {
|
||||
/** 整页 UI类似全覆盖浮层 */
|
||||
/** Full page UI similar to full coverage floating layer */
|
||||
FULL_PAGE = 'full_page',
|
||||
/** 嵌入(左侧有菜单栏) */
|
||||
/** Embed (with menu bar on the left) */
|
||||
EMBED = 'embed',
|
||||
}
|
||||
|
||||
@@ -87,16 +87,16 @@ const MockSetDetail: FC<{
|
||||
[],
|
||||
);
|
||||
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
|
||||
// API 详情
|
||||
// API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>({
|
||||
name: routeResponse?.toolName,
|
||||
});
|
||||
// mock set 详情
|
||||
// Mock set details
|
||||
const [mockSetInfo, setMockSetInfo] = useState<MockSet>({
|
||||
id: mocksetID,
|
||||
name: routeResponse?.mockSetName,
|
||||
});
|
||||
// API 对应 schema
|
||||
// API correspondence schema
|
||||
const [toolSchema, setToolSchema] = useState<string>('');
|
||||
const [perm, setPerm] = useState<{
|
||||
readOnly: boolean;
|
||||
@@ -109,9 +109,9 @@ const MockSetDetail: FC<{
|
||||
const listRef = useRef<MockDataListActions>(null);
|
||||
const contentEleRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 页面展示模式
|
||||
// page display mode
|
||||
const pageMode = params.hideMenu ? PageMode.FULL_PAGE : PageMode.EMBED;
|
||||
// 页面来源
|
||||
// page source
|
||||
const fromSource = routeResponse?.fromSource
|
||||
? (routeResponse.fromSource as PageSource)
|
||||
: PageSource.FROM_MOCK_SET;
|
||||
@@ -142,7 +142,7 @@ const MockSetDetail: FC<{
|
||||
[toolID, pluginID],
|
||||
);
|
||||
|
||||
// 获取当前 tool 信息
|
||||
// Get current tool information
|
||||
const getPluginToolInfo = async () => {
|
||||
try {
|
||||
const { api_info = [] } = await PluginDevelopApi.GetPluginAPIs(
|
||||
@@ -164,7 +164,7 @@ const MockSetDetail: FC<{
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前 mock set 信息
|
||||
// Get current mock set information
|
||||
const getMockSetInfo = async () => {
|
||||
if (!mocksetID) {
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,7 @@ import { getDisplayCols } from './get-col';
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface ListParams {
|
||||
pageNo?: number; // 用于前端计算数量
|
||||
pageNo?: number; // Quantity for front-end computing
|
||||
pageSize?: number;
|
||||
pageToken?: string;
|
||||
order?: {
|
||||
@@ -80,13 +80,13 @@ const TOOL_NOT_FOUND_CODE = '600303108';
|
||||
const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
const resourceNavigate = usePluginNavigate();
|
||||
|
||||
// user信息
|
||||
// User information
|
||||
const userInfo = userStoreService.useUserInfo();
|
||||
|
||||
// 路由信息
|
||||
// routing information
|
||||
|
||||
const [params, setParams] = useState<ListParams>({
|
||||
//请求参数
|
||||
//request parameters
|
||||
pageSize: PAGE_SIZE,
|
||||
pageNo: 1,
|
||||
});
|
||||
@@ -101,11 +101,11 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
})),
|
||||
);
|
||||
|
||||
// space信息
|
||||
// Space information
|
||||
const space = useSpace(spaceID);
|
||||
const isPersonal = space?.space_type === SpaceType.Personal;
|
||||
|
||||
// API 详情
|
||||
// API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>();
|
||||
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
@@ -118,7 +118,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
|
||||
const [editDisabled, setEditDisabled] = useState(false);
|
||||
|
||||
// 后端需要的mock上下文信息
|
||||
// The mock context information required by the backend
|
||||
const ctxInfo = {
|
||||
bizCtx: {
|
||||
trafficScene: TrafficScene.Undefined,
|
||||
@@ -216,7 +216,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前tool信息
|
||||
// Get current tool information
|
||||
const getPluginToolInfo = async () => {
|
||||
try {
|
||||
const { api_info = [] } = await PluginDevelopApi.GetPluginAPIs({
|
||||
@@ -351,13 +351,13 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
if (!editDisabled) {
|
||||
handleEdit(record);
|
||||
}
|
||||
}, // 点击行
|
||||
}, // Click line
|
||||
}),
|
||||
onChange: e => {
|
||||
if (e.sorter?.sortOrder) {
|
||||
tableRef.current?.reset();
|
||||
|
||||
//时间排序
|
||||
//chronological sorting
|
||||
setParams(p => ({
|
||||
...p,
|
||||
pageSize: PAGE_SIZE,
|
||||
@@ -410,7 +410,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
></MockSetEditModal>
|
||||
) : null}
|
||||
{
|
||||
// 删除弹窗
|
||||
// Delete pop-up window
|
||||
deleteMockSet ? (
|
||||
<MockSetDeleteModal
|
||||
visible={!!deleteMockSet}
|
||||
|
||||
@@ -35,8 +35,8 @@ interface UseCreateToolProps {
|
||||
plugin_id: string;
|
||||
onClickWrapper?: (fn: () => void) => () => Promise<void>;
|
||||
/**
|
||||
* 点击创建工具按钮前的回调函数
|
||||
* @returns {boolean | void} 返回false时将阻止后续动作
|
||||
* The callback function before clicking the Create Tool button
|
||||
* @Returns {boolean | void} returns false to block subsequent actions
|
||||
*/
|
||||
onBeforeClick?: () => void;
|
||||
disabled: boolean;
|
||||
@@ -151,7 +151,7 @@ export const useCreateTool = ({
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 创建工具
|
||||
* @description creation tool
|
||||
*/
|
||||
export const CreateTool: FC<CreateToolProps> = props => {
|
||||
const { content } = useCreateTool({
|
||||
|
||||
@@ -155,7 +155,7 @@ const PluginDetailPage = ({
|
||||
);
|
||||
|
||||
const [params, setParams] = useState<GetPluginAPIsRequest>({
|
||||
//请求参数
|
||||
//request parameters
|
||||
page: 1,
|
||||
size: 10,
|
||||
plugin_id: pluginID,
|
||||
@@ -236,7 +236,7 @@ const PluginDetailPage = ({
|
||||
|
||||
const dataSource = data?.api_info;
|
||||
|
||||
/** 不再提示 */
|
||||
/** no longer prompt */
|
||||
const noTips = async () => {
|
||||
const res = await PluginDevelopApi.NoUpdatedPrompt({
|
||||
plugin_id: pluginID,
|
||||
@@ -248,7 +248,7 @@ const PluginDetailPage = ({
|
||||
|
||||
const checkPublish = async () => {
|
||||
if (!pluginInfo?.published) {
|
||||
//未发布过点击直接发布
|
||||
//It has not been published. Click to publish directly.
|
||||
setPublishPopShow(true);
|
||||
return;
|
||||
}
|
||||
@@ -264,7 +264,7 @@ const PluginDetailPage = ({
|
||||
setPublishPopData(res);
|
||||
setShowPublishCheckPop(true);
|
||||
} else {
|
||||
//没有修改api直接发布
|
||||
//Publish directly without modifying the api
|
||||
setPublishPopShow(true);
|
||||
}
|
||||
};
|
||||
@@ -308,14 +308,14 @@ const PluginDetailPage = ({
|
||||
onStatusChange?.('error');
|
||||
}
|
||||
}, [initSuccessed]);
|
||||
// 区分ide的跳转
|
||||
// Differentiate IDE jumps
|
||||
const handleIdeJump = (
|
||||
initialAction = InitialAction.DEFAULT,
|
||||
toolId = '',
|
||||
) => {
|
||||
// ide 逻辑
|
||||
// IDE logic
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({ initialAction, toolId });
|
||||
} else if (toolId) {
|
||||
resourceNavigate.tool?.(toolId);
|
||||
@@ -337,7 +337,7 @@ const PluginDetailPage = ({
|
||||
canEdit ? { mode: 'preview' } : {},
|
||||
);
|
||||
}
|
||||
}, // 点击行
|
||||
}, // Click line
|
||||
});
|
||||
|
||||
const { exampleNode, openExample } = useEditExample({
|
||||
@@ -445,7 +445,7 @@ const PluginDetailPage = ({
|
||||
) : null}
|
||||
|
||||
<Layout.Content className={s['layout-content']}>
|
||||
{/* 已发布且有更新展示 */}
|
||||
{/* Published and updated */}
|
||||
{pluginInfo?.status &&
|
||||
pluginInfo?.published &&
|
||||
canEdit &&
|
||||
@@ -470,7 +470,7 @@ const PluginDetailPage = ({
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{/* plugin简介 */}
|
||||
{/* Plugin Introduction */}
|
||||
{pluginInfo ? (
|
||||
<PluginHeader
|
||||
pluginInfo={pluginInfo}
|
||||
@@ -502,7 +502,7 @@ const PluginDetailPage = ({
|
||||
onBeforeClick={() => {
|
||||
setShowDropDownItem(undefined);
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({
|
||||
initialAction: InitialAction.CREATE_TOOL,
|
||||
toolId: '',
|
||||
@@ -529,7 +529,7 @@ const PluginDetailPage = ({
|
||||
{I18n.t('import')}
|
||||
</Button>
|
||||
) : null}
|
||||
{/* ! 发布按钮 */}
|
||||
{/* ! Post button */}
|
||||
{isRenderIDEPublishButton ? (
|
||||
<Tooltip
|
||||
position="left"
|
||||
@@ -598,7 +598,7 @@ const PluginDetailPage = ({
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{/* 工具列表表格 */}
|
||||
{/* Tool List Form */}
|
||||
{!!dataSource?.length && (
|
||||
<div className="mb-[24px] mt-[36px] text-[18px] weight-[600]">
|
||||
{I18n.t('plugin_api_list_table_name')}
|
||||
@@ -615,7 +615,7 @@ const PluginDetailPage = ({
|
||||
onRow,
|
||||
onChange: e => {
|
||||
if (e.sorter?.sortOrder) {
|
||||
//时间排序
|
||||
//chronological sorting
|
||||
setParams(p => ({
|
||||
...p,
|
||||
page: 1,
|
||||
@@ -634,7 +634,7 @@ const PluginDetailPage = ({
|
||||
btnText: canEdit ? createToolText : undefined,
|
||||
btnOnClick: () => {
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({
|
||||
initialAction: InitialAction.CREATE_TOOL,
|
||||
toolId: '',
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface PluginModalContentProps extends PluginModalModeProps {
|
||||
setQuery: (value: Partial<PluginQuery>, refreshPage?: boolean) => void;
|
||||
}
|
||||
export type PluginModalContentListItem = PluginInfoForPlayground & {
|
||||
// 当前数据属于列表的第几页
|
||||
// The current data belongs to the page of the list
|
||||
belong_page?: number;
|
||||
};
|
||||
|
||||
@@ -99,7 +99,7 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
||||
onCopyPluginCallback,
|
||||
clickProjectPluginCallback,
|
||||
}) => {
|
||||
// 状态hook
|
||||
// Status hook
|
||||
const {
|
||||
type,
|
||||
mineActive,
|
||||
@@ -112,9 +112,9 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
||||
pluginType,
|
||||
} = query;
|
||||
const id = useSpaceStore(store => store.space.id);
|
||||
// scroll的container
|
||||
// Scroll container
|
||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
// 当前active的key
|
||||
// Currently active key
|
||||
const [activeKey, setActivekey] = useState<string | string[] | undefined>([]);
|
||||
const refInfiniteScroll = useRef<InfiniteListRef>(null);
|
||||
const {
|
||||
@@ -140,10 +140,10 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
||||
nodes: state.nodes,
|
||||
})),
|
||||
);
|
||||
// 首次effect不执行,这个是切换状态的effect
|
||||
// The first effect is not executed, this is the effect of switching the state
|
||||
useUpdateEffect(() => {
|
||||
scroll2Top(); // 当筛选项改变时,回到顶部
|
||||
// 只要是query中非page改变,就执行此effect
|
||||
scroll2Top(); // When the filter item changes, return to the top
|
||||
// Perform this effect whenever a non-page change is made in the query
|
||||
}, []);
|
||||
return (
|
||||
<UICompositionModalMain>
|
||||
|
||||
@@ -53,24 +53,24 @@ export interface UsePluginModalPartsProp extends PluginModalModeProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取初始化类型
|
||||
* @param from 来源
|
||||
* @param spaceType 空间类型
|
||||
* @returns 初始化类型
|
||||
* Get initialization type
|
||||
* @Param from source
|
||||
* @param spaceType
|
||||
* @Returns initialization type
|
||||
*/
|
||||
const getInitType = (from?: From, spaceType?: SpaceType) => {
|
||||
// 项目workflow引用插件,默认选中项目插件
|
||||
// Project workflow reference plug-in, the project plug-in is selected by default
|
||||
if (from === From.ProjectWorkflow) {
|
||||
return '';
|
||||
}
|
||||
if (from !== From.ProjectIde || !spaceType || !from) {
|
||||
return '';
|
||||
}
|
||||
// projectIDE下,并且是个人空间,选中Mine
|
||||
// Under projectIDE, and it is personal space, select Mine.
|
||||
if (spaceType === SpaceType.Personal) {
|
||||
return PluginFilterType.Mine;
|
||||
}
|
||||
// projectIDE下,并且是团队空间,选中Team
|
||||
// Under projectIDE, and is a team space, select Team
|
||||
if (spaceType === SpaceType.Team && from === From.ProjectIde) {
|
||||
return PluginFilterType.Team;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export const usePluginModalParts = ({
|
||||
hideCreateBtn,
|
||||
initQuery,
|
||||
}: UsePluginModalPartsProp) => {
|
||||
// 获取devId
|
||||
// Get devId
|
||||
const userInfo = userStoreService.useUserInfo();
|
||||
const spaceType = useSpaceStore(store => store.space.space_type);
|
||||
const [query, setQuery] = useState<PluginQuery>({
|
||||
@@ -103,14 +103,14 @@ export const usePluginModalParts = ({
|
||||
devId: userInfo?.user_id_str || '',
|
||||
search: '',
|
||||
page: DEFAULT_PAGE,
|
||||
// 项目IDE插件仅展示我的插件
|
||||
// Project IDE plugins only show my plugins
|
||||
type: initQuery?.type ?? getInitType(from, spaceType),
|
||||
orderBy: OrderBy.CreateTime,
|
||||
orderByPublic: SortType.Heat,
|
||||
orderByFavorite: SortType.Newest,
|
||||
mineActive: MineActiveEnum.All,
|
||||
isOfficial: initQuery?.isOfficial ?? undefined,
|
||||
// project workflow添加插件,只展示云插件
|
||||
// Add plugins to project workflow, only show cloud plugins
|
||||
pluginType:
|
||||
from === From.ProjectWorkflow ? PluginType.CLoudPlugin : undefined,
|
||||
});
|
||||
|
||||
@@ -85,11 +85,11 @@ export const PluginModalSider: FC<PluginModalSiderProp> = ({
|
||||
maxLength={MAX_SEARCH_LENGTH}
|
||||
onSearch={search => {
|
||||
if (!search) {
|
||||
// 如果search清空了,那么立即更新query
|
||||
// If the search is empty, update the query immediately
|
||||
cancel();
|
||||
updateSearchQuery(search);
|
||||
} else {
|
||||
// 如果search有值,那么防抖更新
|
||||
// If search has a value, then anti-shake update
|
||||
debounceChangeSearch(search);
|
||||
}
|
||||
}}
|
||||
@@ -102,7 +102,7 @@ export const PluginModalSider: FC<PluginModalSiderProp> = ({
|
||||
className={s.addbtn}
|
||||
theme="solid"
|
||||
onClick={() => {
|
||||
// TODO: 其他场景应该也统一创建方式,如果创建成功回调存在,则打开插件modal,否则打开新tab
|
||||
// TODO: Other scenes should also be created in a unified way. If the creation success callback exists, open the plugin modal, otherwise open a new tab.
|
||||
if (
|
||||
onCreateSuccess &&
|
||||
(from === From.ProjectIde || from === From.ProjectWorkflow)
|
||||
|
||||
@@ -169,7 +169,7 @@ export function useInfiniteScrollCacheLoad<
|
||||
] = true;
|
||||
});
|
||||
|
||||
//数据去重
|
||||
//Data deduplicated
|
||||
const uniqList = (list || []).filter(item => {
|
||||
const pluginId = (item as unknown as { pluginInfo: { id: string } })
|
||||
?.pluginInfo?.id;
|
||||
|
||||
@@ -61,9 +61,9 @@ export const CreateCodePluginModal: React.FC<CreatePluginProps> = props => {
|
||||
const [openApi, setOpenApi] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
/** 每次打开重置弹窗数据 */
|
||||
/** Reset pop-up data every time you open it */
|
||||
if (visible) {
|
||||
//格式化json
|
||||
//Format json
|
||||
const desc = JSON.stringify(
|
||||
safeJSONParse(editInfo?.code_info?.plugin_desc),
|
||||
null,
|
||||
|
||||
@@ -114,7 +114,7 @@ export const CreateFormPluginModal: FC<CreatePluginFormProps> = props => {
|
||||
return;
|
||||
}
|
||||
if (visible) {
|
||||
// 显示后滚动条滑动到最上边
|
||||
// Scroll bar after display to top
|
||||
const modalContent = document.querySelector(
|
||||
'.create-plugin-modal-content .semi-modal-body',
|
||||
);
|
||||
@@ -122,7 +122,7 @@ export const CreateFormPluginModal: FC<CreatePluginFormProps> = props => {
|
||||
modalContent.scrollTop = 0;
|
||||
}
|
||||
} else {
|
||||
// 隐藏后重置表单
|
||||
// Reset form after hiding
|
||||
formApi?.current?.reset();
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
@@ -167,7 +167,7 @@ export const FileUpload = ({ onUpload, disabled }: FileUploadProps) => {
|
||||
onChange={({ fileList: list }) => {
|
||||
setFileList(list);
|
||||
if (!list.length) {
|
||||
// 清空content
|
||||
// Clear content
|
||||
onUpload();
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -121,7 +121,7 @@ export const ImportPluginModalContent: React.FC<
|
||||
__disableErrorToast: true,
|
||||
});
|
||||
|
||||
// 解析string
|
||||
// Parse string
|
||||
const result = parsePluginInfo({
|
||||
aiPlugin: ai_plugin,
|
||||
openAPI: openapi,
|
||||
|
||||
@@ -146,17 +146,17 @@ const HeaderList = ({
|
||||
value?: commonParamSchema[];
|
||||
onChange?: (val?: commonParamSchema[]) => void;
|
||||
}) => {
|
||||
/** 添加header */
|
||||
/** Add header */
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const addHeader = data => {
|
||||
const h = [...headerList];
|
||||
h.push(data.name ? data : { name: '', value: '' });
|
||||
setHeaderList?.(h);
|
||||
};
|
||||
/** 删除header */
|
||||
/** Delete header */
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const deleteHeader = index => {
|
||||
// 若为最后一个header,则只清空内容,不删除
|
||||
// If it is the last header, only empty the content, not delete it
|
||||
const filterList = cloneDeep(headerList);
|
||||
filterList.splice(index, 1);
|
||||
setHeaderList?.(filterList);
|
||||
@@ -401,7 +401,7 @@ export const ServiceField = ({ disabled }: PluginInfoFormFieldProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
// extItems 动态下发
|
||||
// extItems dynamic delivery
|
||||
export const ExtItems = ({
|
||||
disabled,
|
||||
extItems,
|
||||
@@ -410,7 +410,7 @@ export const ExtItems = ({
|
||||
const formValues = formApi.getValues();
|
||||
return (
|
||||
<>
|
||||
{/* 服务端动态返回授权项 */}
|
||||
{/* Server level dynamic return authorization */}
|
||||
{extItems?.map(item => (
|
||||
<>
|
||||
{disabled ? (
|
||||
|
||||
@@ -77,8 +77,8 @@ const INITIAL_FORM_VALUES = {
|
||||
};
|
||||
|
||||
/**
|
||||
文件导入plugin确认信息弹窗,目前和普通创建导入很像,调用接口不一样,
|
||||
目前感觉这个确认形式不太友好,后续不太确定优化形态,所以新建单独文件处理,以防污染bot-form-edit
|
||||
File import plugin confirmation information pop-up window, currently very similar to ordinary creation and import, the call interface is different.
|
||||
At present, I feel that this confirmation form is not very friendly, and I am not sure about the optimization form in the future, so a new separate file is created to prevent contamination of bot-form-edit.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
@@ -93,7 +93,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
|
||||
} = props;
|
||||
|
||||
const [authOption, setAuthOption] = useState<AuthOption[]>([]);
|
||||
// 合规审核结果
|
||||
// Compliance audit results
|
||||
const [isValidCheckResult, setIsValidCheckResult] = useState(true);
|
||||
|
||||
const [extItems, setExtItems] = useState<OauthTccOpt[]>([]);
|
||||
@@ -121,7 +121,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
|
||||
|
||||
useEffect(() => {
|
||||
if (importInfo) {
|
||||
//更新插件
|
||||
//update plugin
|
||||
setExtItems(
|
||||
findAuthTypeItem(
|
||||
authOption,
|
||||
@@ -279,7 +279,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
|
||||
>
|
||||
{({ values }) => (
|
||||
<>
|
||||
{/* 插件头像 */}
|
||||
{/* plugin avatar */}
|
||||
<PictureUpload
|
||||
noLabel
|
||||
disabled={disabled}
|
||||
@@ -288,13 +288,13 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
|
||||
iconType={IconType.Plugin}
|
||||
fileBizType={FileBizType.BIZ_PLUGIN_ICON}
|
||||
/>
|
||||
{/* 插件名称/插件描述/插件URL */}
|
||||
{/* Plugin Name/Plugin Description/Plugin URL */}
|
||||
<PluginNameField disabled={disabled} />
|
||||
<PluginDescField disabled={disabled} />
|
||||
<PluginUrlField disabled={true} />
|
||||
{/* 插件Header */}
|
||||
{/* Plugin Header */}
|
||||
<HeaderListField disabled={disabled} />
|
||||
{/* 授权方式 */}
|
||||
{/* Authorization method */}
|
||||
<AuthTypeField
|
||||
disabled={disabled}
|
||||
authOption={authOption}
|
||||
@@ -304,12 +304,12 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{/* 授权方式-Service */}
|
||||
{/* Authorization method-Service */}
|
||||
{values.auth_type.at(-1) === 1 && (
|
||||
<ServiceField disabled={disabled} />
|
||||
)}
|
||||
<ExtItems disabled={disabled} extItems={extItems} />
|
||||
{/* 协议 */}
|
||||
{/* agreement */}
|
||||
{!disabled && (
|
||||
<Space spacing={8} className={s['footer-draft']}>
|
||||
<IconInfoCircle
|
||||
|
||||
@@ -31,7 +31,7 @@ export const formRuleList = {
|
||||
message: I18n.t('create_plugin_modal_nameerror'),
|
||||
}
|
||||
: {
|
||||
pattern: /^[\w\s\u4e00-\u9fa5]+$/u, // 国内增加支持中文
|
||||
pattern: /^[\w\s\u4e00-\u9fa5]+$/u, // Increased domestic support for Chinese
|
||||
message: I18n.t('create_plugin_modal_nameerror_cn'),
|
||||
},
|
||||
],
|
||||
@@ -95,7 +95,7 @@ export interface AuthOption {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any
|
||||
[key: string]: any;
|
||||
}
|
||||
/** 递归寻找auth选项下的输入项 */
|
||||
/** Recursively find the input under the auth option */
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
export const findAuthTypeItem = (data: AuthOption[], targetKey = 0) => {
|
||||
for (const item of data) {
|
||||
|
||||
@@ -120,7 +120,7 @@ export async function getContent(file: Blob, onProgress): Promise<string> {
|
||||
}
|
||||
|
||||
export function isValidURL(str?: string): boolean {
|
||||
// 缩略版
|
||||
// abbreviated version
|
||||
try {
|
||||
const objExp = new RegExp(
|
||||
'^(https?:\\/\\/)?' + // protocol
|
||||
@@ -137,7 +137,7 @@ export function isValidURL(str?: string): boolean {
|
||||
}
|
||||
|
||||
export async function customService(url: string) {
|
||||
// 这里需要自定义请求,需要引入axios
|
||||
// Custom requests are required here, and axios needs to be introduced.
|
||||
const axiosInstance = axios.create({ responseType: 'text' });
|
||||
|
||||
const response = await axiosInstance.get(url);
|
||||
|
||||
@@ -249,8 +249,8 @@ describe('useMockSetInSettingModalController', () => {
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.isEnabled).toBeFalsy(); // 初始状态应该是不启用
|
||||
expect(result.current.mockSetData).toEqual([]); // 初始mockSetData应该是空数组
|
||||
expect(result.current.isEnabled).toBeFalsy(); // The initial state should be not enabled
|
||||
expect(result.current.mockSetData).toEqual([]); // The initial mockSetData should be an empty array
|
||||
});
|
||||
|
||||
it('should act export action', async () => {
|
||||
@@ -260,25 +260,25 @@ describe('useMockSetInSettingModalController', () => {
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.isEnabled).toBeTruthy(); // 有选中的mock数据的前提下,会自动启用
|
||||
expect(result.current.mockSetData.length).toEqual(7); // mockSetData 数据是 7
|
||||
expect(result.current.isEnabled).toBeTruthy(); // If there is selected mock data, it will be automatically enabled
|
||||
expect(result.current.mockSetData.length).toEqual(7); // mockSetData is 7.
|
||||
|
||||
act(() => result.current.doSetCreateModal(true));
|
||||
expect(result.current.showCreateModal).toBeTruthy(); // 打开创建modal
|
||||
expect(result.current.showCreateModal).toBeTruthy(); // Open Create modal
|
||||
|
||||
act(() => result.current.doHandleView({ id: 'record-id' })); // 点击查看
|
||||
act(() => result.current.doHandleView({ id: 'record-id' })); // Click to view
|
||||
|
||||
act(() => result.current.doEnabled()); // 关闭
|
||||
expect(result.current.isEnabled).toBeFalsy(); // 禁用
|
||||
act(() => result.current.doEnabled()); // close
|
||||
expect(result.current.isEnabled).toBeFalsy(); // disable
|
||||
|
||||
act(() => result.current.doSetDeleteId('record-id')); // 删除
|
||||
act(() => result.current.doSetDeleteId('record-id')); // delete
|
||||
expect(result.current.deleteRenderTitle).toBe(
|
||||
'Translated: delete_the_mockset {}',
|
||||
); // 删除后应该显示删除的title
|
||||
); // The deleted title should be displayed after deletion.
|
||||
|
||||
act(() => result.current.doConfirmDelete()); // 确认删除
|
||||
act(() => result.current.doConfirmDelete()); // Confirm deletion
|
||||
|
||||
act(() => result.current.doChangeMock({ id: 'change-mock' })); // 修改mock
|
||||
expect(result.current.selectedMockSet).toStrictEqual({ id: 'change-mock' }); // 修改mock后应该显示新的mock
|
||||
act(() => result.current.doChangeMock({ id: 'change-mock' })); // Modify mock
|
||||
expect(result.current.selectedMockSet).toStrictEqual({ id: 'change-mock' }); // After modifying the mock, the new mock should be displayed.
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('useSaveMockData', () => {
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSaveMockData({
|
||||
mockSetId: undefined, // 测试没有mockSetId的情况
|
||||
mockSetId: undefined, // Test without mockSetId
|
||||
basicParams: {
|
||||
environment: 'environment',
|
||||
workspace_id: 'workspace_id',
|
||||
|
||||
@@ -53,8 +53,8 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
||||
},
|
||||
ParamsTypeDefine: {},
|
||||
PluginMockDataGenerateMode: {
|
||||
MANUAL: 0, // 手动创建
|
||||
RANDOM: 1, // 随机生成
|
||||
MANUAL: 0, // create manually
|
||||
RANDOM: 1, // random generation
|
||||
LLM: 2,
|
||||
},
|
||||
}));
|
||||
@@ -62,21 +62,21 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
||||
vi.mock('@coze-arch/bot-hooks', () => ({
|
||||
SceneType: {
|
||||
BOT__VIEW__WORKFLOW: 'botViewWorkflow',
|
||||
/** bot 详情页查看 workflow,或新建 workflow 但未发布,点击返回 */
|
||||
/** View the workflow on the bot details page, or create a new workflow but not published, click Return */
|
||||
WORKFLOW__BACK__BOT: 'workflowBackBot',
|
||||
/** bot 详情页创建 workflow,在 workflow 发布后返回 */
|
||||
/** The bot details page creates a workflow and returns it after the workflow is published */
|
||||
WORKFLOW_PUBLISHED__BACK__BOT: 'workflowPublishedBackBot',
|
||||
/** bot 详情页进入 mock data 页面 */
|
||||
/** Bot details page Enter the mock data page */
|
||||
BOT__TO__PLUGIN_MOCK_DATA: 'botToPluginMockData',
|
||||
/** workflow 详情页进入 mock data 页面 */
|
||||
/** Workflow details page Enter the mock data page */
|
||||
WORKFLOW__TO__PLUGIN_MOCK_DATA: 'workflowToPluginMockData',
|
||||
/** mock set 页进入 mock data 页面 */
|
||||
/** Mock set page Enter the mock data page */
|
||||
PLUGIN_MOCK_SET__TO__PLUGIN_MOCK_DATA: 'pluginMockSetToPluginMockData',
|
||||
/** bot 详情页进入 knowledge 页面 */
|
||||
/** Bot details page Enter the knowledge page */
|
||||
BOT__VIEW__KNOWLEDGE: 'botViewKnowledge',
|
||||
/** knowledge 页面点击退出返回 bot 详情页(未点击添加) */
|
||||
/** Knowledge page Click Exit to return to bot details page (not clicked Add) */
|
||||
KNOWLEDGE__BACK__BOT: 'knowledgeBackBot',
|
||||
/** knowledge 页面点击返回 bot 详情页,并添加到 bot */
|
||||
/** Knowledge page Click to return to bot details page and add to bot */
|
||||
KNOWLEDGE__ADD_TO__BOT: 'knowledgeAddToBot',
|
||||
},
|
||||
usePageJumpService: vi.fn().mockReturnValue({
|
||||
|
||||
@@ -23,7 +23,7 @@ export const REAL_DATA_MOCKSET = {
|
||||
name: I18n.t('real_data'),
|
||||
};
|
||||
|
||||
// 初始化仅有real_data
|
||||
// Initialization only real_data
|
||||
export const MOCK_OPTION_LIST = [REAL_DATA_MOCKSET];
|
||||
|
||||
export const POLLING_INTERVAL = 10000;
|
||||
|
||||
@@ -146,7 +146,7 @@ export const useInitialGetEnabledMockSet = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 取消
|
||||
// cancel
|
||||
const cancel = () => {
|
||||
pollingTurnRef.current = undefined;
|
||||
cancelReq.current?.();
|
||||
|
||||
@@ -94,11 +94,11 @@
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
/** 创建框 **/
|
||||
/** Create box **/
|
||||
.mock-creation-modal {
|
||||
:global {
|
||||
.semi-modal-content .semi-modal-body {
|
||||
/** 保证内部 tooltip 不被遮盖 **/
|
||||
/** Make sure the internal tooltip is not covered **/
|
||||
overflow: unset
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
}
|
||||
|
||||
div.mock-creation-modal-editor {
|
||||
/** 兼容 modal 在小窗口下 body 高度不生效的问题 */
|
||||
/** Compatible modal body height does not take effect in small windows */
|
||||
height: calc(100vh - 316px);
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ interface MockDataCardProps {
|
||||
bizCtx: infra.BizCtx;
|
||||
}
|
||||
|
||||
/** mock data 展示卡片 */
|
||||
/** Mock data display card */
|
||||
export function MockDataCard({
|
||||
mock,
|
||||
readOnly,
|
||||
|
||||
@@ -55,18 +55,18 @@ import { useSaveMockData } from '../hook/use-save-mock-data';
|
||||
import s from './index.module.less';
|
||||
|
||||
export enum CreationMode {
|
||||
/** 弹窗形式 */
|
||||
/** pop-up window */
|
||||
MODAL = 'modal',
|
||||
/** 嵌入页面 */
|
||||
/** embed page */
|
||||
CARD = 'card',
|
||||
}
|
||||
|
||||
interface MockDataCreateCardProps {
|
||||
mode: CreationMode;
|
||||
mockInfo?: MockDataInfo;
|
||||
// mode 为 modal 时生效
|
||||
// Effective when modal mode
|
||||
visible?: boolean;
|
||||
// mode 为 modal 时生效
|
||||
// Effective when modal mode
|
||||
onCancel?: () => void;
|
||||
onSuccess: (data?: mockset.MockRule[]) => void;
|
||||
bizCtx: infra.BizCtx;
|
||||
@@ -76,7 +76,7 @@ interface MockDataCreateCardProps {
|
||||
};
|
||||
}
|
||||
|
||||
/** 创建or编辑 mock data - */
|
||||
/** Create or edit mock data - */
|
||||
export function MockDataCreateCard({
|
||||
mode,
|
||||
mockInfo,
|
||||
@@ -96,7 +96,7 @@ export function MockDataCreateCard({
|
||||
useTransSchema(schema);
|
||||
const { mock_set_id, tool_id } = useParams<DynamicParams>();
|
||||
|
||||
// space信息
|
||||
// Space information
|
||||
const spaceType = useSpaceStore(store => store.space.space_type);
|
||||
const isPersonal = spaceType === SpaceType.Personal;
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ export const MockDataList = forwardRef(
|
||||
const [deleteModalVisible, setDeleteModalVisible] =
|
||||
useState<boolean>(false);
|
||||
const [deleting, setDeleting] = useState<boolean>(false);
|
||||
// 当前选中状态
|
||||
// Currently selected
|
||||
const [currentSelect, setCurrentSelect] = useState<
|
||||
MockDataInfo | undefined
|
||||
>();
|
||||
@@ -99,7 +99,7 @@ export const MockDataList = forwardRef(
|
||||
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
|
||||
|
||||
const { mock_set_id, space_id, tool_id } = useParams<DynamicParams>();
|
||||
// space信息
|
||||
// Space information
|
||||
const spaceType = useSpaceStore(store => store.space.space_type);
|
||||
const isPersonal = spaceType === SpaceType.Personal;
|
||||
|
||||
@@ -113,7 +113,7 @@ export const MockDataList = forwardRef(
|
||||
setDeleteModalVisible(true);
|
||||
};
|
||||
|
||||
// 获取当前 mock set 下的 mock data
|
||||
// Get the mock data under the current mock set
|
||||
const getMockData = async (needScrollToTop?: boolean) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -181,11 +181,11 @@ export const MockDataList = forwardRef(
|
||||
}
|
||||
};
|
||||
|
||||
// 前端更新
|
||||
// frontend update
|
||||
const updateList = (data: MockRule, action: RuleActions) => {
|
||||
let len = 0;
|
||||
if (action === RuleActions.CREATE) {
|
||||
// 创建场景直接 force update
|
||||
// Create scenes to force updates directly
|
||||
getMockData(true);
|
||||
} else if (action === RuleActions.DELETE) {
|
||||
len = mockDataList.length - 1;
|
||||
@@ -228,7 +228,7 @@ export const MockDataList = forwardRef(
|
||||
|
||||
useEffect(() => {
|
||||
if (routeResponse?.generationMode) {
|
||||
// 清除跳转参数
|
||||
// Clear jump parameters
|
||||
const state = {
|
||||
...history.state,
|
||||
usr: { ...(history.state.usr || {}), generationMode: undefined },
|
||||
|
||||
@@ -42,12 +42,12 @@ export function MockSetPageBreadcrumb({
|
||||
}: MockSetPageBreadcrumbProps) {
|
||||
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
|
||||
|
||||
// 插件详情
|
||||
// plugin details
|
||||
const [pluginInfo, setPluginInfo] = useState<PluginMetaInfo>({
|
||||
name: routeResponse?.pluginName,
|
||||
});
|
||||
|
||||
// 获取当前 plugin 信息
|
||||
// Get current plugin information
|
||||
const getPluginInfo = async () => {
|
||||
try {
|
||||
const res = await DeveloperApi.GetPluginInfo(
|
||||
|
||||
@@ -162,7 +162,7 @@ const MockSetSelectComp = (
|
||||
const bizCtx: BizCtx = {
|
||||
...bizSceneCtx,
|
||||
connectorUID: uid,
|
||||
connectorID: CONNECTOR_ID, // 业务线为Coze
|
||||
connectorID: CONNECTOR_ID, // Business line for Coze
|
||||
};
|
||||
|
||||
const { jump } = usePageJumpService();
|
||||
@@ -449,7 +449,7 @@ const MockSetSelectComp = (
|
||||
content={getTooltipInfo()}
|
||||
visible={disabled && focused}
|
||||
position="left"
|
||||
style={{ display: disabled ? 'block' : 'none' }} // visible disabled不生效
|
||||
style={{ display: disabled ? 'block' : 'none' }} // Visible disabled not effective
|
||||
>
|
||||
<div
|
||||
style={style}
|
||||
|
||||
@@ -71,7 +71,7 @@ export const MockSetDeleteModal = ({
|
||||
} = mockSetInfo || {};
|
||||
const [mockSetRefCount, setMockSetRefCount] = useState(-1);
|
||||
|
||||
// space信息
|
||||
// Space information
|
||||
const spaceType = useSpaceStore(s => s.space.space_type);
|
||||
const isPersonal = spaceType === SpaceType.Personal;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export enum BranchType {
|
||||
type BranchInfo = Record<
|
||||
string,
|
||||
| {
|
||||
// 纵向连接线
|
||||
// Longitudinal cable
|
||||
v: BranchType[];
|
||||
isLast: boolean;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ export function useGenTreeBranch(mockData?: MockDataWithStatus) {
|
||||
const [branchInfo, setBranchInfo] = useState<BranchInfo>({});
|
||||
const [pruned, setPruned] = useState<MockDataWithStatus>();
|
||||
|
||||
// 裁剪树枝
|
||||
// Cut branches
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const pruning = (data?: MockDataWithStatus) => {
|
||||
if (!data?.children) {
|
||||
|
||||
@@ -89,7 +89,7 @@ const useMockSetInSettingModalController = ({
|
||||
() => ({
|
||||
...bizSceneCtx,
|
||||
connectorUID: uid,
|
||||
connectorID: CONNECTOR_ID, // 业务线为Coze
|
||||
connectorID: CONNECTOR_ID, // Business line for Coze
|
||||
}),
|
||||
[bizSceneCtx, uid, CONNECTOR_ID],
|
||||
);
|
||||
|
||||
@@ -123,7 +123,7 @@ export function useSaveMockData({
|
||||
}
|
||||
|
||||
if (successRes.length === 0) {
|
||||
// 仅全部失败时认为失败,此时需要 toast 提示
|
||||
// Only if all fail, it is considered a failure, and a toast prompt is required at this time.
|
||||
Toast.error({
|
||||
content: withSlardarIdButton(
|
||||
failRes[0]?.error?.message || I18n.t('error'),
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
|
||||
import { getMergedDataWithStatus } from '../util/utils';
|
||||
|
||||
/** 缓存最新一个解析结果 */
|
||||
/** cache the latest parsing result */
|
||||
const cache: {
|
||||
schema: string;
|
||||
result: MockDataWithStatus | undefined;
|
||||
@@ -92,7 +92,7 @@ export function useTransSchema(schema?: string, currentMock?: string) {
|
||||
}
|
||||
}, [result, currentMock]);
|
||||
|
||||
// 特殊字段需要单独处理:response_for_model 不能为空字符串
|
||||
// Special fields need to be handled separately: response_for_model cannot be an empty string
|
||||
const testValueValid = useCallback(
|
||||
(value: string) => {
|
||||
if (
|
||||
@@ -118,17 +118,17 @@ export function useTransSchema(schema?: string, currentMock?: string) {
|
||||
);
|
||||
|
||||
return {
|
||||
// 由 schema 生成的结构话数据,值为初始值
|
||||
// Structured data generated by schema with initial values
|
||||
result,
|
||||
// 合并模拟数据的结构话数据,全集
|
||||
// Structural session data that merges simulated data, complete set
|
||||
mergedResult,
|
||||
// mergedResult 转换的 object
|
||||
// mergedResult converted object
|
||||
mergedResultExample,
|
||||
// 格式化的数据
|
||||
// formatted data
|
||||
formattedResultExample,
|
||||
// 是否兼容
|
||||
// Is it compatible?
|
||||
incompatible,
|
||||
// 是否合并模拟数据
|
||||
// Whether to merge analog data
|
||||
isInit: currentMock === undefined,
|
||||
testValueValid,
|
||||
};
|
||||
|
||||
@@ -34,23 +34,23 @@ export enum MockDataStatus {
|
||||
export interface MockDataWithStatus {
|
||||
/** key */
|
||||
key: string;
|
||||
/** 字段名称 */
|
||||
/** field name */
|
||||
label: string;
|
||||
/** 字段值 */
|
||||
/** field value */
|
||||
realValue?: string | number | boolean;
|
||||
/** 展示使用 */
|
||||
/** display use */
|
||||
displayValue?: string;
|
||||
/** 描述 */
|
||||
/** describe */
|
||||
description?: string;
|
||||
/** 是否必填 */
|
||||
/** Is it required? */
|
||||
isRequired: boolean;
|
||||
/** 字段数据类型 */
|
||||
/** field data type */
|
||||
type: MockDataValueType;
|
||||
/** for array */
|
||||
childrenType?: MockDataValueType;
|
||||
/** 字段状态 */
|
||||
/** Field Status */
|
||||
status: MockDataStatus;
|
||||
/** 字段子节点 */
|
||||
/** Field sub-node */
|
||||
children?: MockDataWithStatus[];
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export function transUpperCase(str?: string) {
|
||||
return str ? `${str.slice(0, 1).toUpperCase()}${str.slice(1)}` : '';
|
||||
}
|
||||
|
||||
// 仅开发中使用
|
||||
// Only used in development
|
||||
export function sleep(t = 1000) {
|
||||
return new Promise(r => {
|
||||
setTimeout(() => {
|
||||
@@ -46,7 +46,7 @@ export function safeJSONParse<T>(str: string, errCb?: () => T | undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 value 生成 displayValue
|
||||
// Generate displayValue from value
|
||||
function getTargetValue(
|
||||
type: MockDataValueType,
|
||||
value: string | number | boolean | undefined,
|
||||
@@ -58,10 +58,10 @@ function getTargetValue(
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- plugin resp 的类型由用户定义,包含任何可能
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- The type of the plugin resp is user-defined and contains any possible
|
||||
type PluginRespType = any;
|
||||
|
||||
// 合并 schema 和 mock data
|
||||
// Merge schema and mock data
|
||||
export function getMergedDataWithStatus(
|
||||
schemaData?: MockDataWithStatus,
|
||||
currentMock?: string,
|
||||
@@ -84,12 +84,12 @@ export function getMergedDataWithStatus(
|
||||
? safeJSONParse<PluginRespType>(currentMock) || currentMock
|
||||
: currentMock;
|
||||
|
||||
// 将 mock 转换为 MockDataWithStatus 格式
|
||||
// Convert mock to MockDataWithStatus format
|
||||
const processedMock = transMockData2DataWithStatus(ROOT_KEY, mock, {
|
||||
defaultStatus: MockDataStatus.REMOVED,
|
||||
});
|
||||
|
||||
// 合并
|
||||
// merge
|
||||
const { merged, incompatible } = mergeDataWithStatus(
|
||||
schemaData.children,
|
||||
processedMock?.children,
|
||||
@@ -105,7 +105,7 @@ export function getMergedDataWithStatus(
|
||||
};
|
||||
}
|
||||
|
||||
// 解析当前 realValue 所属于的 MockDataValueType
|
||||
// Parse the MockDataValueType to which the current realValue belongs
|
||||
function getMockDataType(currentMock: PluginRespType) {
|
||||
let dataTypeName = typeof currentMock as MockDataValueType | undefined;
|
||||
if (currentMock instanceof Array) {
|
||||
@@ -118,7 +118,7 @@ function compareMockDataType(
|
||||
mockDataType?: MockDataValueType,
|
||||
initDataType?: MockDataValueType,
|
||||
) {
|
||||
// mock data 的类型是根据值识别出的,存在 Integer 类型被识别为 Number 的情况
|
||||
// The type of mock data is recognized by value, and there are cases where the Integer type is recognized as Number.
|
||||
if (mockDataType === MockDataValueType.NUMBER) {
|
||||
return (
|
||||
initDataType === MockDataValueType.NUMBER ||
|
||||
@@ -129,7 +129,7 @@ function compareMockDataType(
|
||||
}
|
||||
}
|
||||
|
||||
// 转换 Object 格式到 DataWithStatus 格式
|
||||
// Convert Object format to DataWithStatus format
|
||||
export function transMockData2DataWithStatus(
|
||||
label: string,
|
||||
currentMock: PluginRespType,
|
||||
@@ -262,8 +262,8 @@ function merge2DataList(
|
||||
}
|
||||
}
|
||||
|
||||
// 在合并 array 时,会出现 autoInitDataList(originData) 中只存在一个初始化数据,而 mockDataListWithStatus(appendData) 存在多个相同结构的数据
|
||||
// 需要将 mockDataListWithStatus 中剩余的数据进行合入
|
||||
// When combining arrays, it appears that only one initialization data exists in autoInitDataList (originData), while mockDataListWithStatus (appendData) has multiple data of the same structure
|
||||
// The remaining data in the mockDataListWithStatus needs to be incorporated
|
||||
if (appendData.length && isArrayType) {
|
||||
const target = autoInitDataList[0];
|
||||
appendData.forEach(item => {
|
||||
@@ -285,7 +285,7 @@ function merge2DataList(
|
||||
};
|
||||
}
|
||||
|
||||
// 合并两个 MockDataWithStatus 数组,以 autoInitDataList 顺序优先
|
||||
// Merge two MockDataWithStatus arrays, in autoInitDataList order first
|
||||
export function mergeDataWithStatus(
|
||||
autoInitDataList?: MockDataWithStatus[],
|
||||
mockDataListWithStatus?: MockDataWithStatus[],
|
||||
@@ -301,7 +301,7 @@ export function mergeDataWithStatus(
|
||||
};
|
||||
}
|
||||
|
||||
// 在合并 array 时,存在 mockDataListWithStatus 为空的情况,此时直接判断
|
||||
// When merging the array, there is a situation where the mockDataListWithStatus is empty. At this time, it is directly judged
|
||||
if (mockDataListWithStatus.length === 0 && isArrayType) {
|
||||
return {
|
||||
merged: [],
|
||||
|
||||
@@ -31,7 +31,7 @@ interface RiskAction {
|
||||
const initialStore: RiskStore = {
|
||||
pluginRiskIsRead: true,
|
||||
toolHiddenModeNewbieGuideIsRead: true,
|
||||
// 支持扩展其它风险提示...
|
||||
// Support for expanding other risk alerts...
|
||||
};
|
||||
|
||||
export const useRiskWarningStore = create<RiskStore & RiskAction>()(
|
||||
|
||||
@@ -93,6 +93,6 @@ describe('useParametersInSettingModalController', () => {
|
||||
result.current.doUpdateParams();
|
||||
});
|
||||
|
||||
expect(result.current.isUpdateLoading).toBe(false); // 假设更新完成后isUpdateLoading为false
|
||||
expect(result.current.isUpdateLoading).toBe(false); // Assuming isUpdateLoading is false after the update is complete
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('findPathById', () => {
|
||||
});
|
||||
|
||||
describe('addDepthAndValue', () => {
|
||||
// 测试 1:验证函数是否正常工作
|
||||
// Test 1: Verify that the function is working properly
|
||||
it('should add depth to each node in the tree', () => {
|
||||
const tree = [{ id: 1, sub_parameters: [{ id: 2 }, { id: 3 }] }, { id: 4 }];
|
||||
addDepthAndValue(tree);
|
||||
@@ -85,14 +85,14 @@ describe('addDepthAndValue', () => {
|
||||
expect(tree[1].deep).toEqual(1);
|
||||
});
|
||||
|
||||
// 测试 2:验证函数在空树情况下是否正常工作
|
||||
// Test 2: Verify that the function works properly in the empty tree case
|
||||
it('should not fail on empty trees', () => {
|
||||
const tree: any[] = [];
|
||||
addDepthAndValue(tree);
|
||||
expect(tree).toEqual([]);
|
||||
});
|
||||
|
||||
// 测试 3:验证函数在只有一个节点的树情况下是否正常工作
|
||||
// Test 3: Verify that the function works properly in a tree with only one node
|
||||
it('should handle single-node trees', () => {
|
||||
const tree = [{ id: 1 }];
|
||||
addDepthAndValue(tree);
|
||||
@@ -114,7 +114,7 @@ describe('handleDeepArr', () => {
|
||||
const deepArr = [];
|
||||
handleDeepArr(tree, deepArr);
|
||||
|
||||
// 断言
|
||||
// assert
|
||||
expect(deepArr).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
});
|
||||
@@ -130,7 +130,7 @@ describe('maxDeep', () => {
|
||||
},
|
||||
];
|
||||
|
||||
// 测试 tree1 的最大深度
|
||||
// Test the maximum depth of tree1
|
||||
expect(maxDeep(tree1)).toEqual(5);
|
||||
});
|
||||
|
||||
@@ -138,10 +138,10 @@ describe('maxDeep', () => {
|
||||
const tree2 = [];
|
||||
const tree3 = [{ deep: 1 }];
|
||||
|
||||
// 测试空树的最大深度
|
||||
// Test the maximum depth of an empty tree
|
||||
expect(maxDeep(tree2)).toEqual(0);
|
||||
|
||||
// 测试只有一个节点的树的最大深度
|
||||
// Test the maximum depth of a tree with only one node
|
||||
expect(maxDeep(tree3)).toEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -174,9 +174,9 @@ describe('deleteNode', () => {
|
||||
|
||||
const result = deleteNode(data, targetKey);
|
||||
|
||||
// 断言删除成功
|
||||
// Asserts successful deletion
|
||||
expect(result).toBe(true);
|
||||
// 断言目标节点已删除
|
||||
// Asserts that the target node has been deleted
|
||||
expect(data.find(node => node.id === targetKey)).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -191,7 +191,7 @@ describe('deleteNode', () => {
|
||||
|
||||
const result = deleteNode(data, targetKey);
|
||||
|
||||
// 断言删除失败
|
||||
// Assertion deletion failed
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
@@ -212,11 +212,11 @@ describe('deleteNode', () => {
|
||||
|
||||
const result = deleteNode(data, targetKey);
|
||||
|
||||
// 断言删除成功
|
||||
// Asserts successful deletion
|
||||
expect(result).toBe(true);
|
||||
// 断言目标节点已删除
|
||||
// Asserts that the target node has been deleted
|
||||
expect(data.find(node => node.id === targetKey)).toBeUndefined();
|
||||
// 断言子节点已删除
|
||||
// Asserts that the sub-node has been deleted
|
||||
expect(data[1].sub_parameters.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -273,7 +273,7 @@ describe('deleteAllChildNode', () => {
|
||||
});
|
||||
|
||||
describe('updateNodeById', () => {
|
||||
// 创建测试数据
|
||||
// Create test data
|
||||
const data = [
|
||||
{
|
||||
id: '1',
|
||||
@@ -291,10 +291,10 @@ describe('updateNodeById', () => {
|
||||
const field = 'name';
|
||||
const value = 'Updated Node';
|
||||
|
||||
// 调用被测试的函数
|
||||
// Call the function under test
|
||||
updateNodeById({ data, targetKey, field, value });
|
||||
|
||||
// 验证节点数据是否已更新
|
||||
// Verify that the node data has been updated
|
||||
expect(data[1].name).toEqual(value);
|
||||
});
|
||||
|
||||
@@ -303,7 +303,7 @@ describe('updateNodeById', () => {
|
||||
const field = 'name';
|
||||
const value = 'Updated Node';
|
||||
|
||||
// 调用被测试的函数
|
||||
// Call the function under test
|
||||
updateNodeById({ data, targetKey, field, value });
|
||||
expect(data[0].sub_parameters[1].name).toEqual(value);
|
||||
});
|
||||
@@ -351,7 +351,7 @@ describe('findTemplateNodeByPath', () => {
|
||||
|
||||
describe('transformTreeToObj', () => {
|
||||
it('should convert a tree to an object', () => {
|
||||
// 创建一个树结构的参数数组
|
||||
// Create a tree-structured array of parameters
|
||||
const tree = [
|
||||
{
|
||||
name: 'stringParam',
|
||||
@@ -397,10 +397,10 @@ describe('transformTreeToObj', () => {
|
||||
},
|
||||
];
|
||||
|
||||
// 调用函数并将结果存储在变量 obj 中
|
||||
// Call the function and store the result in the variable obj
|
||||
const obj = transformTreeToObj(tree);
|
||||
|
||||
// 检查转换后的对象是否具有正确的属性和值
|
||||
// Checking whether the converted object has the correct properties and values
|
||||
expect(obj).toEqual({
|
||||
stringParam: 'Hello, World!',
|
||||
numberParam: 42,
|
||||
|
||||
@@ -36,13 +36,13 @@ export const InfoPopover: React.FC<InfoPopoverProps> = props => {
|
||||
className="!max-w-[320px]"
|
||||
content={data?.map((item, index) => (
|
||||
<Fragment key={`${item.type}${index}`}>
|
||||
{/* 加粗标题 */}
|
||||
{/* bold title */}
|
||||
{item.type === 'title' ? (
|
||||
<Typography.Text fontSize="14px" className="dark coz-fg-primary">
|
||||
{item.text}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
{/* 文本 */}
|
||||
{/* Text */}
|
||||
{item.type === 'text' ? (
|
||||
<Typography.Paragraph
|
||||
fontSize="12px"
|
||||
@@ -51,9 +51,9 @@ export const InfoPopover: React.FC<InfoPopoverProps> = props => {
|
||||
{item.text}
|
||||
</Typography.Paragraph>
|
||||
) : null}
|
||||
{/* 换行 */}
|
||||
{/* line feed */}
|
||||
{item.type === 'br' ? <div className="h-[8px]" /> : null}
|
||||
{/* 示例,边框内展示 */}
|
||||
{/* Example, display inside the border */}
|
||||
{item.type === 'demo' ? (
|
||||
<div className="dark mt-[4px] p-[10px] border border-solid coz-stroke-primary">
|
||||
<Typography.Paragraph
|
||||
|
||||
@@ -96,7 +96,7 @@ export const useBaseInfo = ({
|
||||
formRef.current?.formApi.setValue('desc', desc);
|
||||
});
|
||||
|
||||
// 提交基础信息
|
||||
// Submit basic information
|
||||
const submitBaseInfo = async () => {
|
||||
const status = await formRef.current?.formApi
|
||||
.validate()
|
||||
|
||||
@@ -110,7 +110,7 @@ export const useBaseMore = ({
|
||||
baseInfo.api_extend?.auth_mode,
|
||||
]);
|
||||
|
||||
// 提交基础信息
|
||||
// Submit basic information
|
||||
const submitBaseInfo = async () => {
|
||||
const status = await formRef.current?.formApi
|
||||
.validate()
|
||||
|
||||
@@ -73,7 +73,7 @@ export const CascaderItem: FC<CProps> = ({
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const isObjectField = (record.deep ?? 0) > 1 && record.name !== ARRAYTAG;
|
||||
|
||||
// 通过check触发校验(提交时)
|
||||
// Trigger validation via check (when committed)
|
||||
useEffect(() => {
|
||||
if (check === 0) {
|
||||
return;
|
||||
@@ -81,7 +81,7 @@ export const CascaderItem: FC<CProps> = ({
|
||||
handleCheck(value);
|
||||
}, [check]);
|
||||
|
||||
// 校验
|
||||
// validation
|
||||
const handleCheck = (val?: CascaderValueType) => {
|
||||
const status = !val?.[0] ? 1 : 0;
|
||||
setErrorStatus(status);
|
||||
|
||||
@@ -92,7 +92,7 @@ export const FileUploadItem: FC<{
|
||||
const { uploading, uri, url, name, type } = fileState;
|
||||
|
||||
/**
|
||||
* 回显 只有一个url(string),需要兼容 => 不展示icon,url作为文件名
|
||||
* Echo, only one url (string), need to be compatible = > do not show icon, url as file name
|
||||
*/
|
||||
const onlyUrlString = !!url && !uri;
|
||||
const displayName = onlyUrlString ? value : name;
|
||||
@@ -113,7 +113,7 @@ export const FileUploadItem: FC<{
|
||||
if (uploading) {
|
||||
return uploadButton;
|
||||
} else if (onlyUrlString && type === FileTypeEnum.IMAGE) {
|
||||
/** image不是即时上传的无法确认其为合法资源路径 */
|
||||
/** The image is not uploaded immediately and cannot be confirmed as a legitimate resource path. */
|
||||
icon = fileUnknownIcon;
|
||||
} else if (!isImageString) {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
|
||||
@@ -26,16 +26,16 @@ import { FileTypeEnum } from '@coze-studio/file-kit/logic';
|
||||
|
||||
import { type APIParameterRecord } from './types/params';
|
||||
|
||||
export const childrenRecordName = 'sub_parameters'; // 子节点名称
|
||||
export const ROWKEY = 'id'; // 唯一标识符
|
||||
export const ARRAYTAG = '[Array Item]'; // 数组元素标识符
|
||||
export const ROOTTAG = '[Root Item]'; // root为数组的标识符
|
||||
export const childrenRecordName = 'sub_parameters'; // sub-node name
|
||||
export const ROWKEY = 'id'; // unique device identifier
|
||||
export const ARRAYTAG = '[Array Item]'; // Array element identifier
|
||||
export const ROOTTAG = '[Root Item]'; // Root is the identifier of the array
|
||||
export const STARTNODE = 0;
|
||||
export const REQUESTNODE = 1;
|
||||
export const RESPONSENODE = 2;
|
||||
export const DEBUGNODE = 3;
|
||||
export const ENDSTEP = 4;
|
||||
// 传入方法options
|
||||
// Incoming method options
|
||||
export const parameterLocationOptions = [
|
||||
{
|
||||
label: 'Body',
|
||||
@@ -57,8 +57,8 @@ export const parameterLocationOptions = [
|
||||
|
||||
export enum ParameterTypeExtend {
|
||||
/**
|
||||
* 扩展类型
|
||||
* 与 AssistParameterType 一一对应
|
||||
* extension type
|
||||
* One-to-one correspondence with AssistParameterType
|
||||
*/
|
||||
DEFAULT = 10001,
|
||||
IMAGE,
|
||||
@@ -93,7 +93,7 @@ interface ParameterTypeOption {
|
||||
}
|
||||
|
||||
/**
|
||||
* 未扩展File类型前的 基础类型,多处使用 需要保留 start
|
||||
* The basic type before the unextended File type is used in many places, and start needs to be reserved.
|
||||
*/
|
||||
export const parameterTypeOptions: Array<ParameterTypeOption> = [
|
||||
{
|
||||
@@ -145,7 +145,7 @@ export const parameterTypeOptionsSub: Array<ParameterTypeOption> = [
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 未扩展File类型前的 基础类型,多处使用 需要保留 end
|
||||
* Unexpanded File type, base type, used in many places, need to keep end
|
||||
*/
|
||||
|
||||
export const parameterTypeExtendMap: Record<
|
||||
@@ -406,12 +406,12 @@ export const methodType: ExtInfoText[] = [
|
||||
export enum ParamsFormErrorStatus {
|
||||
NO_ERROR = 0,
|
||||
NAME_EMPTY = 1,
|
||||
// 中文
|
||||
// Chinese
|
||||
CHINESE = 2,
|
||||
// 重复
|
||||
// repeat
|
||||
REPEAT = 3,
|
||||
ASCII = 4,
|
||||
// 未填写
|
||||
// not filled in
|
||||
DESC_EMPTY = 5,
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ const ProcessContent: FC<PropsWithChildren> = ({ children }) => (
|
||||
<div className={s['process-content']}>{children}</div>
|
||||
);
|
||||
|
||||
/** stringify 缩进 */
|
||||
/** Stringify indent */
|
||||
const INDENTATION_SPACES = 2;
|
||||
const LLMAndAPIContent: FC<{
|
||||
toolMessageUnit: CheckParamsProps;
|
||||
|
||||
@@ -36,7 +36,7 @@ import { type CheckParamsProps, STATUS } from '../types';
|
||||
import s from '../index.module.less';
|
||||
import ParamsForm from './params-form';
|
||||
|
||||
/** stringify 缩进 */
|
||||
/** Stringify indent */
|
||||
const INDENTATION_SPACES = 2;
|
||||
const SLEEP_NUM = 100;
|
||||
|
||||
@@ -68,7 +68,7 @@ export const DebugParams: React.FC<{
|
||||
const paramsFormRef = useRef<{ data: Array<APIParameter> }>(null);
|
||||
|
||||
const handleAction = async () => {
|
||||
// 校验是否必填
|
||||
// Verification is required
|
||||
setCheck(check + 1);
|
||||
await sleep(SLEEP_NUM);
|
||||
const errorEle = document.getElementsByClassName('errorDebugClassTag');
|
||||
|
||||
@@ -53,7 +53,7 @@ const InputItem = ({
|
||||
}: InputItemProps): JSX.Element => {
|
||||
const [value, setValue] = useState(val);
|
||||
const [errorStatus, setErrorStatus] = useState(false);
|
||||
// 通过check触发校验(提交时)
|
||||
// Trigger validation via check (when committed)
|
||||
useEffect(() => {
|
||||
if (check === 0 || value === ARRAYTAG || value === ROOTTAG) {
|
||||
return;
|
||||
|
||||
@@ -128,7 +128,7 @@ const getParamsTitle = (isShowExampleTag: boolean, disabled: boolean) =>
|
||||
)
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function -- 已经在拆了
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function -- already dismantling
|
||||
const ParamsForm = (
|
||||
props: ParamsFormProps,
|
||||
ref: Ref<{ data: Array<APIParameter> } | null>,
|
||||
@@ -160,7 +160,7 @@ const ParamsForm = (
|
||||
}));
|
||||
|
||||
const [flag, setFlag] = useState<boolean>(false);
|
||||
// 添加子节点
|
||||
// Add sub-node
|
||||
const addChildNode = (record: APIParameter) => {
|
||||
if (!data) {
|
||||
return;
|
||||
@@ -168,7 +168,7 @@ const ParamsForm = (
|
||||
let result: APIParameter & {
|
||||
path?: Array<number>;
|
||||
} = {};
|
||||
// 1.查找路径
|
||||
// 1. Find the path
|
||||
findPathById({
|
||||
data,
|
||||
callback: (item: APIParameter, path: Array<number>) => {
|
||||
@@ -178,16 +178,16 @@ const ParamsForm = (
|
||||
},
|
||||
});
|
||||
|
||||
// 2.拼接路径
|
||||
// 2. Splicing path
|
||||
const path = (result?.path || [])
|
||||
.map((v: number) => [v, childrenRecordName])
|
||||
.flat();
|
||||
// newPath是模版的路径,下面添加节点newNode可以直接从该路径引用
|
||||
// newPath is the path of the template. The following node newNode can be directly referenced from this path
|
||||
const newPath = findTemplateNodeByPath(resourceData, path);
|
||||
// 3.添加节点
|
||||
// 3. Add a node
|
||||
const newData = cloneDeep(data);
|
||||
if (Array.isArray(ObjectGet(newData, path))) {
|
||||
// 这一步是为了根据newPath找到对应的根节点,并且克隆一个新节点
|
||||
// This step is to find the corresponding root node according to newPath and clone a new node
|
||||
const newNode = cloneWithRandomKey(ObjectGet(resourceData, newPath)[0]);
|
||||
ObjectSet(newData, path, [...ObjectGet(newData, path), newNode]);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export const Debug: React.FC<{
|
||||
debugExample?: DebugExample;
|
||||
setDebugStatus?: (status: STATUS | undefined) => void;
|
||||
setDebugExample?: (v: DebugExample) => void;
|
||||
isViewExample?: boolean; // 查看 example 模式 标题不一样
|
||||
isViewExample?: boolean; // Look at the example mode, the title is different
|
||||
onSuccessCallback?: () => void;
|
||||
}> = ({
|
||||
disabled,
|
||||
@@ -94,7 +94,7 @@ export const Debug: React.FC<{
|
||||
setDebugStatus?.(innerStatus);
|
||||
innerStatus === STATUS.PASS &&
|
||||
setDebugExample?.({ req_example: request, resp_example: response });
|
||||
// 调试成功后回调
|
||||
// Callback after successful debugging
|
||||
innerStatus === STATUS.PASS && onSuccessCallback?.();
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export const InputAndVariableItem = ({
|
||||
onChange={val => {
|
||||
onSourceChange?.(Number(val));
|
||||
|
||||
// 切换来源,清空默认值
|
||||
// Switch source, clear default
|
||||
onReferenceChange?.('');
|
||||
onValueChange?.('');
|
||||
}}
|
||||
|
||||
@@ -59,7 +59,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
|
||||
addChildNode,
|
||||
enableFileType = false,
|
||||
}) => {
|
||||
// 删除全部子节点;
|
||||
// Delete all sub-nodes;
|
||||
const handleDeleteAllChildNode = (r: APIParameter) => {
|
||||
const cloneData = cloneDeep(data);
|
||||
const delStatus = deleteAllChildNode(cloneData, r[ROWKEY] as string);
|
||||
@@ -86,7 +86,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
|
||||
}
|
||||
|
||||
if (!isResponse) {
|
||||
// 切换类型,重置default value
|
||||
// Switch type, reset default value
|
||||
if (record.global_default) {
|
||||
updateNodeWithData({
|
||||
record,
|
||||
@@ -103,7 +103,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
|
||||
value: [type, assistType ?? null],
|
||||
};
|
||||
|
||||
// updateNodeWithData 会变更type类型,保留原始的type
|
||||
// updateNodeWithData will change the type type and keep the original type.
|
||||
const recordType = record?.type;
|
||||
|
||||
if (type === ParameterType.Array) {
|
||||
|
||||
@@ -89,7 +89,7 @@ const DefaultValueModal = ({
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
// 校验是否必填
|
||||
// Verification is required
|
||||
setCheck(check + 1);
|
||||
const errorEle = document.getElementsByClassName('errorDebugClassTag');
|
||||
if (errorEle.length > 0) {
|
||||
@@ -153,8 +153,8 @@ export const DefaultValueInput = ({
|
||||
data,
|
||||
setData,
|
||||
canReference = false,
|
||||
defaultKey = 'global_default', //输入框的key
|
||||
disableKey = 'global_disable', //开启按钮key
|
||||
defaultKey = 'global_default', //Text box key
|
||||
disableKey = 'global_disable', //Open button key
|
||||
referenceOption,
|
||||
}: DefaultValueInputProps) => {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -173,7 +173,7 @@ export const DefaultValueInput = ({
|
||||
return <></>;
|
||||
}
|
||||
|
||||
// 复杂类型暂不支持引用变量
|
||||
// Complex types do not currently support reference variables
|
||||
if (record.type === ParameterType.Array) {
|
||||
return (
|
||||
<div className={styles['modal-wrapper']}>
|
||||
|
||||
@@ -60,14 +60,14 @@ export const InputItem = ({
|
||||
useEffect(() => {
|
||||
setValue(val);
|
||||
}, [val]);
|
||||
// 通过check触发校验(提交时)
|
||||
// Trigger validation via check (when committed)
|
||||
useEffect(() => {
|
||||
if (check === 0 || value === ARRAYTAG || value === ROOTTAG) {
|
||||
return;
|
||||
}
|
||||
handleCheck(value);
|
||||
}, [check]);
|
||||
// 校验
|
||||
// validation
|
||||
const handleCheck = (checkVal: string) => {
|
||||
let status =
|
||||
checkVal === ''
|
||||
@@ -104,7 +104,7 @@ export const InputItem = ({
|
||||
}
|
||||
setErrorStatus(status);
|
||||
};
|
||||
// 过滤空格、限制输入长度
|
||||
// Filter spaces, limit input length
|
||||
const handleFilter = (v: string) => {
|
||||
if (filterSpace) {
|
||||
v = v.replace(/\s+/g, '');
|
||||
@@ -122,7 +122,7 @@ export const InputItem = ({
|
||||
item.type === ParameterType.Object,
|
||||
)
|
||||
: true;
|
||||
// 每增加一层,因为有展开icon,宽度减少20
|
||||
// Each additional layer decreases the width by 20 because of the expansion icon.
|
||||
const vWidth = dynamicWidth
|
||||
? `calc(100% - ${DEEP_INDENT_NUM * deep}px)`
|
||||
: width;
|
||||
@@ -175,7 +175,7 @@ export const InputItem = ({
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
{/* 参数名称设置动态列宽 */}
|
||||
{/* Parameter name Set dynamic column width */}
|
||||
{errorStatus !== 0 && dynamicWidth ? (
|
||||
<div className={s['check-box']} style={{ width: tipWidth }}>
|
||||
<span className={cl(s['form-check-tip'], 'errorClassTag', s.w110)}>
|
||||
@@ -183,7 +183,7 @@ export const InputItem = ({
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 非参数列表设置固定最大宽 */}
|
||||
{/* Non-parametric list setting fixed maximum width */}
|
||||
{errorStatus !== 0 && !dynamicWidth && (
|
||||
<div className={s['check-box']} style={{ width: tipWidth }}>
|
||||
<span
|
||||
@@ -212,14 +212,14 @@ export const SelectItem = ({
|
||||
const [value, setValue] = useState(!record?.type ? undefined : record?.type);
|
||||
const [errorStatus, setErrorStatus] = useState<number>(0);
|
||||
|
||||
// 通过check触发校验(提交时)
|
||||
// Trigger validation via check (when committed)
|
||||
useEffect(() => {
|
||||
if (check === 0) {
|
||||
return;
|
||||
}
|
||||
handleCheck(value);
|
||||
}, [check]);
|
||||
// 校验
|
||||
// validation
|
||||
const handleCheck = (val: string | ParameterType | undefined) => {
|
||||
const status = val === undefined ? 1 : 0;
|
||||
setErrorStatus(status);
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function -- 历史逻辑 陆续在拆 */
|
||||
/* eslint-disable max-lines -- 历史逻辑 陆续在拆 */
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function -- historical logic, dismantling one after another */
|
||||
/* eslint-disable max-lines -- historical logic, dismantling one after another */
|
||||
|
||||
import { cloneDeep, flow, get as ObjectGet, set as ObjectSet } from 'lodash-es';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
@@ -75,7 +75,7 @@ export interface ColumnsProps {
|
||||
showSecurityCheckFailedMsg: boolean;
|
||||
setShowSecurityCheckFailedMsg: (flag: boolean) => void;
|
||||
/**
|
||||
* 是否支持扩展的文件类型
|
||||
* Whether extended file types are supported
|
||||
*/
|
||||
enableFileType?: boolean;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ export const getColumns = ({
|
||||
setShowSecurityCheckFailedMsg,
|
||||
enableFileType = false,
|
||||
}: ColumnsProps) => {
|
||||
// 添加子节点
|
||||
// Add sub-node
|
||||
const addChildNode: AddChildNodeFn = ({
|
||||
record,
|
||||
isArray = false,
|
||||
@@ -118,37 +118,37 @@ export const getColumns = ({
|
||||
path?: Array<number>;
|
||||
} = {};
|
||||
|
||||
// 1.查找路径
|
||||
// 1. Find the path
|
||||
findPathById({
|
||||
data,
|
||||
callback: (item: APIParameter, path: Array<number>) => {
|
||||
if (item[ROWKEY] === record[ROWKEY]) {
|
||||
result = { ...item, path };
|
||||
// 修改复杂类型结构,需要重置数组的默认值
|
||||
// Modifying complex type structures requires resetting the default values of the array
|
||||
deleteArrayGlobalDefaultByPath(newData, path);
|
||||
}
|
||||
},
|
||||
});
|
||||
// 2.拼接路径
|
||||
// 2. Splicing path
|
||||
const path = (result?.path || [])
|
||||
.map((v: number) => [v, childrenRecordName])
|
||||
.flat();
|
||||
// 如果是添加子节点,则更新父节点中的类型
|
||||
// If adding a sub-node, update the type in the parent node
|
||||
if (recordType) {
|
||||
const typePath = cloneDeep(path);
|
||||
typePath.pop();
|
||||
typePath.push('type');
|
||||
|
||||
// type 为4/5,切换节点的时候需要先删除子节点
|
||||
// recordType 原节点的类型
|
||||
// newData 新节点数据
|
||||
// The type is 4/5. When switching nodes, you need to delete the sub-node first.
|
||||
// recordType The type of the original node
|
||||
// newData new node data
|
||||
if (ObjectGet(newData, typePath) !== recordType) {
|
||||
deleteAllChildNode(newData, record[ROWKEY] as string);
|
||||
}
|
||||
|
||||
ObjectSet(newData, typePath, type);
|
||||
}
|
||||
// 3.添加节点
|
||||
// 3. Add a node
|
||||
if (Array.isArray(ObjectGet(newData, path))) {
|
||||
ObjectSet(newData, path, [
|
||||
...ObjectGet(newData, path),
|
||||
@@ -167,7 +167,7 @@ export const getColumns = ({
|
||||
}
|
||||
setData(newData);
|
||||
};
|
||||
// 删除子节点
|
||||
// Delete sub-node
|
||||
const deleteChildNode = (record: APIParameter) => {
|
||||
const cloneData = cloneDeep(data);
|
||||
const delStatsu = deleteNode(cloneData, record[ROWKEY] as string);
|
||||
@@ -281,7 +281,7 @@ export const getColumns = ({
|
||||
),
|
||||
key: 'desc',
|
||||
render: (record: APIParameter) =>
|
||||
// ,帮助用户/大模型更好地理解。
|
||||
// To help users/large models better understand.
|
||||
disabled ? (
|
||||
<Typography.Text
|
||||
component="div"
|
||||
@@ -390,7 +390,7 @@ export const getColumns = ({
|
||||
disabled={disabled}
|
||||
defaultChecked={record.is_required}
|
||||
onChange={e => {
|
||||
// 必填 + 没有默认值 = 可见
|
||||
// Required + no default = visible
|
||||
if (e.target.checked && !record.global_default) {
|
||||
updateNodeWithData({
|
||||
record,
|
||||
@@ -510,7 +510,7 @@ export const getColumns = ({
|
||||
],
|
||||
);
|
||||
}
|
||||
//出参场景,移除 required,增加 enabled 开关
|
||||
//Exported parameter scene, remove required, add enabled switch
|
||||
|
||||
if (isResponse) {
|
||||
const targetIndex = columns.findIndex(c => c.key === 'default');
|
||||
@@ -549,14 +549,14 @@ export const getColumns = ({
|
||||
});
|
||||
}
|
||||
return flow(
|
||||
// 将 columns 以函数参数形式传入,而非直接传给组合函数(`flow(...)(columns)`)是为了利于类型推导
|
||||
// The purpose of passing columns as function arguments rather than directly to the combinatorial function (flow (...) (columns)) is to facilitate type derivation
|
||||
() => columns,
|
||||
// 只读状态不展示后四项操作列
|
||||
// Read-only status does not show the last four action columns
|
||||
newColumns => {
|
||||
const len = isResponse ? DISABLED_RES_SLICE : DISABLED_REQ_SLICE;
|
||||
return disabled ? newColumns.slice(0, len) : newColumns;
|
||||
},
|
||||
// response不需要location字段
|
||||
// Response does not require location field
|
||||
newColumns =>
|
||||
isResponse
|
||||
? newColumns.filter(item => item.key !== 'location')
|
||||
|
||||
@@ -105,8 +105,8 @@ export const useRequestParams = ({
|
||||
}
|
||||
setFormData(fd);
|
||||
};
|
||||
const [flag, setFlag] = useState<boolean>(false); // 为了更新视图
|
||||
const [checkFlag, setCheckFlag] = useState<number>(0); // 全局校验用
|
||||
const [flag, setFlag] = useState<boolean>(false); // To update the view
|
||||
const [checkFlag, setCheckFlag] = useState<number>(0); // global validation
|
||||
const columns = getColumns({
|
||||
data,
|
||||
flag,
|
||||
@@ -192,13 +192,13 @@ export const useRequestParams = ({
|
||||
style={{ minWidth: 1008, overflowY: 'auto' }}
|
||||
>
|
||||
<Table
|
||||
// 最小宽度,为了兼容多层级场景,最大层级可支持超过50层
|
||||
// 最小宽度 = 模块最小宽度 + (当前层级数 - 宽度变化起始层级) * (当前层级数 < 宽度变化起始层级 ? 小间隔数 : 大间隔数)
|
||||
// Minimum width, in order to be compatible with multi-level scenarios, the maximum level can support more than 50 layers
|
||||
// Minimum width = minimum width of module + (current level number - width change starting level) * (current level number < width change starting level? small interval number: large interval number)
|
||||
style={{
|
||||
minWidth: `calc(1008px + ${
|
||||
(maxNum - STARTNUM) * (maxNum < CHANGENUM ? SMALLGAP : MAXZGAP)
|
||||
}px)`,
|
||||
}} // 从第4层开始,每多一层增加19px
|
||||
}} // From the 4th layer, add 19px to each additional layer.
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
|
||||
@@ -109,8 +109,8 @@ export const useResponseParams = ({
|
||||
const [data, setFormData] = useState<Array<APIParameter>>(
|
||||
responseParams || [],
|
||||
);
|
||||
const [flag, setFlag] = useState<boolean>(false); // 为了更新视图
|
||||
const [checkFlag, setCheckFlag] = useState<number>(0); // 全局校验用
|
||||
const [flag, setFlag] = useState<boolean>(false); // To update the view
|
||||
const [checkFlag, setCheckFlag] = useState<number>(0); // global validation
|
||||
const [inputModal, setInputModal] = useState<boolean>(false);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
@@ -282,7 +282,7 @@ export const useResponseParams = ({
|
||||
>
|
||||
<Table
|
||||
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- ui
|
||||
style={{ minWidth: `calc(1008px + ${(maxNum - 6) * 20}px)` }} // 从第6层开始,每多一层增加20px
|
||||
style={{ minWidth: `calc(1008px + ${(maxNum - 6) * 20}px)` }} // From the 6th layer, add 20px to each additional layer.
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/* eslint-disable complexity */
|
||||
/* eslint-disable max-lines */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- 一些历史any 改不动 */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- some history can't be changed */
|
||||
import { nanoid } from 'nanoid';
|
||||
import { cloneDeep, has, isEmpty, isNumber, isObject } from 'lodash-es';
|
||||
import {
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
|
||||
import { ARRAYTAG, ROWKEY, childrenRecordName } from './config';
|
||||
|
||||
// 遍历树,返回目标id路径
|
||||
// Traverse the tree and return the target ID path
|
||||
export const findPathById = ({
|
||||
data,
|
||||
callback,
|
||||
@@ -55,7 +55,7 @@ export const findPathById = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 给每层对象增加层级深度标识
|
||||
// Add layer depth markers to each layer of objects
|
||||
export const addDepthAndValue = (
|
||||
tree: any,
|
||||
valKey: 'global_default' | 'local_default' = 'global_default',
|
||||
@@ -64,28 +64,28 @@ export const addDepthAndValue = (
|
||||
if (!Array.isArray(tree)) {
|
||||
return;
|
||||
}
|
||||
// 遍历树中的每个节点
|
||||
// Traverse each node in the tree
|
||||
for (const node of tree) {
|
||||
// 为当前节点添加深度标识符
|
||||
// Add a depth identifier to the current node
|
||||
node.deep = depth;
|
||||
if (node[valKey]) {
|
||||
node.value = node[valKey];
|
||||
}
|
||||
// 如果当前节点有子节点,则递归地为子节点添加深度标识符
|
||||
// If the current node has a sub-node, add a depth identifier to the sub-node recursively
|
||||
if (node[childrenRecordName]) {
|
||||
addDepthAndValue(node[childrenRecordName], valKey, depth + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 将深度信息push到一个数组里,最后取最大值
|
||||
// Push the depth information into an array, and finally take the maximum value
|
||||
export const handleDeepArr = (tree: any, deepArr: Array<number> = []) => {
|
||||
if (!Array.isArray(tree)) {
|
||||
return;
|
||||
}
|
||||
// 遍历树中的每个节点
|
||||
// Traverse each node in the tree
|
||||
for (const node of tree) {
|
||||
// 为当前节点添加深度标识符
|
||||
// Add a depth identifier to the current node
|
||||
if (isNumber(node.deep)) {
|
||||
deepArr.push(node.deep);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ export const handleDeepArr = (tree: any, deepArr: Array<number> = []) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 返回最大深度
|
||||
// Return to maximum depth
|
||||
export const maxDeep = (tree: any) => {
|
||||
if (!Array.isArray(tree) || tree.length === 0) {
|
||||
return 0;
|
||||
@@ -112,7 +112,7 @@ interface DefaultNode {
|
||||
deep?: number;
|
||||
}
|
||||
|
||||
// 默认子节点
|
||||
// Default sub-node
|
||||
export const defaultNode = ({
|
||||
isArray = false,
|
||||
iscChildren = false,
|
||||
@@ -128,7 +128,7 @@ export const defaultNode = ({
|
||||
deep,
|
||||
});
|
||||
|
||||
// 删除当前节点
|
||||
// Delete the current node
|
||||
export const deleteNode = (data: any, targetKey: string) => {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i][ROWKEY] === targetKey) {
|
||||
@@ -146,7 +146,7 @@ export const deleteNode = (data: any, targetKey: string) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
// 删除全部子节点
|
||||
// Delete all sub-nodes
|
||||
export const deleteAllChildNode = (data: any, targetKey: string) => {
|
||||
for (const item of data) {
|
||||
if (item[ROWKEY] === targetKey) {
|
||||
@@ -169,7 +169,7 @@ interface UpdateNodeById {
|
||||
targetKey: string;
|
||||
field: string;
|
||||
value: any;
|
||||
/** 数组的子节点是否需要继承父节点的字段值,当前只有可见性开关需要继承 */
|
||||
/** Whether the sub-node of the array needs to inherit the field values of the parent node, currently only the visibility switch needs to inherit */
|
||||
inherit?: boolean;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ const updateNodeByVal = (data: any, field: any, val: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 更新节点信息
|
||||
// Update node information
|
||||
export const updateNodeById = ({
|
||||
data,
|
||||
targetKey,
|
||||
@@ -216,19 +216,19 @@ export const updateNodeById = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 根据路径找对应模版值
|
||||
// Find the corresponding template value according to the path
|
||||
export const findTemplateNodeByPath = (
|
||||
dsl: any,
|
||||
path: Array<string | number>,
|
||||
) => {
|
||||
let node = cloneDeep(dsl);
|
||||
const newPath = [...path]; //创建新的路径,避免修改原路径
|
||||
const newPath = [...path]; //Create a new path to avoid modifying the original path
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
// 如果存在节点,说明是源数据节点上增加子节点
|
||||
// If there is a node, it means that a sub-node is added to the source data node.
|
||||
if (node[path[i]]) {
|
||||
node = node[path[i]];
|
||||
} else {
|
||||
// 如果不存在,说明是新增的节点增加子节点,这时需要将路径指向原始节点(第一个节点)
|
||||
// If it doesn't exist, it means that the newly added node adds a sub-node. At this time, you need to point the path to the original node (the first node).
|
||||
node = node[0];
|
||||
newPath[i] = 0;
|
||||
}
|
||||
@@ -236,9 +236,9 @@ export const findTemplateNodeByPath = (
|
||||
return newPath;
|
||||
};
|
||||
|
||||
// 树转换成对象
|
||||
// Converting trees to objects
|
||||
export const transformTreeToObj = (tree: any, checkType = true): any =>
|
||||
// 树的每一层级表示一个对象的属性集
|
||||
// Each level of the tree represents a set of properties of an object
|
||||
|
||||
tree.reduce((acc: any, item: any) => {
|
||||
let arrTemp = [];
|
||||
@@ -278,8 +278,8 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
|
||||
break;
|
||||
case ParameterType.Array:
|
||||
/**
|
||||
* 如果是数组,需要过滤掉空的项(且数组的子项非object和array)
|
||||
* 这里用temp接收过滤后的子项,避免直接修改原数组(因为原数组和页面数据绑定,不能直接删除空项)
|
||||
* If it is an array, you need to filter out empty items (and the children of the array are not object and array).
|
||||
* Here, use temp to receive the filtered sub-items to avoid directly modifying the original array (because the original array and page data are bound, empty items cannot be directly deleted)
|
||||
*/
|
||||
arrTemp = item.sub_parameters;
|
||||
if (
|
||||
@@ -296,21 +296,21 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
|
||||
break;
|
||||
}
|
||||
acc[item.name] = arrTemp.map((subItem: any) => {
|
||||
// boolean类型匹配字符串true/false
|
||||
// Boolean type matching string true/false
|
||||
if ([ParameterType.Bool].includes(subItem.type)) {
|
||||
return checkType ? subItem.value === 'true' : subItem.value;
|
||||
}
|
||||
// 数字类型转为number
|
||||
// Number type to number
|
||||
if (
|
||||
[ParameterType.Integer, ParameterType.Number].includes(subItem.type)
|
||||
) {
|
||||
return checkType ? Number(subItem.value) : subItem.value;
|
||||
}
|
||||
// 字符串类型直接返回(进到这里的已经是过滤完空值的数组)
|
||||
// The string type is returned directly (the array entered here is already an array of filtered null values)
|
||||
if ([ParameterType.String].includes(subItem.type)) {
|
||||
return subItem.value;
|
||||
}
|
||||
// 如果是对象,递归遍历
|
||||
// If it is an object, recursive traversal
|
||||
if (subItem.type === ParameterType.Object) {
|
||||
return transformTreeToObj(subItem.sub_parameters, checkType);
|
||||
}
|
||||
@@ -322,28 +322,28 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// 克隆节点,修改key及清空value
|
||||
// Clone the node, modify the key and clear the value
|
||||
export const cloneWithRandomKey = (obj: any) => {
|
||||
// 创建新对象储存值
|
||||
// Create a new object stored value
|
||||
const clone: any = {};
|
||||
|
||||
// 遍历原对象的所有属性
|
||||
// Iterate through all properties of the original object
|
||||
for (const prop in obj) {
|
||||
// 如果原对象的这个属性是一个对象,递归调用 cloneWithRandomKey 函数
|
||||
// If this property of the original object is an object, recursively call the cloneWithRandomKey function
|
||||
if (obj[prop]?.constructor === Object) {
|
||||
clone[prop] = cloneWithRandomKey(obj[prop]);
|
||||
} else {
|
||||
// 否则,直接复制这个属性
|
||||
// Otherwise, copy this property directly
|
||||
clone[prop] = obj[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// 如果这个对象有 sub_parameters 属性,需要遍历它
|
||||
// If this object has sub_parameters properties, you need to iterate over it
|
||||
if ('sub_parameters' in clone) {
|
||||
clone.sub_parameters = clone.sub_parameters?.map(cloneWithRandomKey);
|
||||
}
|
||||
|
||||
// 生成一个新的随机 key
|
||||
// Generate a new random key
|
||||
if (clone[ROWKEY]) {
|
||||
clone[ROWKEY] = nanoid();
|
||||
}
|
||||
@@ -351,10 +351,10 @@ export const cloneWithRandomKey = (obj: any) => {
|
||||
clone.value = null;
|
||||
}
|
||||
|
||||
// 返回克隆的对象
|
||||
// Returns the cloned object
|
||||
return clone;
|
||||
};
|
||||
// 判断参数是否显示删除按钮 先判断是否是根节点,根节点允许删除
|
||||
// To determine whether the parameter shows the delete button, first determine whether it is the root node, and the root node allows deletion.
|
||||
export const handleIsShowDelete = (
|
||||
data: any,
|
||||
targetKey: string | undefined,
|
||||
@@ -366,7 +366,7 @@ export const handleIsShowDelete = (
|
||||
return isShowDelete(data, targetKey);
|
||||
};
|
||||
|
||||
// 检查是否存在相同名称
|
||||
// Check if the same name exists
|
||||
export const checkSameName = (
|
||||
data: Array<APIParameter>,
|
||||
targetKey: string,
|
||||
@@ -389,7 +389,7 @@ export const checkSameName = (
|
||||
}
|
||||
};
|
||||
|
||||
// 检查是否有array类型(用来判断response是否需要操作列)
|
||||
// Check if there is an array type (used to determine whether the response requires an operation column)
|
||||
export const checkHasArray = (data: unknown) => {
|
||||
if (!Array.isArray(data)) {
|
||||
return false;
|
||||
@@ -401,7 +401,7 @@ export const checkHasArray = (data: unknown) => {
|
||||
Array.isArray(item[childrenRecordName]) &&
|
||||
item[childrenRecordName].length > 0
|
||||
) {
|
||||
// 调整 循环退出时机
|
||||
// Adjustment, loop exit timing
|
||||
if (checkHasArray(item[childrenRecordName])) {
|
||||
return true;
|
||||
}
|
||||
@@ -410,7 +410,7 @@ export const checkHasArray = (data: unknown) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
// 判断参数是否显示删除按钮(object类型最后一个不允许删除)
|
||||
// Determine whether the parameter shows the delete button (the last one of the object type is not allowed to be deleted)
|
||||
export const isShowDelete = (data: any, targetKey: string | undefined) => {
|
||||
for (const item of data) {
|
||||
if (item[ROWKEY] === targetKey) {
|
||||
@@ -433,14 +433,14 @@ export const sleep = (time: number) =>
|
||||
}, time);
|
||||
});
|
||||
|
||||
// 该方法兼容chrome、Arch、Safari浏览器及iPad,增加兼容firefox
|
||||
// This method is compatible with Chrome, Arch, Safari and iPad, and is compatible with Firefox.
|
||||
export const scrollToErrorElement = (className: string) => {
|
||||
const errorElement = document.querySelector(className);
|
||||
if (errorElement) {
|
||||
if (typeof (errorElement as any).scrollIntoViewIfNeeded === 'function') {
|
||||
(errorElement as any).scrollIntoViewIfNeeded();
|
||||
} else {
|
||||
// 兼容性处理,如 Firefox
|
||||
// Compatibility handling, such as Firefox
|
||||
errorElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
@@ -470,7 +470,7 @@ export const initParamsDefault = (
|
||||
if (!obj[keyDefault]) {
|
||||
obj[keyDefault] = '';
|
||||
}
|
||||
// bot非引用+必填+local默认值为空+不可见,是异常场景,需手动拨正
|
||||
// bot non-reference + required + local default value is empty + invisible, it is an abnormal scene and needs to be manually dialed
|
||||
const isUnusual =
|
||||
obj.default_param_source === DefaultParamSource.Input &&
|
||||
keyDefault === 'local_default' &&
|
||||
@@ -529,7 +529,7 @@ export const transformArrayToTree = (array, template: Array<APIParameter>) => {
|
||||
|
||||
const createSubTree = (arrItem: any, tem: any) => {
|
||||
let subTree: APIParameter & { value?: unknown } = {};
|
||||
// 数组
|
||||
// array
|
||||
if (Array.isArray(arrItem)) {
|
||||
subTree = {
|
||||
...tem,
|
||||
@@ -593,7 +593,7 @@ export const transformParamsToTree = (params: Array<APIParameter>) => {
|
||||
result[i].sub_parameters = tree;
|
||||
}
|
||||
} else {
|
||||
// 对象嵌数组有问题 被覆盖了 需要重置
|
||||
// There is a problem with the object embedded array, it is overwritten and needs to be reset.
|
||||
result[i].sub_parameters = transformParamsToTree(
|
||||
result[i].sub_parameters || [],
|
||||
);
|
||||
@@ -601,7 +601,7 @@ export const transformParamsToTree = (params: Array<APIParameter>) => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// data 额外加工 / 如果本身没有 global_default === undefined 就设置 global_disable 也是 undefined,最后将所有的 global_default 设置成 undefined
|
||||
// Data extra processing/If there is no global_default === undefined, set global_disable is also undefined, and finally set all global_default to undefined
|
||||
export const doRemoveDefaultFromResponseParams = (
|
||||
data: APIParameter[],
|
||||
hasRequired = false,
|
||||
|
||||
@@ -33,7 +33,7 @@ export const typesConfig = {
|
||||
boolean: ParameterType.Bool,
|
||||
};
|
||||
|
||||
// tool 数据回显用
|
||||
// Tool data recall
|
||||
interface ExampleReqParamsType {
|
||||
[key: string]: string | number | null | object | boolean;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export const setEditToolExampleValue = (
|
||||
setDefault(requestParams, exampleReqParams);
|
||||
};
|
||||
|
||||
// 重置 type is_required sub_parameters
|
||||
// Resettype is_required sub_parameters
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
export const resetWorkflowKey = currentTarget => {
|
||||
if (Array.isArray(currentTarget)) {
|
||||
@@ -125,7 +125,7 @@ export const resetStoreKey = currentTarget => {
|
||||
currentTarget.local_disable = false;
|
||||
currentTarget.location = undefined;
|
||||
currentTarget.id = nanoid();
|
||||
// store 那边是 sub_params 字段 个人 的是 sub_parameters
|
||||
// The store over there is sub_params field, personal, sub_parameters
|
||||
if (!('sub_parameters' in currentTarget)) {
|
||||
currentTarget.sub_parameters = [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user