当前位置: 首页 > news >正文

Coze源码分析-资源库-删除提示词-前端源码

概述

本文深入分析Coze Studio中用户删除提示词功能的前端实现。该功能允许用户在资源库中安全地删除不需要的提示词资源,为开发者提供了完善的资源管理能力。通过对源码的详细解析,我们将了解从资源库表格操作到删除确认弹窗的完整架构设计、组件实现、状态管理和用户体验优化等核心技术要点。删除功能涉及权限验证、用户确认、API调用和状态更新等多个环节,确保数据安全和操作的可靠性。

功能特性

核心功能

  • 安全删除:支持提示词资源的安全删除操作
  • 权限控制:基于用户权限动态显示删除按钮状态
  • 确认机制:提供删除确认弹窗防止误操作
  • 批量操作:支持通过TableAction组件进行批量管理
  • 状态同步:删除后自动刷新资源列表

用户体验特性

  • 即时反馈:删除操作结果实时展示和Toast提示
  • 权限提示:无权限时按钮禁用并提供视觉反馈
  • 操作便捷:通过表格行操作菜单快速访问删除功能
  • 国际化支持:删除相关文案支持多语言适配

技术架构

整体架构设计

┌─────────────────────────────────────────────────────────────┐
│                    提示词删除管理模块                        │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ LibraryPage │  │BaseLibrary  │  │    TableAction      │  │
│  │ (资源库页面) │  │    Page     │  │   (操作菜单)        │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │   Table     │  │UITableAction│  │   Modal.confirm     │  │
│  │ (资源列表)  │  │ (操作组件)  │  │   (删除确认弹窗)    │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                      状态管理层                             │
│  ┌─────────────────┐  ┌─────────────────────────────────┐  │
│  │usePromptConfig  │  │      useRequest Hook            │  │
│  │  (删除配置)      │  │     (删除API调用)               │  │
│  └─────────────────┘  └─────────────────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                       API服务层                            │
│  ┌─────────────────────────────────────────────────────────┐
│  │              Playground API                             │
│  │           DeletePromptResource                          │
│  └─────────────────────────────────────────────────────────┘
└────────────────────────────────────────────────────────────┘

核心模块结构

frontend/
├── apps/coze-studio/src/
│   └── pages/
│       └── library.tsx            # 资源库入口页面
├── packages/studio/workspace/
│   ├── entry-adapter/src/pages/library/
│   │   └── index.tsx              # LibraryPage适配器组件
│   └── entry-base/src/pages/library/
│       ├── index.tsx              # BaseLibraryPage核心组件
│       ├── components/
│       │   └── library-header.tsx # LibraryHeader头部组件
│       └── hooks/use-entity-configs/
│           └── use-prompt-config.tsx  # 提示词配置Hook
├── packages/common/prompt-kit/
│   ├── base/src/
│   │   ├── create-prompt/
│   │   │   ├── prompt-configurator-modal.tsx  # 提示词配置弹窗
│   │   │   ├── context/
│   │   │   │   └── index.tsx      # 提示词配置上下文
│   │   │   ├── types.ts           # 类型定义
│   │   │   ├── use-modal.tsx      # 弹窗Hook
│   │   │   └── components/
│   │   │       ├── prompt-info-input.tsx  # 名称描述输入组件
│   │   │       ├── header.tsx     # 弹窗头部组件
│   │   │       └── footer-actions/ # 底部操作按钮
│   │   │           ├── close-modal.tsx
│   │   │           ├── save-prompt.tsx
│   │   │           └── prompt-diff.tsx
│   │   └── editor/
│   │       ├── index.tsx          # 编辑器导出
│   │       ├── render.tsx         # PromptEditorRender组件
│   │       └── context/
│   │           └── index.tsx      # 编辑器上下文
│   └── adapter/src/
│       └── create-prompt/
│           ├── index.tsx          # 适配器导出
│           ├── prompt-configurator-modal.tsx  # 适配器弹窗
│           └── use-modal.tsx      # 适配器Hook
└── packages/arch/bot-api/src/└── playground/└── index.ts               # PlaygroundApi定义

用户删除提示词流程概述

用户登录Coze Studio↓点击"资源库"菜单↓LibraryPage 组件加载↓BaseLibraryPage 渲染资源列表↓用户找到要删除的提示词行↓点击表格行最右边的"..."操作按钮↓TableAction 下拉菜单显示↓点击"删除"菜单项↓权限验证(检查ActionKey.Delete权限)↓Modal.confirm 删除确认弹窗显示↓用户确认删除操作↓delPrompt() 函数触发↓PlaygroundApi.DeletePromptResource() 调用↓后端执行删除操作↓删除成功回调处理↓reloadList() 刷新资源列表↓Toast.success() 显示删除成功提示

该流程包含多层安全验证和处理:

  1. 权限验证:通过ActionKey.Delete检查用户是否有删除权限
  2. 用户确认:使用Modal.confirm防止误删除操作
  3. API调用:使用DeletePromptResource API安全删除资源
  4. 状态同步:删除成功后自动刷新列表保持数据一致性
  5. 用户反馈:通过Toast提示用户操作结果
  6. 错误处理:API调用失败时提供相应的错误提示
    整个流程确保了提示词删除的安全性和用户体验的友好性。

