coze-studio/frontend/packages/agent-ide/space-bot/src/hook/tools-publish-back-modal.ts

189 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useCallback, useEffect } from 'react';
import { debounce } from 'lodash-es';
import { withSlardarIdButton } from '@coze-studio/bot-utils';
import { type WorkFlowItemType } from '@coze-studio/bot-detail-store';
import { reporter } from '@coze-arch/logger';
import { I18n } from '@coze-arch/i18n';
import { OpenBlockEvent, emitEvent } from '@coze-arch/bot-utils';
import { useSpaceStore } from '@coze-arch/bot-studio-store';
import { UIModal, UIToast } from '@coze-arch/bot-semi';
import { type SceneResponseType } from '@coze-arch/bot-hooks/src/page-jump';
import {
usePageJumpResponse,
PageType,
SceneType,
OpenModeType,
} from '@coze-arch/bot-hooks';
import { CustomError } from '@coze-arch/bot-error';
import { WorkflowMode } from '@coze-arch/bot-api/workflow_api';
import { PluginType } from '@coze-arch/bot-api/developer_api';
import { PluginDevelopApi } from '@coze-arch/bot-api';
/**
* workflow 发布成功后跳转回 bot 编辑页,弹窗提示是否添加到 bot
*/
export const useWorkflowPublishedModel = ({
flowMode,
addedWorkflows,
onOk,
skipByExternal,
title = I18n.t('PublishSuccessConfirm'),
pageType = PageType.BOT,
}: {
flowMode?: WorkflowMode;
/** 已添加的 workflow若已添加该 workflow 则不弹窗)。为了兼容 single 和 multi 模式,所以由外部传入 */
addedWorkflows: WorkFlowItemType[];
/** 点击确认并查询 workflow 对应的 plugin 成功后的回调,也是为了兼容 single 和 multi 两种模式才由外部传入 */
onOk: (workflow: WorkFlowItemType) => unknown;
/** 允许业务方额外附带禁止弹窗的条件。主要用于 multi 模式 */
skipByExternal?: (
jumpResponse: SceneResponseType<
| SceneType.WORKFLOW_PUBLISHED__BACK__BOT
| SceneType.WORKFLOW_PUBLISHED__BACK__DOUYIN_BOT
| SceneType.WORKFLOW_PUBLISHED__BACK__SOCIAL_SCENE
>,
) => boolean;
title?: string;
pageType?: PageType;
}): void => {
const isImageflow = flowMode === WorkflowMode.Imageflow;
const jumpResponse = usePageJumpResponse(pageType);
// 使用 useCallback 缓存防抖函数,避免 UIModal 弹窗出现多次
const debouncedEffect = useCallback(
debounce(() => {
const isNotWorkflowPublishedBackBot =
jumpResponse?.scene !== SceneType.WORKFLOW_PUBLISHED__BACK__BOT;
const isNotWorkflowPublishedBackSocialScene =
jumpResponse?.scene !==
SceneType.WORKFLOW_PUBLISHED__BACK__SOCIAL_SCENE;
const isOnlyOnceAdd =
(
jumpResponse as SceneResponseType<SceneType.WORKFLOW_PUBLISHED__BACK__BOT>
)?.workflowOpenMode === OpenModeType.OnlyOnceAdd;
const isNotWorkflowPublishedBackDouyinBot =
jumpResponse?.scene !== SceneType.WORKFLOW_PUBLISHED__BACK__DOUYIN_BOT;
if (
(isNotWorkflowPublishedBackBot &&
isNotWorkflowPublishedBackDouyinBot &&
isNotWorkflowPublishedBackSocialScene) ||
isOnlyOnceAdd
) {
// 不是发布跳转的场景,或者是仅添加一次,直接不弹窗
return;
}
// 配置了 flowMode 才判断,否则不进行 flowMode 限制(适配 ChatFlow
if (
typeof flowMode !== 'undefined' &&
(jumpResponse?.flowMode || WorkflowMode.Workflow) !== flowMode
) {
return;
}
if (skipByExternal?.(jumpResponse)) {
return;
}
if (
addedWorkflows.some(
workflow => workflow.workflow_id === jumpResponse.workflowID,
)
) {
// 已经添加过该 workflow 了,不弹窗
return;
}
const { workflowID, pluginID } = jumpResponse;
UIModal.success({
title,
cancelText: I18n.t('Cancel'),
okText: I18n.t('Confirm'),
onCancel: () => jumpResponse.clearScene(true),
onOk: async () => {
try {
const plugin = (
await PluginDevelopApi.GetPlaygroundPluginList({
space_id: useSpaceStore.getState().getSpaceId(),
page: 1,
size: 1,
plugin_ids: [pluginID],
plugin_types: [
isImageflow ? PluginType.IMAGEFLOW : PluginType.WORKFLOW,
],
})
).data?.plugin_list?.[0];
if (!plugin) {
const msg = I18n.t('AddFailedToast');
UIToast.error({
content: withSlardarIdButton(msg),
});
throw new CustomError('normal_error', msg);
}
const workflow: WorkFlowItemType = {
workflow_id: workflowID,
plugin_id: plugin.id || '',
name: plugin.name || '',
desc: plugin.desc_for_human || '',
parameters: plugin.plugin_apis?.at(0)?.parameters ?? [],
plugin_icon: plugin.plugin_icon || '',
flow_mode:
plugin.plugin_type === PluginType.IMAGEFLOW
? WorkflowMode.Imageflow
: (jumpResponse?.flowMode ?? WorkflowMode.Workflow),
};
const onOkResult = onOk(workflow);
const res = await Promise.resolve(onOkResult);
if (res !== false) {
UIToast.success(
I18n.t('AddSuccessToast', { name: plugin.name || workflowID }),
);
emitEvent(
isImageflow
? OpenBlockEvent.IMAGEFLOW_BLOCK_OPEN
: OpenBlockEvent.WORKFLOW_BLOCK_OPEN,
);
}
} catch (e) {
reporter.error({
message: e instanceof Error ? e.message : e?.toString(),
error: e,
});
} finally {
jumpResponse.clearScene(true);
}
},
});
}, 1000),
[], // 空依赖数组
);
useEffect(() => {
debouncedEffect();
// 清理函数
return () => {
debouncedEffect.cancel();
};
}, [debouncedEffect]);
};