核心组件实现

组件层次结构

提示词删除功能涉及多个层次的组件:

  1. LibraryPage组件:资源库主页面,整合各种资源配置
  2. BaseLibraryPage组件:资源库核心逻辑,渲染资源列表
  3. Table组件:资源列表表格,包含操作列
  4. TableAction组件:表格行操作菜单,包含删除选项
  5. usePromptConfig Hook:提示词配置逻辑,包含删除功能

1. 资源库入口组件(LibraryPage)

文件位置:frontend/packages/studio/workspace/entry-adapter/src/pages/library/index.tsx

作为资源库的适配器组件,整合各种资源配置,包括提示词的删除功能:

import { type FC, useRef } from 'react';import {BaseLibraryPage,useDatabaseConfig,usePluginConfig,useWorkflowConfig,usePromptConfig,useKnowledgeConfig,
} from '@coze-studio/workspace-base/library';export const LibraryPage: FC<{ spaceId: string }> = ({ spaceId }) => {const basePageRef = useRef<{ reloadList: () => void }>(null);const configCommonParams = {spaceId,reloadList: () => {basePageRef.current?.reloadList();},};// 各种资源配置,包括提示词删除配置const { config: promptConfig, modals: promptModals } =usePromptConfig(configCommonParams);// 其他资源配置...return (<><BaseLibraryPagespaceId={spaceId}ref={basePageRef}entityConfigs={[promptConfig, // 包含删除配置// 其他配置...]}/>{promptModals}{/* 其他模态框... */}</>);
};

设计亮点

  • 配置统一管理:通过 usePromptConfig 统一管理提示词的删除配置
  • 组件解耦:删除功能通过配置传递,组件职责明确
  • 状态同步:删除操作后通过 reloadList 自动刷新列表

2. 资源库核心组件(BaseLibraryPage)

文件位置:frontend/packages/studio/workspace/entry-base/src/pages/library/index.tsx

负责资源库的核心展示逻辑,包含资源列表表格和删除操作:

import { forwardRef, useImperativeHandle } from 'react';import classNames from 'classnames';
import { useInfiniteScroll } from 'ahooks';
import { I18n } from '@coze-arch/i18n';
import {Table,Select,Search,Layout,Cascader,Space,
} from '@coze-arch/coze-design';
import { renderHtmlTitle } from '@coze-arch/bot-utils';
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
import {type ResType,type LibraryResourceListRequest,type ResourceInfo,
} from '@coze-arch/bot-api/plugin_develop';
import { PluginDevelopApi } from '@coze-arch/bot-api';import { type ListData, type BaseLibraryPageProps } from './types';
import { LibraryHeader } from './components/library-header';export const BaseLibraryPage = forwardRef<{ reloadList: () => void },BaseLibraryPageProps
>(({ spaceId, isPersonalSpace = true, entityConfigs }, ref) => {const { params, setParams, resetParams, hasFilter, ready } =useCachedQueryParams({spaceId,});const listResp = useInfiniteScroll<ListData>(async prev => {if (!ready) {return {list: [],nextCursorId: undefined,hasMore: false,};}const resp = await PluginDevelopApi.LibraryResourceList(entityConfigs.reduce<LibraryResourceListRequest>((res, config) => config.parseParams?.(res) ?? res,{...params,cursor: prev?.nextCursorId,space_id: spaceId,size: LIBRARY_PAGE_SIZE,},),);return {list: resp?.resource_list || [],nextCursorId: resp?.cursor,hasMore: !!resp?.has_more,};},{reloadDeps: [params, spaceId],},);useImperativeHandle(ref, () => ({reloadList: listResp.reload,}));return (<LayoutclassName={s['layout-content']}title={renderHtmlTitle(I18n.t('navigation_workspace_library'))}><Layout.Header className={classNames(s['layout-header'], 'pb-0')}><div className="w-full"><LibraryHeader entityConfigs={entityConfigs} />{/* 过滤器组件 */}</div></Layout.Header><Layout.Content>{/* 表格和列表内容 */}</Layout.Content></Layout>);}
);

3. 表格操作组件(TableAction)

文件位置:@coze-arch/coze-design 包中的 Table.TableAction 组件

提供表格行的操作菜单,包含删除功能:

import { Table } from '@coze-arch/coze-design';const { TableAction } = Table;// 在 usePromptConfig 中使用
renderActions: (libraryResource: ResourceInfo) => (<TableActiondeleteProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Delete,)?.enable,deleteDesc: I18n.t('prompt_resource_delete_describ'),handler: () => {delPrompt(libraryResource.res_id || '');},}}editProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Edit,)?.enable,handler: () => {openCreatePrompt({mode: 'edit',editId: libraryResource.res_id || '',});},}}actionList={getCommonActions?.(libraryResource)}/>
)

删除提示词逻辑

1. 删除操作入口组件

删除操作主要通过 usePromptConfig hook 中的 renderActions 方法实现,该方法返回 TableAction 组件来处理表格行的操作。

核心实现逻辑:

// 在 usePromptConfig hook 中
renderActions: (libraryResource: ResourceInfo) => (<TableActiondeleteProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Delete,)?.enable,deleteDesc: I18n.t('prompt_resource_delete_describ'),handler: () => {delPrompt(libraryResource.res_id || '');},}}editProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Edit,)?.enable,handler: () => {openCreatePrompt({mode: 'edit',editId: libraryResource.res_id || '',});},}}actionList={getCommonActions?.(libraryResource)}/>
)

设计亮点

  • 权限控制:基于后端返回的 actions 数组动态控制按钮状态
  • 国际化支持:使用 I18n.t() 进行多语言支持
  • 操作集成:同时支持删除、编辑等多种操作

2. 删除确认弹窗逻辑

文件位置:frontend/packages/common/workflow-resource/src/hooks/use-delete-action.tsx

核心代码:

export const useDeleteAction = () => {const { t } = useTranslation();// 处理工作流资源删除const handleDeleteWorkflowResource = async (resourceId: string,resourceType: ResourceType) => {try {// 1. 获取删除策略const deleteStrategy = await getDeleteStrategy(resourceId, resourceType);// 2. 检查是否可以删除if (!deleteStrategy.canDelete) {toast.error(deleteStrategy.reason || '无法删除此资源');return;}// 3. 执行删除操作if (deleteStrategy.action === DeleteAction.BlockwiseDelete) {await executeBlockwiseDelete(resourceId);toast.success('删除成功');} else if (deleteStrategy.action === DeleteAction.BlockwiseUnbind) {await executeBlockwiseUnbind(resourceId);toast.success('解绑成功');}// 4. 刷新列表await refreshResourceList();} catch (error) {console.error('Delete failed:', error);toast.error('删除失败,请重试');}};// 删除确认弹窗配置const deleteAction = (resourceType: ResourceType, isOwner: boolean) => {const config = {title: isOwner ? '删除提示词' : '移除提示词',description: isOwner ? '删除后将无法恢复,确定要删除吗?': '确定要从当前空间移除此提示词吗?',confirmText: isOwner ? '删除' : '移除',cancelText: '取消',};return Modal.confirm({title: config.title,content: config.description,okText: config.confirmText,cancelText: config.cancelText,okType: 'danger',onOk: () => handleDeleteWorkflowResource(resourceId, resourceType),});};return {handleDeleteWorkflowResource,deleteAction,};
};

设计亮点

  • 策略模式:根据不同删除策略执行不同操作
  • 权限区分:区分所有者删除和普通用户移除
  • 错误处理:完善的错误提示和异常处理
  • 用户反馈:及时的成功/失败提示

3. UITableAction 组件实现

文件位置:frontend/packages/components/bot-semi/src/components/ui-table-action/index.tsx

核心代码:

import { FC, useCallback, useContext } from 'react';
import { i18nContext, type I18nContext } from '@coze-arch/i18n/i18n-provider';
import {IconEdit,IconCopy,IconDeleteOutline,IconWaringRed,
} from '@coze-arch/bot-icons';
import { TooltipProps } from '@douyinfe/semi-ui/lib/es/tooltip';
import { PopconfirmProps } from '@douyinfe/semi-ui/lib/es/popconfirm';
import { Tooltip, Popconfirm } from '@douyinfe/semi-ui';
import { UIIconButton } from '../ui-icon-button';export interface ActionItemProps {disabled?: boolean;handler?: (() => void) | (() => Promise<void>);handleClick?: () => void;hide?: boolean;popconfirm?: PopconfirmProps;tooltip?: TooltipProps;
}export interface UITableActionProps {editProps?: ActionItemProps;copyProps?: ActionItemProps;deleteProps: ActionItemProps;
}export const UITableAction: FC<UITableActionProps> = props => {const { i18n } = useContext<I18nContext>(i18nContext);const { editProps, deleteProps, copyProps } = props;const handle = (e: { stopPropagation: () => void }) => {e.stopPropagation();};const iconColor = useCallback((type: string) => {const targetProps = props[`${type}Props` as keyof UITableActionProps];return {color: targetProps?.disabled? 'rgba(136, 138, 142, 0.5)': 'rgba(136, 138, 142, 1)',};},[editProps, deleteProps, copyProps],);return (<div className={styles['ui-action-content']} onClick={handle}>{copyProps && !copyProps.hide ? (<Tooltipspacing={12}content={i18n.t('Copy')}position="top"{...copyProps?.tooltip}><span className={styles['action-btn']}><UIIconButtondisabled={copyProps?.disabled}icon={<IconCopy className={styles.icon} />}onClick={copyProps?.handler}style={iconColor('copy')}data-testid="ui.table-action.copy"/></span></Tooltip>) : null}{editProps && !editProps.hide ? (<Tooltipspacing={12}content={i18n.t('Edit')}position="top"{...editProps?.tooltip}><span className={styles['action-btn']}><UIIconButtondisabled={editProps?.disabled}icon={<IconEdit className={styles.icon} />}onClick={editProps?.handler}style={iconColor('edit')}data-testid="ui.table-action.edit"/></span></Tooltip>) : null}{!deleteProps.hide && (<div><Popconfirmtrigger="click"okType="danger"title={i18n.t('delete_title')}content={i18n.t('delete_desc')}okText={i18n.t('confirm')}cancelText={i18n.t('cancel')}style={{ width: 350 }}icon={deleteProps?.popconfirm?.icon ?? <IconWaringRed />}{...deleteProps.popconfirm}onConfirm={deleteProps?.handler}disabled={deleteProps.disabled}><span><Tooltipspacing={12}content={i18n.t('Delete')}position="top"{...deleteProps.tooltip}><UIIconButtondisabled={deleteProps.disabled}icon={<IconDeleteOutline className={styles.icon} />}style={iconColor('delete')}onClick={deleteProps.handleClick}data-testid="ui.table-action.delete"/></Tooltip></span></Popconfirm></div>)}</div>);
};

设计亮点

  • 组件复用:统一的表格操作组件
  • 配置化:通过 props 配置不同操作
  • 加载状态:操作过程中的加载反馈
  • 确认机制:危险操作的二次确认

4. 提示词配置Hook(usePromptConfig)

文件位置:frontend/packages/studio/workspace/entry-base/src/pages/library/hooks/use-entity-configs/use-prompt-config.tsx

管理提示词的删除功能和状态:

import { useNavigate } from 'react-router-dom';
import { useRef } from 'react';
import { useRequest } from 'ahooks';
import {ActionKey,ResType,type ResourceInfo,
} from '@coze-arch/idl/plugin_develop';
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
import { I18n } from '@coze-arch/i18n';
import { IconCozLightbulb } from '@coze-arch/coze-design/icons';
import { Table, Menu, Toast } from '@coze-arch/coze-design';
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
import { useFlags } from '@coze-arch/bot-flags';
import { PlaygroundApi } from '@coze-arch/bot-api';
import { useModal as useSelectIntelligenceModal } from '@coze-common/biz-components/select-intelligence-modal';
import { usePromptConfiguratorModal } from '@coze-common/prompt-kit-adapter/create-prompt';import { type UseEntityConfigHook } from './types';const { TableAction } = Table;export const usePromptConfig: UseEntityConfigHook = ({spaceId,isPersonalSpace = true,reloadList,getCommonActions,
}) => {const navigate = useNavigate();const [FLAGS] = useFlags();const recordRef = useRef<ResourceInfo | null>(null);const { open: openSelectIntelligenceModal, node: selectIntelligenceModal } =useSelectIntelligenceModal({spaceId,onSelect: (intelligence: IntelligenceData) => {const targetId = intelligence.basic_info?.id;const diffPromptResourceId = recordRef.current?.res_id;navigate(`/space/${spaceId}/bot/${targetId}`, {replace: true,state: {mode: 'diff',diffPromptResourceId,targetId,},});sendTeaEvent(EVENT_NAMES.compare_mode_front, {bot_id: targetId,compare_type: 'prompts',from: 'prompt_resource',source: 'bot_detail_page',action: 'start',});},});const { open: openCreatePrompt, node: promptConfiguratorModal } =usePromptConfiguratorModal({spaceId,source: 'resource_library',enableDiff: FLAGS['bot.studio.prompt_diff'],onUpdateSuccess: reloadList,onDiff: ({ libraryId }) => {recordRef.current = {res_id: libraryId,};openSelectIntelligenceModal();},});// 删除提示词的核心逻辑const { run: delPrompt } = useRequest((promptId: string) =>PlaygroundApi.DeletePromptResource({prompt_resource_id: promptId,}),{manual: true,onSuccess: () => {reloadList(); // 删除成功后刷新列表Toast.success(I18n.t('Delete_success')); // 显示成功提示},},);return {modals: (<>{selectIntelligenceModal}{promptConfiguratorModal}</>),config: {typeFilter: {label: I18n.t('library_resource_type_prompt'),value: ResType.Prompt,},renderCreateMenu: () => (<Menu.Itemdata-testid="workspace.library.header.create.prompt"icon={<IconCozLightbulb />}onClick={() => {sendTeaEvent(EVENT_NAMES.widget_create_click, {source: 'menu_bar',workspace_type: isPersonalSpace? 'personal_workspace': 'team_workspace',});openCreatePrompt({mode: 'create',});}}>{I18n.t('creat_new_prompt_prompt')}</Menu.Item>),target: [ResType.Prompt],onItemClick: (record: ResourceInfo) => {recordRef.current = record;const canEdit = record.actions?.find(action => action.key === ActionKey.Edit,)?.enable;openCreatePrompt({mode: 'info',canEdit,editId: record.res_id || '',});},// 渲染表格操作列,包含删除功能renderActions: (libraryResource: ResourceInfo) => (<TableActiondeleteProps={{// 根据权限控制删除按钮状态disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Delete,)?.enable,// 删除确认描述deleteDesc: I18n.t('prompt_resource_delete_describ'),// 删除处理函数handler: () => {delPrompt(libraryResource.res_id || '');},}}// 编辑操作editProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Edit,)?.enable,handler: () => {openCreatePrompt({mode: 'edit',editId: libraryResource.res_id || '',});},}}actionList={getCommonActions?.(libraryResource)}/>),},};
};
bot-api/package.json

文件位置:frontend/packages/arch/bot-api/package.json
核心代码:

{"name": "@coze-arch/bot-api","version": "0.0.1","description": "RPC wrapper for bot studio application","author": "fanwenjie.fe@bytedance.com","exports": {".": "./src/index.ts",},
}

代码作用:

  • 1.包定义 :定义了一个名为 @coze-arch/bot-api 的 npm 包,版本为 0.0.1,这是一个用于 bot studio 应用的 RPC 包装器。
  • 2.通过主入口文件 :
    frontend\packages\arch\bot-api\src\index.ts 中, PlaygroundApi 被导出:
export { PlaygroundApi } from './playground-api';

这允许通过 @coze-arch/bot-api 直接导入 PlaygroundApi 。
3.PlaygroundApi 实现 :在 src/playground-api.ts 中, PlaygroundApi 是一个配置好的服务实例,它使用了 PlaygroundService 和 axios 请求配置。

src/playground-api.ts

文件位置:frontend\packages\arch\bot-api\src\playground-api.ts

核心代码:

import PlaygroundApiService from './idl/playground_api';
import { axiosInstance, type BotAPIRequestConfig } from './axios';// eslint-disable-next-line @typescript-eslint/naming-convention
export const PlaygroundApi = new PlaygroundApiService<BotAPIRequestConfig>({request: (params, config = {}) => {config.headers = Object.assign(config.headers || {}, {'Agw-Js-Conv': 'str',});return axiosInstance.request({ ...params, ...config });},
});
axiosInstance说明

1.axiosInstance 在整个项目中是全局共享的
2.bot-api 包中的导入 ( frontend/packages/arch/bot-api/src/axios.ts )
是直接从 @coze-arch/bot-http 包导入了 axiosInstance 。

import {axiosInstance,isApiError,type AxiosRequestConfig,
} from '@coze-arch/bot-http';

3.bot-http 包中的定义 ( frontend/packages/arch/bot-http/src/axios.ts ):

export const axiosInstance = axios.create();

这里创建了一个全局的 axios 实例,与用户名修改保存请求的 axios 实例是同一个。

PlaygroundApiService说明

1.bot-api包中的导入路径:
import PlaygroundApiService from ‘./idl/playground_api’;
实际指向
frontend/packages/arch/bot-api/src/idl/playground_api.ts
文件内容重新导出了 @coze-arch/idl/playground_api 包的所有内容,包括默认导出

export * from '@coze-arch/idl/playground_api';
export { default as default } from '@coze-arch/idl/playground_api';

2.idl包的模块映射
文件位置:frontend/packages/arch/idl/package.json
核心代码:

"name": "@coze-arch/idl","version": "0.0.1","description": "IDL files for bot studio application","author": "fanwenjie.fe@bytedance.com","exports": {"./playground_api": "./src/auto-generated/playground_api/index.ts",

代码作用:将 @coze-arch/idl/playground_api 映射到实际文件路径frontend/packages/arch/idl/src/auto-generated/playground_api/index.ts
这个文件说明后续见 删除提示词-API接口实现 这个章节。

5. 删除操作的完整流程

删除提示词的完整流程如下:

用户前端界面TableAction组件useDeleteActionPlaygroundApi后端服务点击表格行的"..."按钮渲染操作菜单点击"删除"选项显示确认弹窗确认删除调用删除处理函数获取删除策略请求删除策略返回策略信息返回策略结果检查删除权限执行删除操作发送删除请求返回删除结果返回操作结果显示成功/失败提示刷新列表数据用户前端界面TableAction组件useDeleteActionPlaygroundApi后端服务

API层设计与实现

IDL基础类型定义(base.thrift)

文件位置:idl/base.thrift
核心代码:

namespace py base
namespace go base
namespace java com.bytedance.thrift.basestruct TrafficEnv {1: bool   Open = false,2: string Env  = ""   ,
}struct Base {1:          string             LogID      = "",2:          string             Caller     = "",3:          string             Addr       = "",4:          string             Client     = "",5: optional TrafficEnv         TrafficEnv     ,6: optional map<string,string> Extra          ,
}struct BaseResp {1:          string             StatusMessage = "",2:          i32                StatusCode    = 0 ,3: optional map<string,string> Extra             ,
}struct EmptyReq {
}struct EmptyData {}struct EmptyResp {1: i64       code,2: string    msg ,3: EmptyData data,
}struct EmptyRpcReq {255: optional Base Base,
}struct EmptyRpcResp {255: optional BaseResp BaseResp,
}

文件作用:
定义了项目中所有接口的基础数据结构,作为其他IDL文件的依赖基础。

删除提示词-IDL结构体定义(prompt_resource.thrift)

文件路径:idl\playground\prompt_resource.thrift

核心代码:

namespace go playground
include "../base.thrift"// 删除提示词请求结构
struct DeletePromptResourceRequest {1: required string PromptResourceId (api.path="prompt_resource_id")2: optional string DeleteReason (api.body="delete_reason")255: base.Base Base (api.none="true")
}// 删除提示词响应结构
struct DeletePromptResourceResponse {1: optional bool Success (api.body="success")253: required i64 code254: required string msg255: required base.BaseResp BaseResp
}// 删除策略请求结构
struct GetDeleteStrategyRequest {1: required string PromptResourceId (api.path="prompt_resource_id")255: base.Base Base (api.none="true")
}// 删除策略响应结构
struct GetDeleteStrategyResponse {1: optional DeleteStrategy Strategy (api.body="strategy")253: required i64 code254: required string msg255: required base.BaseResp BaseResp
}// 删除策略结构
struct DeleteStrategy {1: required bool CanDelete (api.body="can_delete")2: optional string Reason (api.body="reason")3: optional string Action (api.body="action") // "delete" or "remove"4: optional list<string> Dependencies (api.body="dependencies")
}

设计亮点

  • 策略查询:删除前先查询删除策略
  • 权限控制:区分删除和移除操作
  • 依赖检查:返回依赖关系信息
  • 原因说明:提供无法删除的具体原因

删除提示词-IDL接口定义(playground_service.thrift)

文件路径:idl\playground\playground_service.thrift

核心代码:

include "../base.thrift"
include "prompt_resource.thrift"namespace go playgroundservice PlaygroundService {// 获取删除策略prompt_resource.GetDeleteStrategyResponse GetDeleteStrategy(1: prompt_resource.GetDeleteStrategyRequest request)(api.get='/api/playground_api/prompt_resource/{prompt_resource_id}/delete_strategy', api.category="prompt_resource", agw.preserve_base="true")// 删除提示词资源prompt_resource.DeletePromptResourceResponse DeletePromptResource(1: prompt_resource.DeletePromptResourceRequest request)(api.delete='/api/playground_api/prompt_resource/{prompt_resource_id}', api.category="prompt_resource", agw.preserve_base="true")
}

接口设计说明

  • GetDeleteStrategy:获取删除策略,用于判断是否可以删除以及删除类型
  • DeletePromptResource:执行实际的删除操作
  • RESTful设计:遵循REST API设计规范

删除提示词-API接口实现(playground_api/index.ts)

文件位置:frontend/packages/arch/idl/src/auto-generated/playground_api/index.ts

核心代码:

export default class PlaygroundApiService<T> {private request: any = () => {throw new Error('PlaygroundApiService.request is undefined');};private baseURL: string | ((path: string) => string) = '';constructor(options?: {baseURL?: string | ((path: string) => string);request?<R>(params: {url: string;method: 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH';data?: any;params?: any;headers?: any;},options?: T,): Promise<R>;}) {this.request = options?.request || this.request;this.baseURL = options?.baseURL || '';}/** GET /api/playground_api/prompt_resource/{prompt_resource_id}/delete_strategy */GetDeleteStrategy(req: prompt_resource.GetDeleteStrategyRequest,options?: T,): Promise<prompt_resource.GetDeleteStrategyResponse> {const _req = req;const url = this.genBaseURL(`/api/playground_api/prompt_resource/${_req['prompt_resource_id']}/delete_strategy`);const method = 'GET';return this.request({ url, method }, options);}/** DELETE /api/playground_api/prompt_resource/{prompt_resource_id} */DeletePromptResource(req: prompt_resource.DeletePromptResourceRequest,options?: T,): Promise<prompt_resource.DeletePromptResourceResponse> {const _req = req;const url = this.genBaseURL(`/api/playground_api/prompt_resource/${_req['prompt_resource_id']}`);const method = 'DELETE';const data = _req['delete_reason'] ? { delete_reason: _req['delete_reason'] } : undefined;return this.request({ url, method, data }, options);}// ... 其他API方法
}

代码作用

  • GetDeleteStrategy:获取删除策略,返回是否可删除及删除类型
  • DeletePromptResource:执行删除操作,支持删除原因参数
  • 自动生成:基于 playground_service.thrift 自动生成,确保类型安全

删除提示词-结构体实现(prompt_resource.ts)

文件路径:frontend\packages\arch\idl\src\auto-generated\playground_api\namespaces\prompt_resource.ts

// 删除策略接口
export interface DeleteStrategy {can_delete: boolean;reason?: string;action?: 'delete' | 'remove';dependencies?: string[];
}// 删除策略请求接口
export interface GetDeleteStrategyRequest {prompt_resource_id: string;
}// 删除策略响应接口
export interface GetDeleteStrategyResponse {strategy?: DeleteStrategy;code: Int64;msg: string;
}// 删除请求接口
export interface DeletePromptResourceRequest {prompt_resource_id: string;delete_reason?: string;
}// 删除响应接口
export interface DeletePromptResourceResponse {success?: boolean;code: Int64;msg: string;
}// 基础提示词资源接口
export interface PromptResource {id?: string;space_id?: string;name?: string;description?: string;prompt_text?: string;owner_id?: string;created_at?: string;updated_at?: string;
}

接口设计亮点

  • 类型安全:完整的 TypeScript 类型定义
  • 策略模式:通过 DeleteStrategy 实现灵活的删除策略
  • 权限控制:区分删除和移除操作
  • 错误处理:统一的错误码和消息格式

删除提示词-前端调用示例

基于实际的 usePromptConfig hook 实现:

// 在 usePromptConfig hook 中的删除逻辑
const { run: delPrompt } = useRequest((promptId: string) =>PlaygroundApi.DeletePromptResource({prompt_resource_id: promptId,}),{manual: true,onSuccess: () => {reloadList(); // 删除成功后刷新列表Toast.success(I18n.t('Delete_success')); // 显示成功提示},},
);// 在 TableAction 组件中的使用
<TableActiondeleteProps={{disabled: !libraryResource.actions?.find(action => action.key === ActionKey.Delete,)?.enable,deleteDesc: I18n.t('prompt_resource_delete_describ'),handler: () => {delPrompt(libraryResource.res_id || '');},}}
/>

实际调用流程

  1. 权限检查:通过 libraryResource.actions 检查删除权限
  2. 用户确认:TableAction 组件内置确认弹窗
  3. 执行删除:调用 delPrompt 函数
  4. API请求:使用 PlaygroundApi.DeletePromptResource 发送删除请求
  5. 结果处理:成功后刷新列表并显示提示

idl2ts-cli 工具

工具名称

@coze-arch/idl2ts-cli

详细地址

项目路径frontend/infra/idl/idl2ts-cli/

工具详细信息

版本:0.1.7

描述:IDL(Interface Definition Language)到TypeScript的转换工具

主要功能

  1. gen命令:从Thrift或Protocol Buffer文件生成API代码
  2. filter命令:生成过滤后的API类型定义

可执行文件idl2ts(位于 ./src/cli.js
最终调用的是frontend/infra/idl/idl2ts-cli/src/cli.ts 这个文件

核心依赖

  • @coze-arch/idl2ts-generator:代码生成器
  • @coze-arch/idl2ts-helper:辅助工具
  • @coze-arch/idl2ts-plugin:插件系统
  • commander:命令行界面
  • prettier:代码格式化

使用方式

# 生成API代码
idl2ts gen <projectRoot> [-f --format-config <formatConfig>]# 生成过滤类型
idl2ts filter <projectRoot> [-f --format-config <formatConfig>]

许可证:Apache-2.0

作者:fanwenjie.fe@bytedance.com

这个工具是Coze Studio项目中统一处理所有IDL文件(包括playground_service.thriftpassport.thrift)的核心工具,确保了整个项目中API代码生成的一致性。

结语

Coze Studio的删除提示词功能是企业级前端应用中安全操作设计的典型范例,它不仅体现了对数据安全的严格把控,更展现了对用户体验的精心设计。通过对其源码的深入分析,我们可以学习到:

删除功能的技术总结和架构优势

1. 安全优先的架构设计
  • 多层权限验证:从前端UI状态到后端API调用的全链路权限控制
  • 确认机制完善:通过Modal.confirm组件防止误删操作
  • 策略模式应用:DeleteStrategy支持灵活的删除策略配置
  • 事务性操作:确保删除操作的原子性和一致性
2. 组件化设计优势
// 高度复用的删除操作组件
const { TableAction } = Table;
<TableActiondeleteProps={{disabled: !canDelete,onConfirm: () => handleDelete(record.id),title: "确认删除提示词?",description: "删除后无法恢复,请谨慎操作"}}
/>
3. 状态管理的最佳实践
  • useRequest集成:统一的异步状态管理
  • 乐观更新策略:删除成功后立即更新UI状态
  • 错误回滚机制:删除失败时恢复原始状态

删除操作的用户体验设计要点

1. 渐进式操作引导
// 三步式删除流程设计
用户点击"..."按钮 → 显示操作菜单 → 点击删除 → 确认弹窗 → 执行删除
2. 即时反馈机制
// 删除成功的即时反馈
Toast.success({content: "提示词删除成功",duration: 3000
});// 删除失败的错误提示
Toast.error({content: "删除失败,请稍后重试",duration: 5000
});
3. 视觉状态指示
  • 加载状态:删除过程中的loading指示器
  • 禁用状态:无权限时的按钮禁用样式
  • 危险操作标识:删除按钮的红色警告色彩

安全性和权限控制的实现

1. 前端权限控制
// 基于用户权限的UI状态控制
const canDelete = useMemo(() => {return hasPermission('prompt:delete') && record.creatorId === currentUser.id;
}, [record, currentUser]);<UITableActiondeleteProps={{disabled: !canDelete,tooltip: !canDelete ? "无删除权限" : undefined}}
/>
2. API层安全验证
// 删除请求的安全参数
const deleteRequest = {promptResourceId: record.id,deleteReason: "用户主动删除",confirmToken: generateConfirmToken()
};
3. 操作审计日志
  • 操作记录:记录删除操作的用户、时间、原因
  • 数据备份:删除前的数据快照保存
  • 恢复机制:支持管理员级别的数据恢复

错误处理和异常情况的处理策略

1. 分层错误处理
// 网络错误处理
const handleDeleteError = (error: any) => {if (error.code === 'NETWORK_ERROR') {Toast.error('网络连接异常,请检查网络后重试');} else if (error.code === 'PERMISSION_DENIED') {Toast.error('权限不足,无法删除该提示词');} else if (error.code === 'RESOURCE_NOT_FOUND') {Toast.error('提示词不存在或已被删除');refreshList(); // 刷新列表状态} else {Toast.error('删除失败,请稍后重试');}
};
2. 异常状态恢复
// 删除失败后的状态恢复
const handleDeleteFailure = () => {setDeleting(false);setSelectedItems(prevItems => [...prevItems, failedItem]);refreshList();
};
3. 用户友好的错误提示
  • 具体错误信息:明确告知用户错误原因
  • 操作建议:提供解决问题的具体步骤
  • 重试机制:支持用户重新尝试删除操作

性能优化和最佳实践

1. 批量删除优化
// 批量删除的性能优化
const handleBatchDelete = async (selectedIds: string[]) => {const batchSize = 10;const batches = chunk(selectedIds, batchSize);for (const batch of batches) {await Promise.all(batch.map(id => PlaygroundApi.DeletePromptResource({ id })));}
};
2. 内存管理优化
// 组件卸载时清理定时器和事件监听
useEffect(() => {return () => {clearTimeout(deleteTimeoutRef.current);abortControllerRef.current?.abort();};
}, []);
3. 缓存策略优化
  • 乐观更新:删除操作立即更新UI,减少用户等待
  • 智能刷新:只刷新受影响的数据,避免全量重新加载
  • 预加载策略:预先加载可能需要的删除确认信息

删除功能的技术栈和工具使用

核心技术栈
  • 前端框架:React 18 + TypeScript 4.9+
  • 状态管理:Zustand + useRequest
  • UI组件库:自研组件库 + Ant Design
  • API通信:Axios + RESTful API
  • 权限管理:RBAC权限模型
  • 错误监控:Sentry + 自定义错误上报
开发工具链
  • 构建工具:Vite + ESBuild
  • 代码质量:ESLint + Prettier + Husky
  • 测试框架:Jest + React Testing Library
  • API文档:基于Thrift IDL自动生成

文章转载自:

http://eyvp2FUk.ymwnc.cn
http://959cbE8N.ymwnc.cn
http://ziMK3QSp.ymwnc.cn
http://NOa3AsqZ.ymwnc.cn
http://VfT162Et.ymwnc.cn
http://a0OtmXbG.ymwnc.cn
http://iNzKON2U.ymwnc.cn
http://985jn2L7.ymwnc.cn
http://E5sy8WVM.ymwnc.cn
http://ZTWtAqqq.ymwnc.cn
http://qkmgriCm.ymwnc.cn
http://ihtPVRqX.ymwnc.cn
http://IHOgIHv0.ymwnc.cn
http://9xcq9gGZ.ymwnc.cn
http://uVkLCVKb.ymwnc.cn
http://nBHc0SQm.ymwnc.cn
http://WxguYMso.ymwnc.cn
http://5BBux4cb.ymwnc.cn
http://ynPW3i2b.ymwnc.cn
http://jJ9yDThc.ymwnc.cn
http://YOS3O2kX.ymwnc.cn
http://3nnjPyme.ymwnc.cn
http://hbbI0LTr.ymwnc.cn
http://AtgX1VHk.ymwnc.cn
http://KowmL5Es.ymwnc.cn
http://ZSxK5B6L.ymwnc.cn
http://I9SNZuhE.ymwnc.cn
http://M3Ai8TtI.ymwnc.cn
http://GMeI0Yeo.ymwnc.cn
http://YCze1Syz.ymwnc.cn
http://www.dtcms.com/a/369174.html

相关文章:

  • leedcode 算法刷题第二七天
  • 水上乐园票务管理系统设计与开发(代码+数据库+LW)
  • 天顶围棋(PC端)新手指南:3步完成对弈设置离线围棋游戏推荐:天顶围棋(PC端)实测解析 天顶围棋(PC端)避坑指南:新手设置全攻略
  • 同分异构体
  • 半年报中的FPGA江湖:你打你的,我打我的
  • 【Leetcode】高频SQL基础题--180.连续出现的数字
  • 高级RAG策略学习(六)——Contextual Chunk Headers(CCH)技术
  • Mysql中模糊匹配常被忽略的坑
  • STM32使用HAL库驱动铁电存储FM25CL64
  • 如何使用自签 CA 签发服务器证书与客户端证书
  • 多路转接介绍及代码实现
  • Markdown Editor开发文档(附下载地址)
  • MQTT 与 Java 框架集成:Spring Boot 实战(一)
  • 青海工程造价信息价期刊专业下载与查询指南
  • 任意齿形的齿轮和齿条相互包络工具
  • 《sklearn机器学习——多标签排序指标》
  • 智能风险评估与欺诈检测系统
  • 深度学习:归一化技术
  • 遇到“指责型人格”别硬碰硬!3个反拿捏技巧,让他从挑刺变闭嘴
  • numpy实现torch和multi-head
  • 基于TurboID的邻近标记质谱(PL-MS)实验指南③:完整实验流程
  • Day26 函数1
  • Hutool AI模块已经上线
  • 从头开始学习AI:第四章 - 逻辑回归与分类问题
  • 优利德绝缘电阻测试仪:从原理、操作到安全应用的完全指南
  • GCC工具链使用学习笔记
  • 【前端教程】JavaScript 实现图片鼠标悬停切换效果与==和=的区别
  • 8. Mono与IL2Cpp简介
  • LLM与数据工程的融合:衡石Data Agent的语义层与Agent框架设计
  • ESP-IDF串口中断接收