chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
@@ -98,7 +98,7 @@ export const MockForm = React.forwardRef(
|
||||
}));
|
||||
useEffect(() => {
|
||||
eventEmitter.on('change', (...args: any[]) => {
|
||||
// 实际上都是假的咯 假设 args 第一个参数是 field 第二个参数是具体 value
|
||||
// In fact, it is all false. Suppose the first argument of args is field and the second argument is a specific value.
|
||||
valuesRef.current[args[0]] = args[1];
|
||||
props.onValueChange(valuesRef.current, args[1]);
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ export const StepFooter: FC = () => {
|
||||
}
|
||||
const res = await callbackResult;
|
||||
|
||||
// 返回 false 则直接 return
|
||||
// If it returns false, it will be returned directly.
|
||||
if (typeof res === 'boolean' && res === false) {
|
||||
setSubmitButtonLoading(false);
|
||||
return;
|
||||
@@ -71,7 +71,7 @@ export const StepFooter: FC = () => {
|
||||
|
||||
// onSubmit
|
||||
try {
|
||||
// 判断传入的 submit 函数如果是异步,则按钮 loading
|
||||
// Determine if the passed submit function is asynchronous, then the button loading
|
||||
const callbackResult = onSubmit?.();
|
||||
if (callbackResult instanceof Promise) {
|
||||
setSubmitButtonLoading(true);
|
||||
@@ -79,10 +79,10 @@ export const StepFooter: FC = () => {
|
||||
await callbackResult;
|
||||
|
||||
if (isLastStep) {
|
||||
//关闭
|
||||
//close
|
||||
onCancel?.();
|
||||
} else {
|
||||
// 下一步
|
||||
// Next step
|
||||
useStepStore.setState(state => ({
|
||||
step: Math.min(state.step + 1, lastStep),
|
||||
}));
|
||||
@@ -95,10 +95,10 @@ export const StepFooter: FC = () => {
|
||||
const handleClickPrev = () => {
|
||||
getCallbacks()?.onPrevious?.();
|
||||
if (isFirstStep) {
|
||||
// 关闭
|
||||
// close
|
||||
onCancel?.();
|
||||
} else {
|
||||
// 上一步
|
||||
// previous step
|
||||
useStepStore.setState(state => ({
|
||||
step: Math.max(state.step - 1, firstStep),
|
||||
}));
|
||||
|
||||
@@ -118,7 +118,7 @@ export const TablePreview: FC = () => {
|
||||
});
|
||||
let res: AddTableResponse;
|
||||
try {
|
||||
// TODO:此需求暂停,后端下线,后续待开放
|
||||
// TODO: This demand is suspended, the backend is offline, and it will be opened later.
|
||||
// res = await DataModelApi.AddTable({
|
||||
// file: {
|
||||
// tos_uri: fileList[0].response.upload_uri,
|
||||
|
||||
@@ -121,7 +121,7 @@ export const TableStructure: FC = () => {
|
||||
|
||||
let res: PreviewTableFileResponse;
|
||||
try {
|
||||
// TODO:此需求暂停,后端下线,后续待开放
|
||||
// TODO: This demand is suspended, the backend is offline, and it will be opened later.
|
||||
// res = await DataModelApi.PreviewTableFile({
|
||||
// file: {
|
||||
// tos_uri: fileList[0].response.upload_uri,
|
||||
@@ -168,7 +168,7 @@ export const TableStructure: FC = () => {
|
||||
}
|
||||
});
|
||||
|
||||
// 上一步保存当前状态
|
||||
// Previous Save the current state
|
||||
onPrevious(() => {
|
||||
const tableBasicValue =
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -265,7 +265,7 @@ export const TableStructure: FC = () => {
|
||||
};
|
||||
|
||||
if (changedKeys.length === 1 && changedKeys.includes('sheetID')) {
|
||||
// FIXME: 此处 semi 有 bug,始终是 override 更新,所以需要也添加上 sheetID 属性
|
||||
// FIXME: There is a bug in semi here, and it is always override update, so you need to add the sheetID attribute as well.
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
excelInfoFormRef.current.formApi.setValues({
|
||||
sheetID: changedValue.sheetID,
|
||||
@@ -274,7 +274,7 @@ export const TableStructure: FC = () => {
|
||||
});
|
||||
}
|
||||
|
||||
// 切换 sheet
|
||||
// Switch sheet
|
||||
if (
|
||||
changedKeys.length === 3 &&
|
||||
changedKeys.includes('headerRow') &&
|
||||
@@ -284,7 +284,7 @@ export const TableStructure: FC = () => {
|
||||
await reloadTableValue({ updateTableName: true });
|
||||
}
|
||||
|
||||
// 仅更新 headerRow
|
||||
// Update headerRow only
|
||||
if (changedKeys.length === 1 && changedKeys.includes('headerRow')) {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
if (changedValue.headerRow >= values.dataStartRow) {
|
||||
@@ -299,7 +299,7 @@ export const TableStructure: FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 仅更新 dataStartRow
|
||||
// Update dataStartRow only
|
||||
if (
|
||||
changedKeys.length === 1 &&
|
||||
changedKeys.includes('dataStartRow')
|
||||
|
||||
@@ -163,7 +163,7 @@ export const Upload: FC = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
// 业务
|
||||
// business
|
||||
const { name, fileInstance } = file;
|
||||
|
||||
if (fileInstance) {
|
||||
@@ -246,7 +246,7 @@ export const Upload: FC = () => {
|
||||
setCurrentState({
|
||||
fileList: fileList.filter((f, i) => index !== i),
|
||||
});
|
||||
// reset 配置
|
||||
// Reset configuration
|
||||
setTableStructure({
|
||||
excelBasicInfo: undefined,
|
||||
excelValue: undefined,
|
||||
@@ -380,7 +380,7 @@ export const Upload: FC = () => {
|
||||
style={{
|
||||
height: '100%',
|
||||
/**
|
||||
* NOTE: 此处采取 css 隐藏是为了保持 upload 过程,否则会取消上传
|
||||
* NOTE: css hiding is taken here to keep the upload process, otherwise the upload will be cancelled
|
||||
*/
|
||||
...(fileList.length > 0
|
||||
? {
|
||||
@@ -395,8 +395,8 @@ export const Upload: FC = () => {
|
||||
});
|
||||
}}
|
||||
beforeUpload={fileInfo => {
|
||||
// 不通过 maxSize 属性来限制的原因是
|
||||
// 只有 beforeUpload 钩子能改 validateMessage
|
||||
// The reason for not limiting by the maxSize property is
|
||||
// Only the beforeUpload hook can change validateMessage
|
||||
const res = {
|
||||
fileInstance: fileInfo.file.fileInstance,
|
||||
status: fileInfo.file.status,
|
||||
@@ -438,7 +438,7 @@ export const Upload: FC = () => {
|
||||
dragMainText={I18n.t('db_table_0126_016')}
|
||||
dragSubText={I18n.t('db_table_0126_017')}
|
||||
onChange={({ fileList: files }) => {
|
||||
// 存在校验通过的才上传
|
||||
// It will only be uploaded if the verification is passed.
|
||||
if (files.some(f => f.shouldUpload)) {
|
||||
setCurrentState({
|
||||
fileList: files,
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// 20MB 限制
|
||||
// 20MB limit
|
||||
export const ACCEPT_FILE_MAX_SIZE = 20 * 1024 * 1024;
|
||||
export const ACCEPT_FILE_TYPES = ['.xlsx', '.xls', '.csv'].join(',');
|
||||
|
||||
@@ -62,7 +62,7 @@ export default class DatamodelService<T> {
|
||||
*
|
||||
* [jump to BAM]()
|
||||
*
|
||||
* 【Table Import】导入文件数据预检查
|
||||
* [Table Import] Import file data pre-check
|
||||
*/
|
||||
PreviewTableFile(
|
||||
req: table_import.PreviewTableFileRequest,
|
||||
@@ -84,7 +84,7 @@ export default class DatamodelService<T> {
|
||||
*
|
||||
* [jump to BAM]()
|
||||
*
|
||||
* 【Table Import】导入文件数据任务信息查询
|
||||
* [Table Import] Import file data task information query
|
||||
*/
|
||||
QueryTableFileTaskStatus(
|
||||
req: table_import.QueryTableFileTaskStatusRequest,
|
||||
@@ -107,7 +107,7 @@ export default class DatamodelService<T> {
|
||||
*
|
||||
* [jump to BAM]()
|
||||
*
|
||||
* 【Table Import】导入文件添加table
|
||||
* [Table Import] Import file Add table
|
||||
*/
|
||||
AddTable(
|
||||
req: table_import.AddTableRequest,
|
||||
|
||||
@@ -22,33 +22,33 @@
|
||||
export type Int64 = string | number;
|
||||
|
||||
export enum BotTableRWMode {
|
||||
/** 单用户模式 */
|
||||
/** single user mode */
|
||||
LimitedReadWrite = 1,
|
||||
/** 只读模式 */
|
||||
/** read-only mode */
|
||||
ReadOnly = 2,
|
||||
/** 多用户模式 */
|
||||
/** multi-user mode */
|
||||
UnlimitedReadWrite = 3,
|
||||
/** Max 边界值 */
|
||||
/** Max boundary value */
|
||||
RWModeMax = 4,
|
||||
}
|
||||
|
||||
export enum BotTableStatus {
|
||||
/** 初始化(不可用) */
|
||||
/** Initialization (not available) */
|
||||
Init = 0,
|
||||
/** 已上线 */
|
||||
/** It's online now. */
|
||||
Online = 1,
|
||||
/** 删除 */
|
||||
/** delete */
|
||||
Delete = 2,
|
||||
/** 草稿态(未 publish) */
|
||||
/** Draft status (not published) */
|
||||
Draft = 3,
|
||||
}
|
||||
|
||||
export enum FieldItemType {
|
||||
/** 文本 */
|
||||
/** Text */
|
||||
Text = 1,
|
||||
/** 数字 */
|
||||
/** number */
|
||||
Number = 2,
|
||||
/** 时间 */
|
||||
/** time */
|
||||
Date = 3,
|
||||
/** float */
|
||||
Float = 4,
|
||||
@@ -56,13 +56,13 @@ export enum FieldItemType {
|
||||
Boolean = 5,
|
||||
}
|
||||
|
||||
/** Table model相关常量,结构体定义 */
|
||||
/** Table model related constants, structure definitions */
|
||||
export enum FieldType {
|
||||
/** 文本 */
|
||||
/** Text */
|
||||
Text = 1,
|
||||
/** 数字 */
|
||||
/** number */
|
||||
Number = 2,
|
||||
/** 时间 */
|
||||
/** time */
|
||||
Date = 3,
|
||||
/** float */
|
||||
Float = 4,
|
||||
@@ -71,49 +71,49 @@ export enum FieldType {
|
||||
}
|
||||
|
||||
export enum ImportFileTaskStatus {
|
||||
/** 任务初始化 */
|
||||
/** task initialization */
|
||||
Init = 1,
|
||||
/** 任务处理中 */
|
||||
/** Task in progress */
|
||||
Enqueue = 2,
|
||||
/** 任务成功 */
|
||||
/** Mission successful */
|
||||
Succeed = 3,
|
||||
/** 任务失败 */
|
||||
/** Mission failed */
|
||||
Failed = 4,
|
||||
}
|
||||
|
||||
export enum Language {
|
||||
/** 中文 */
|
||||
/** Chinese */
|
||||
Chinese = 1,
|
||||
/** 英文 */
|
||||
/** English */
|
||||
English = 2,
|
||||
}
|
||||
|
||||
export enum TableType {
|
||||
/** 草稿 */
|
||||
/** draft */
|
||||
DraftTable = 1,
|
||||
/** 线上 */
|
||||
/** online */
|
||||
OnlineTable = 2,
|
||||
}
|
||||
|
||||
export interface FieldItem {
|
||||
/** 字段名称,用户自定义,可能为中文 */
|
||||
/** Field name, user-defined, possibly in Chinese */
|
||||
name: string;
|
||||
desc?: string;
|
||||
type: FieldItemType;
|
||||
must_required?: boolean;
|
||||
/** 字段Id,服务端生成,全局唯一(新增为0) */
|
||||
/** Field Id, server level generated, globally unique (added as 0) */
|
||||
id?: Int64;
|
||||
/** 字段名称语言类型 */
|
||||
/** Field Name Language Type */
|
||||
lang?: Language;
|
||||
/** 物理字段名,服务端生成,单个table下唯一 */
|
||||
/** Physical field name, server level generation, unique under a single table */
|
||||
physics_name?: string;
|
||||
/** 是否主键 */
|
||||
/** Whether primary key */
|
||||
primary_key?: boolean;
|
||||
/** 字段可见性,1:用户自定义;2:业务定义,对用户可见;3:业务定义,对用户隐藏 */
|
||||
/** Field visibility, 1: user-defined; 2: business definition, visible to users; 3: business definition, hidden from users */
|
||||
visibility?: number;
|
||||
/** 在excel文档中使用,映射到excel中对应的列 */
|
||||
/** Used in an excel document, map to the corresponding column in excel */
|
||||
sequence?: string;
|
||||
/** 业务自定义扩展field元数据 */
|
||||
/** Business custom extension field metadata */
|
||||
map_ext_meta?: Record<string, string>;
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
@@ -33,15 +33,15 @@ export interface AddTableRequest {
|
||||
}
|
||||
|
||||
export interface AddTableResponse {
|
||||
/** 相关id. bot_id */
|
||||
/** Related id bot_id */
|
||||
bot_id: string;
|
||||
/** table_id */
|
||||
table_id: string;
|
||||
/** 表名 */
|
||||
/** table name */
|
||||
table_name: string;
|
||||
/** 上传 TableFile 的 task id,用于后期查询使用.
|
||||
DataModelService 使用 GID 保证 task_id 全局唯一,后续查询时只需要 task_id.
|
||||
DataModel 服务会记录 table 的 lastTaskID, 查询时可以通过 table_id 查到唯一的
|
||||
/** Upload the task id of TableFile for later query use.
|
||||
DataModelService uses GID to ensure that task_id globally unique, and subsequent queries only require task_id.
|
||||
The DataModel service will record the lastTaskID of the table, which can be found by table_id when querying
|
||||
task_id */
|
||||
task_id: Int64;
|
||||
code: number;
|
||||
@@ -51,24 +51,24 @@ task_id */
|
||||
export interface FileInfo {
|
||||
/** tos uri */
|
||||
tos_uri: string;
|
||||
/** Excel 行号 */
|
||||
/** Excel line number */
|
||||
header_row: Int64;
|
||||
/** Excel 数据开始行 */
|
||||
/** Excel data start line */
|
||||
start_data_row: Int64;
|
||||
/** Excel sheet id, 0 for default */
|
||||
sheet_id?: number;
|
||||
}
|
||||
|
||||
export interface ImportTableInfo {
|
||||
/** table 所属的 bot_id */
|
||||
/** Table belongs to bot_id */
|
||||
bot_id: string;
|
||||
/** 表名 */
|
||||
/** table name */
|
||||
table_name: string;
|
||||
/** 表描述 */
|
||||
/** table description */
|
||||
table_desc?: string;
|
||||
/** 字段信息 */
|
||||
/** Field information */
|
||||
table_meta: Array<table_base.FieldItem>;
|
||||
/** 空间ID */
|
||||
/** Space ID */
|
||||
space_id: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ export const useUploadProgress = (params: {
|
||||
try {
|
||||
let res: QueryTableFileTaskStatusResponse;
|
||||
try {
|
||||
// TODO:此需求暂停,后端下线,后续待开放
|
||||
// TODO: This demand is suspended, the backend is offline, and it will be opened later.
|
||||
// res = await DataModelApi.QueryTableFileTaskStatus({
|
||||
// table_id: tableID,
|
||||
// bot_id: botID,
|
||||
@@ -89,7 +89,7 @@ export const useUploadProgress = (params: {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 不在Processing则停止轮询
|
||||
// Stop polling without Processing
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
if (res?.status !== ImportFileTaskStatus.Enqueue) {
|
||||
clearInterval(importResultRef.current);
|
||||
@@ -97,8 +97,8 @@ export const useUploadProgress = (params: {
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功后---写入localStorage
|
||||
* 没有任务---写入localStorage
|
||||
* After success --- write to localStorage
|
||||
* No task --- write to localStorage
|
||||
*/
|
||||
if (
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -129,7 +129,7 @@ export const useUploadProgress = (params: {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 读取localStorage,减少不必要的请求次数
|
||||
// Read localStorage to reduce unnecessary requests
|
||||
const lsMap = readFromLocalStorage();
|
||||
const inLocaleStorage = (lsMap[botID] || []).includes(tableID);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface initialConfigStore {
|
||||
}) => Promise<void>;
|
||||
}
|
||||
|
||||
// 用来存储静态状态,非初始化场景下,仅只读不可修改
|
||||
// Used to store static state, in non-initialization scenarios, read-only and not modifiable
|
||||
export const useInitialConfigStore = create<initialConfigStore>()(set => ({
|
||||
onCancel: noop,
|
||||
botId: '',
|
||||
|
||||
@@ -131,7 +131,7 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
mapOfShouldHidingDatabaseTableStructureTips,
|
||||
setMapOfShouldHidingDatabaseTableStructureTips,
|
||||
] = useLocalStorageState<string | undefined>(
|
||||
// FIXME: 此属性名意义不明确,处为了兼容,暂不修改此属性名,但后续需要使用更明确的命名
|
||||
// FIXME: The meaning of this property name is unclear. For compatibility, this property name will not be modified for the time being, but a more explicit naming needs to be used in the future.
|
||||
'use-local-storage-state-modify-tips',
|
||||
{
|
||||
defaultValue: '',
|
||||
@@ -181,9 +181,9 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
const showEntry = isEntry && !isEdit && !NL2DBInfo;
|
||||
const shouldShowAIGenerate =
|
||||
/**
|
||||
* 1. 入口不展示
|
||||
* 2. 编辑态不展示
|
||||
* 3. Excel导入时不展示
|
||||
* 1. The entrance is not displayed
|
||||
* 2. Editing status is not displayed
|
||||
* 3. Excel is not displayed when importing
|
||||
*/
|
||||
!showEntry && !isEdit && createType !== CreateType.excel;
|
||||
|
||||
@@ -280,8 +280,8 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
})),
|
||||
});
|
||||
|
||||
// data 是初始值,此处需要手动 setState 更新子组件状态
|
||||
// 若 Modal 已提前关闭,子组件卸载,则 ref 为空,需要加上可选链判断一下
|
||||
// Data is the initial value, where you need to manually setState to update the subcomponent state
|
||||
// If Modal has been closed early and the subassembly is uninstalled, the ref is empty. You need to add an optional chain to judge.
|
||||
tableStructureRef.current?.setTableFieldsList(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
res.bot_table_list[0].field_list.map(i => ({
|
||||
@@ -562,7 +562,7 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
onDeleteField={list => {
|
||||
setIsDeletedField(
|
||||
!database.tableMemoryList.every(i =>
|
||||
// TODO: 当前field id生成规则有问题,故暂时使用 nanoid 替换
|
||||
// TODO: There is a problem with the current field id generation rule, so the nanoid is temporarily replaced
|
||||
list.find(j => j.nanoid === i.nanoid),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@ import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { type MapperItem, type TriggerType, VerifyType } from '../../../types';
|
||||
|
||||
// 校验 Table Name 和 Field Name
|
||||
// Validation Table Name and Field Name
|
||||
const namingRegexMapper = [
|
||||
{
|
||||
type: 1,
|
||||
@@ -49,7 +49,7 @@ export const validateNaming = (str: string, errList: string[] = []) => {
|
||||
return list;
|
||||
};
|
||||
|
||||
// 校验 Table Fields
|
||||
// Validation Table Fields
|
||||
export const thMapper: MapperItem[] = [
|
||||
{
|
||||
label: I18n.t('db_add_table_field_name'),
|
||||
@@ -120,7 +120,7 @@ export const validateFields = (
|
||||
const msg = verifyItem.message;
|
||||
switch (verifyItem.type) {
|
||||
case VerifyType.Required: {
|
||||
// 报错出现时机:点击保存按钮时,出现提示。表中某一行填写了数据,但是未填写必填字段时,需要报错
|
||||
// When the error occurs: When clicking the Save button, a prompt appears. When a row in the table fills in the data, but the required fields are not filled in, an error needs to be reported.
|
||||
if (
|
||||
trigger === 'save' &&
|
||||
!value &&
|
||||
@@ -131,14 +131,14 @@ export const validateFields = (
|
||||
) {
|
||||
listItem.errorMapper[thKey].push(msg);
|
||||
}
|
||||
// 报错消失时机:必填输入框输入了内容后,报错立刻消失
|
||||
// Error reporting and disappearance timing: Required text box After entering the content, the error will disappear immediately
|
||||
if (trigger === 'change' && value) {
|
||||
listItem.errorMapper[thKey] = errTarget.filter(i => i !== msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VerifyType.Unique: {
|
||||
// 报错出现时机:点击保存按钮时,出现提示。
|
||||
// When the error occurs: When you click the Save button, a prompt appears.
|
||||
if (
|
||||
trigger === 'save' &&
|
||||
value &&
|
||||
@@ -146,7 +146,7 @@ export const validateFields = (
|
||||
) {
|
||||
listItem.errorMapper[thKey].push(msg);
|
||||
}
|
||||
// 报错消失时机:必填输入框输入了内容后,报错立刻消失
|
||||
// Error reporting and disappearance timing: Required text box After entering the content, the error will disappear immediately
|
||||
if (
|
||||
trigger === 'change' &&
|
||||
value &&
|
||||
@@ -157,7 +157,7 @@ export const validateFields = (
|
||||
break;
|
||||
}
|
||||
case VerifyType.Naming: {
|
||||
// 报错出现时机:命名格式有问题,失去焦点时,立刻校验格式
|
||||
// Error timing: There is a problem with the naming format. When you lose focus, check the format immediately
|
||||
if (
|
||||
trigger === 'save' ||
|
||||
trigger === 'blur' ||
|
||||
|
||||
@@ -97,10 +97,10 @@ export interface DatabaseTableStructureProps {
|
||||
loading?: boolean;
|
||||
loadingTips?: string;
|
||||
/**
|
||||
* excel: 单用户模式|只读模式
|
||||
* normal: 单用户模式|只读模式
|
||||
* expert: 单用户模式|只读模式|多用户模式
|
||||
* undefined: 不支持读写模式
|
||||
* Excel: single user mode | read-only mode
|
||||
* Normal: Single user mode | Read-only mode
|
||||
* Expert: Single user mode | Read-only mode | Multi-user mode
|
||||
* Undefined: Read and write modes are not supported
|
||||
*/
|
||||
readAndWriteModeOptions?: ReadAndWriteModeOptions;
|
||||
enableAdd?: boolean;
|
||||
@@ -219,11 +219,11 @@ export const DatabaseTableStructure = forwardRef<
|
||||
};
|
||||
|
||||
const verifyAllBeforeSave = async (): Promise<boolean> => {
|
||||
// 触发 tableFields 校验
|
||||
// Trigger tableFields validation
|
||||
const validatedTableFieldsList = validateFields(tableFieldsList, 'save');
|
||||
setTableFieldsList(validatedTableFieldsList);
|
||||
|
||||
// 触发并校验 tableBasicInfo
|
||||
// Trigger and validate tableBasicInfo
|
||||
try {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
await tableBasicInfoFormRef.current.formApi.validate(['name']);
|
||||
@@ -231,7 +231,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验 tableFields
|
||||
// Validation tableFields
|
||||
if (
|
||||
validatedTableFieldsList.find(i =>
|
||||
Object.keys(i.errorMapper || {}).find(
|
||||
@@ -242,7 +242,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验 tableFields 是否为空
|
||||
// Verify that tableFields is empty
|
||||
if (isEmptyList) {
|
||||
return false;
|
||||
}
|
||||
@@ -354,7 +354,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化 ref 属性
|
||||
// Initialize ref attribute
|
||||
useImperativeHandle<DatabaseTableStructureRef, DatabaseTableStructureRef>(
|
||||
ref,
|
||||
() => ({
|
||||
@@ -374,7 +374,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
[isReadonly, tableFieldsList, tableBasicInfoFormRef],
|
||||
);
|
||||
|
||||
// 自定义表单项组件
|
||||
// Custom form item component
|
||||
const FormInputInner: FC<any> = useCallback(
|
||||
p => {
|
||||
const { onChange, value, onBlur, validateStatus } = p;
|
||||
@@ -413,7 +413,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
[],
|
||||
);
|
||||
|
||||
// 校验是否 disable 下一步按钮
|
||||
// Verify that the Next button is disabled
|
||||
useComputingEnableGoToNextStep?.(tableFieldsList);
|
||||
|
||||
const dataSource = enableAdd
|
||||
|
||||
@@ -103,7 +103,7 @@ export const DATABASE_CONTENT_CHECK_ERROR_CODE = 708024072;
|
||||
export const DATABASE_CONTENT_CHECK_ERROR_CODE_NEW = 708334072;
|
||||
|
||||
/**
|
||||
* 内置字段: uuid
|
||||
* Built-in field: uuid
|
||||
*/
|
||||
export const USER_ID_FIELD: TableMemoryItem = {
|
||||
name: 'uuid',
|
||||
@@ -115,7 +115,7 @@ export const USER_ID_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置字段: id
|
||||
* Built-in field: id
|
||||
*/
|
||||
export const ID_FIELD: TableMemoryItem = {
|
||||
name: 'id',
|
||||
@@ -127,6 +127,6 @@ export const ID_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置系统字段
|
||||
* Built-in system fields
|
||||
*/
|
||||
export const SYSTEM_FIELDS = [USER_ID_FIELD, ID_FIELD];
|
||||
|
||||
@@ -28,9 +28,9 @@ export enum CreateType {
|
||||
custom = 'custom',
|
||||
template = 'template',
|
||||
excel = 'excel',
|
||||
// 推荐建表
|
||||
// recommended table
|
||||
recommend = 'recommend',
|
||||
// 输入自然语言建表
|
||||
// Enter natural language to build a table
|
||||
naturalLanguage = 'naturalLanguage',
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ interface CreateTableModalExtraParams {
|
||||
creatorId?: string;
|
||||
}
|
||||
|
||||
// RenderGenerate属性类型定义
|
||||
// RenderGenerate property type definition
|
||||
export interface RenderGenerateProps {
|
||||
tableStructureRef: RefObject<DatabaseTableStructureRef>;
|
||||
onGenerateChange: (tableMemoryList: TableMemoryItem[]) => void;
|
||||
@@ -181,7 +181,7 @@ export function DatabaseCreateTableModal({
|
||||
setSaveBtnDisabled(true);
|
||||
return;
|
||||
}
|
||||
// 系统字段不计入字段数量限制
|
||||
// System fields do not count towards the number of fields limit
|
||||
if (list.filter(i => !i.isSystemField).length > MAX_COLUMNS) {
|
||||
setSaveBtnDisabled(true);
|
||||
return;
|
||||
@@ -204,8 +204,8 @@ export function DatabaseCreateTableModal({
|
||||
|
||||
const onSave: OnSave = async ({ response }) => {
|
||||
/**
|
||||
* 在 DatabaseTableStructure 这个组件中,提交已经区分了 edit 和 create 两种状态,
|
||||
* 并且存在一个onSave的回调,因此提交之后的逻辑全部收敛在这里
|
||||
* In DatabaseTableStructure component, commit already distinguishes between edit and create states,
|
||||
* And there is an onSave callback, so the logic after commit all converges here
|
||||
*/
|
||||
await onSubmit?.(response);
|
||||
};
|
||||
@@ -262,7 +262,7 @@ export function DatabaseCreateTableModal({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* 编辑弹窗出现 Banner 提示 */}
|
||||
{/* Banner prompt appears in the edit pop-up window */}
|
||||
{isModify ? (
|
||||
<DismissibleBanner
|
||||
type="warning"
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
VerifyType,
|
||||
} from '../../../types/database-field';
|
||||
|
||||
// 校验 Table Name 和 Field Name
|
||||
// Validation Table Name and Field Name
|
||||
const namingRegexMapper = [
|
||||
{
|
||||
type: 1,
|
||||
@@ -53,7 +53,7 @@ export const validateNaming = (str: string, errList: string[] = []) => {
|
||||
return list;
|
||||
};
|
||||
|
||||
// 校验 Table Fields
|
||||
// Validation Table Fields
|
||||
export const thMapper: MapperItem[] = [
|
||||
{
|
||||
label: I18n.t('db_add_table_field_name'),
|
||||
@@ -124,7 +124,7 @@ export const validateFields = (
|
||||
const msg = verifyItem.message;
|
||||
switch (verifyItem.type) {
|
||||
case VerifyType.Required: {
|
||||
// 报错出现时机:点击保存按钮时,出现提示。表中某一行填写了数据,但是未填写必填字段时,需要报错
|
||||
// When the error occurs: When clicking the Save button, a prompt appears. When a row in the table fills in the data, but the required fields are not filled in, an error needs to be reported.
|
||||
if (
|
||||
trigger === 'save' &&
|
||||
!value &&
|
||||
@@ -135,14 +135,14 @@ export const validateFields = (
|
||||
) {
|
||||
listItem.errorMapper[thKey].push(msg);
|
||||
}
|
||||
// 报错消失时机:必填输入框输入了内容后,报错立刻消失
|
||||
// Error reporting and disappearance timing: Required text box After entering the content, the error will disappear immediately
|
||||
if (trigger === 'change' && value) {
|
||||
listItem.errorMapper[thKey] = errTarget.filter(i => i !== msg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VerifyType.Unique: {
|
||||
// 报错出现时机:点击保存按钮时,出现提示。
|
||||
// When the error occurs: When you click the Save button, a prompt appears.
|
||||
if (
|
||||
trigger === 'save' &&
|
||||
value &&
|
||||
@@ -150,7 +150,7 @@ export const validateFields = (
|
||||
) {
|
||||
listItem.errorMapper[thKey].push(msg);
|
||||
}
|
||||
// 报错消失时机:必填输入框输入了内容后,报错立刻消失
|
||||
// Error reporting and disappearance timing: Required text box After entering the content, the error will disappear immediately
|
||||
if (
|
||||
trigger === 'change' &&
|
||||
value &&
|
||||
@@ -161,7 +161,7 @@ export const validateFields = (
|
||||
break;
|
||||
}
|
||||
case VerifyType.Naming: {
|
||||
// 报错出现时机:命名格式有问题,失去焦点时,立刻校验格式
|
||||
// Error timing: There is a problem with the naming format. When you lose focus, check the format immediately
|
||||
if (
|
||||
trigger === 'save' ||
|
||||
trigger === 'blur' ||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
import {
|
||||
useRef,
|
||||
@@ -89,19 +89,19 @@ export interface DatabaseTableStructureProps {
|
||||
loadingTips?: string;
|
||||
projectID?: string;
|
||||
/**
|
||||
* excel: 单用户模式|只读模式
|
||||
* normal: 单用户模式|只读模式
|
||||
* expert: 单用户模式|只读模式|多用户模式
|
||||
* undefined: 不支持读写模式
|
||||
* Excel: single user mode | read-only mode
|
||||
* Normal: Single user mode | Read-only mode
|
||||
* Expert: Single user mode | Read-only mode | Multi-user mode
|
||||
* Undefined: Read and write modes are not supported
|
||||
*/
|
||||
readAndWriteModeOptions?: ReadAndWriteModeOptions;
|
||||
/** databaseInfo中只显示 Mode 的UI */
|
||||
/** Only display Mode UI in DatabaseInfo */
|
||||
onlyShowDatabaseInfoRWMode?: boolean;
|
||||
enableAdd?: boolean;
|
||||
isReadonlyMode?: boolean;
|
||||
maxColumnNum?: number;
|
||||
/**
|
||||
* 是否展示基本信息(表名、介绍)
|
||||
* Whether to display basic information (table name, introduction)
|
||||
*/
|
||||
showDatabaseBaseInfo?: boolean;
|
||||
hiddenTableBorder?: boolean;
|
||||
@@ -138,7 +138,7 @@ export interface DatabaseTableStructureRef {
|
||||
export const DatabaseTableStructure = forwardRef<
|
||||
DatabaseTableStructureRef,
|
||||
DatabaseTableStructureProps
|
||||
// eslint-disable-next-line max-lines-per-function, @coze-arch/max-line-per-function, complexity -- 历史文件拷贝
|
||||
// eslint-disable-next-line max-lines-per-function, @coze-arch/max-line-per-function, complexity -- historical file copy
|
||||
>((props, ref) => {
|
||||
const {
|
||||
data: initialData,
|
||||
@@ -156,7 +156,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
enableAdd = true,
|
||||
loading = false,
|
||||
setContentCheckErrorMsg = noop,
|
||||
// TODO 把 AI generate 的 loading tip 放到 table 里面
|
||||
// TODO put AI generated loading tips into the table
|
||||
// loadingTips,
|
||||
createType,
|
||||
showDatabaseBaseInfo,
|
||||
@@ -177,7 +177,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
|
||||
const [isReadonly, { setTrue: enableReadonly, setFalse: disableReadonly }] =
|
||||
useBoolean(false);
|
||||
// 系统字段不计入字段数量限制
|
||||
// System fields do not count towards the number of fields limit
|
||||
const userFields = tableFieldsList.filter(i => !i.isSystemField);
|
||||
const isRowMaxLimit = userFields.length >= maxColumnNum;
|
||||
const isExceedRowMaxLimit = userFields.length > maxColumnNum;
|
||||
@@ -233,11 +233,11 @@ export const DatabaseTableStructure = forwardRef<
|
||||
};
|
||||
|
||||
const verifyAllBeforeSave = async (): Promise<boolean> => {
|
||||
// 触发 tableFields 校验
|
||||
// Trigger tableFields validation
|
||||
const validatedTableFieldsList = validateFields(tableFieldsList, 'save');
|
||||
setTableFieldsList(validatedTableFieldsList);
|
||||
|
||||
// 触发并校验 tableBasicInfo
|
||||
// Trigger and validate tableBasicInfo
|
||||
if (showDatabaseBaseInfo) {
|
||||
try {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -247,7 +247,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
}
|
||||
}
|
||||
|
||||
// 校验 tableFields
|
||||
// Validation tableFields
|
||||
if (
|
||||
validatedTableFieldsList.find(i =>
|
||||
Object.keys(i.errorMapper || {}).find(
|
||||
@@ -258,7 +258,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验 tableFields 是否为空
|
||||
// Verify that tableFields is empty
|
||||
if (isEmptyList) {
|
||||
return false;
|
||||
}
|
||||
@@ -382,7 +382,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
return '';
|
||||
};
|
||||
|
||||
// 初始化 ref 属性
|
||||
// Initialize ref attribute
|
||||
useImperativeHandle<DatabaseTableStructureRef, DatabaseTableStructureRef>(
|
||||
ref,
|
||||
() => ({
|
||||
@@ -402,7 +402,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
[isReadonly, tableFieldsList, tableBasicInfoFormRef],
|
||||
);
|
||||
|
||||
// 校验是否 disable 下一步按钮
|
||||
// Verify that the Next button is disabled
|
||||
useComputingEnableGoToNextStep?.(tableFieldsList, isEmptyList);
|
||||
|
||||
const dataSource = enableAdd
|
||||
@@ -759,7 +759,7 @@ export const DatabaseTableStructure = forwardRef<
|
||||
}}
|
||||
wrapperClassName={s['table-structure-table-wrapper']}
|
||||
/>
|
||||
{/* 表格为空时,底部的错误提示 */}
|
||||
{/* Error message at the bottom when the table is empty */}
|
||||
{isEmptyList && !loading ? (
|
||||
<div className={s['table-empty-tips']}>
|
||||
{I18n.t('db_table_save_exception_nofield')}
|
||||
|
||||
@@ -54,7 +54,7 @@ export type SLInputProps = ComponentProps<typeof Input> & {
|
||||
ellipsisPopoverProps?: PopoverProps;
|
||||
onFocusPopoverProps?: PopoverProps;
|
||||
tooltipProps?: TooltipProps;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- 历史逻辑
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- historical logic
|
||||
inputProps?: InputProps & { 'data-dtestid'?: string; 'data-testid'?: string };
|
||||
errorMsg?: string;
|
||||
errorMsgFloat?: boolean;
|
||||
@@ -205,7 +205,7 @@ export const SLInput: React.FC<SLInputProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
// Semi 不导出被 withField 包装的组件的 props 类型(甚至是 any ´_>`)
|
||||
// Semi does not export the props type (or even any ´_>`) of the component wrapped with the withField.
|
||||
// https://github.com/DouyinFE/semi-design/blob/v2.69.2/packages/semi-ui/form/hoc/withField.tsx#L528
|
||||
export const FormSLInput: React.FunctionComponent<
|
||||
CommonFieldProps & Omit<SLInputProps, keyof CommonexcludeType>
|
||||
|
||||
@@ -103,7 +103,7 @@ export const DATABASE_CONTENT_CHECK_ERROR_CODE = 708024072;
|
||||
export const DATABASE_CONTENT_CHECK_ERROR_CODE_NEW = 708334072;
|
||||
|
||||
/**
|
||||
* 内置字段: uuid
|
||||
* Built-in field: uuid
|
||||
* bstudio_connector_uid
|
||||
*/
|
||||
export const USER_ID_FIELD: TableMemoryItem = {
|
||||
@@ -116,7 +116,7 @@ export const USER_ID_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置字段: id
|
||||
* Built-in field: id
|
||||
*/
|
||||
export const ID_FIELD: TableMemoryItem = {
|
||||
name: 'id',
|
||||
@@ -128,7 +128,7 @@ export const ID_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置字段: sys_platform
|
||||
* Built-in fields: sys_platform
|
||||
* bstudio_connector_id
|
||||
*/
|
||||
export const PLATFORM_FIELD: TableMemoryItem = {
|
||||
@@ -141,7 +141,7 @@ export const PLATFORM_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置字段: connector_id
|
||||
* Built-in fields: connector_id
|
||||
* bstudio_create_time
|
||||
*/
|
||||
export const CREATE_TIME_FIELD: TableMemoryItem = {
|
||||
@@ -154,7 +154,7 @@ export const CREATE_TIME_FIELD: TableMemoryItem = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 内置系统字段
|
||||
* Built-in system fields
|
||||
*/
|
||||
export const SYSTEM_FIELDS = [
|
||||
ID_FIELD,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import { type DatabaseInfo } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
type AlterBotTableResponse,
|
||||
@@ -24,17 +24,17 @@ export type OnSave = (params: {
|
||||
response: InsertBotTableResponse | AlterBotTableResponse;
|
||||
}) => Promise<void>;
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention -- 历史文件拷贝 */
|
||||
/* eslint-disable @typescript-eslint/naming-convention -- history file copy */
|
||||
export enum CreateType {
|
||||
custom = 'custom',
|
||||
template = 'template',
|
||||
excel = 'excel',
|
||||
// 推荐建表
|
||||
// recommended table
|
||||
recommend = 'recommend',
|
||||
// 输入自然语言建表
|
||||
// Enter natural language to build a table
|
||||
naturalLanguage = 'naturalLanguage',
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/naming-convention -- 历史文件拷贝 */
|
||||
/* eslint-enable @typescript-eslint/naming-convention -- history file copy */
|
||||
|
||||
export interface MapperItem {
|
||||
label: string;
|
||||
@@ -43,7 +43,7 @@ export interface MapperItem {
|
||||
type: VerifyType;
|
||||
message: string;
|
||||
}[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 历史文件拷贝
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- historical file copy
|
||||
defaultValue: any;
|
||||
require: boolean;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 数据库详情页 tab
|
||||
* Database details page tab
|
||||
*/
|
||||
export enum DatabaseTabs {
|
||||
/** 表结构 */
|
||||
/** table structure */
|
||||
Structure = 'structure',
|
||||
/** 测试数据 */
|
||||
/** test data */
|
||||
Draft = 'draft',
|
||||
/** 线上数据 */
|
||||
/** online data */
|
||||
Online = 'online',
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export function StepConfig({
|
||||
onTableSheetChange,
|
||||
}: StepConfigProps) {
|
||||
const [tableData, setTableData] = useState<TableSettingsData>();
|
||||
// 默认值:使用第1个数据表,第1行是表头,第2行开始是数据
|
||||
// Default: Use the first data table, the first row is the header, and the second row starts with data
|
||||
const [tableSettings, setTableSettings] = useState<TableSettings>({
|
||||
sheet_id: 0,
|
||||
header_line_idx: 0,
|
||||
@@ -86,12 +86,12 @@ export function StepConfig({
|
||||
onSuccess: res => {
|
||||
setTableData({
|
||||
sheet_list: res.sheet_list,
|
||||
preview_data: {}, // TableSettingBar 并没有读取 preview_data,但是在判断它非空
|
||||
preview_data: {}, // TableSettingBar does not read preview_data, but it is not empty
|
||||
});
|
||||
if (res.table_meta) {
|
||||
setTableStructure(
|
||||
res.table_meta.map(column => {
|
||||
// 表结构中有同名字段时,使用原本的类型及描述
|
||||
// When there are fields with the same name in the table structure, use the original type and description
|
||||
const matchedField = tableFields.find(
|
||||
field => field.fieldName === column.column_name,
|
||||
);
|
||||
|
||||
@@ -64,13 +64,13 @@ export function StepProcess({
|
||||
[fileItem],
|
||||
);
|
||||
const [progressProps, setProgressProps] = useState<ProcessProps>({
|
||||
// 第一行文本(文件名)
|
||||
// First line of text (file name)
|
||||
mainText: fileItem.name,
|
||||
// 第二行文本(文件大小)
|
||||
// Second line of text (file size)
|
||||
subText: fileSize,
|
||||
// hover 时显示的第二行文本,与上面保持一致
|
||||
// The second line of text displayed when hovering, consistent with the above
|
||||
tipText: fileSize,
|
||||
// 进度条百分比,初始 10% 与 @coze-data/knowledge-resource-processor-base/unit-progress 保持一致
|
||||
// Progress bar percentage, initial 10% is consistent with @code-data/knowledge-resource-processor-base/unit-progress
|
||||
percent: INIT_PERCENT,
|
||||
status: ProcessStatus.Processing,
|
||||
});
|
||||
@@ -87,7 +87,7 @@ export function StepProcess({
|
||||
onSuccess: res => {
|
||||
const { data } = res;
|
||||
if (data) {
|
||||
// 有错误信息代表处理失败,展示错误信息,并停止轮询
|
||||
// If there is an error message, it means the processing failed. Display the error message and stop polling.
|
||||
if (data.status_descript) {
|
||||
const msg = data.status_descript;
|
||||
setProgressProps(props => ({
|
||||
@@ -102,7 +102,7 @@ export function StepProcess({
|
||||
...props,
|
||||
percent: data.progress ?? 0,
|
||||
}));
|
||||
// 进度 100 代表处理完成,更新状态并停止轮询
|
||||
// Progress 100 represents process completion, update status and stop polling
|
||||
if (data.progress === COMPLETE_PERCENT) {
|
||||
setProgressProps(props => ({
|
||||
...props,
|
||||
@@ -117,7 +117,7 @@ export function StepProcess({
|
||||
},
|
||||
);
|
||||
|
||||
// 提交任务,并开始轮询进度
|
||||
// Submit the task and start polling progress
|
||||
useEffect(() => {
|
||||
MemoryApi.SubmitDatabaseInsertTask({
|
||||
database_id: databaseId,
|
||||
|
||||
@@ -130,7 +130,7 @@ export const DatabaseDetail = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 需要一个 store,后续改造
|
||||
// Need a store, follow-up renovation
|
||||
const isReadOnlyMode = databaseInfo.creator_id !== userId || !!version;
|
||||
|
||||
const tableInitData: DatabaseInitInfo = useMemo(
|
||||
@@ -355,7 +355,7 @@ export const DatabaseDetail = ({
|
||||
databaseId={databaseId}
|
||||
tableType={TableType.DraftTable}
|
||||
tableFields={databaseInfo.field_list || []}
|
||||
// 测试数据无需控制权限,只要能看到的数据就能修改删除
|
||||
// Test data does not require control rights, as long as the data can be seen, it can be modified and deleted
|
||||
isReadonlyMode={false}
|
||||
enterFrom={enterFrom}
|
||||
onAfterEditRecords={onAfterEditRecords}
|
||||
|
||||
@@ -90,7 +90,7 @@ export interface DatabaseModalProps {
|
||||
botId: string;
|
||||
spaceId: string;
|
||||
readonly: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- 历史逻辑
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- historical logic
|
||||
NL2DBInfo: NL2DBInfo | null;
|
||||
expertModeConfig?: ExpertModeConfig;
|
||||
onSave?: OnSave;
|
||||
@@ -138,7 +138,7 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
mapOfShouldHidingDatabaseTableStructureTips,
|
||||
setMapOfShouldHidingDatabaseTableStructureTips,
|
||||
] = useLocalStorageState<string | undefined>(
|
||||
// FIXME: 此属性名意义不明确,处为了兼容,暂不修改此属性名,但后续需要使用更明确的命名
|
||||
// FIXME: The meaning of this property name is unclear. For compatibility, this property name will not be modified for the time being, but a more explicit naming needs to be used in the future.
|
||||
'use-local-storage-state-modify-tips',
|
||||
{
|
||||
defaultValue: '',
|
||||
@@ -188,9 +188,9 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
const showEntry = isEntry && !isEdit && !NL2DBInfo;
|
||||
const shouldShowAIGenerate =
|
||||
/**
|
||||
* 1. 入口不展示
|
||||
* 2. 编辑态不展示
|
||||
* 3. Excel导入时不展示
|
||||
* 1. The entrance is not displayed
|
||||
* 2. Editing status is not displayed
|
||||
* 3. Excel is not displayed when importing
|
||||
*/
|
||||
!showEntry && !isEdit && createType !== CreateType.excel;
|
||||
|
||||
@@ -282,8 +282,8 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
})),
|
||||
});
|
||||
|
||||
// data 是初始值,此处需要手动 setState 更新子组件状态
|
||||
// 若 Modal 已提前关闭,子组件卸载,则 ref 为空,需要加上可选链判断一下
|
||||
// Data is the initial value, where you need to manually setState to update the subcomponent state
|
||||
// If Modal has been closed early and the subassembly is uninstalled, the ref is empty. You need to add an optional chain to judge.
|
||||
tableStructureRef.current?.setTableFieldsList(
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
res.bot_table_list[0].field_list.map(i => ({
|
||||
@@ -538,7 +538,7 @@ export const DatabaseModal: React.FC<DatabaseModalProps> = props => {
|
||||
onDeleteField={list => {
|
||||
setIsDeletedField(
|
||||
!database.tableMemoryList.every(i =>
|
||||
// TODO: 当前field id生成规则有问题,故暂时使用 nanoid 替换
|
||||
// TODO: There is a problem with the current field id generation rule, so the nanoid is temporarily replaced
|
||||
list.find(j => j.nanoid === i.nanoid),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -56,7 +56,7 @@ export function formatTableDataRow(
|
||||
dataRowFieldList.forEach(_key => {
|
||||
const structItem = structList.find(i => i.fieldName === _key);
|
||||
if (!structItem) {
|
||||
// 系统字段
|
||||
// System field
|
||||
formattedDataRow[_key] = {
|
||||
fieldName: _key,
|
||||
type: FieldItemType.Text,
|
||||
@@ -157,7 +157,7 @@ function DatabaseTableCell({ value }: DatabaseTableCellProps) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Table Field 表头数据
|
||||
* Get Table Field Header Data
|
||||
*/
|
||||
export const getTableColumns = ({
|
||||
fieldList,
|
||||
@@ -168,7 +168,7 @@ export const getTableColumns = ({
|
||||
}: GetTableColumnsParams) => {
|
||||
const columns: ColumnProps<TableRow>[] = [];
|
||||
|
||||
// 系统字段列
|
||||
// System field column
|
||||
columns.push(
|
||||
...SYSTEM_FIELDS.map(item => ({
|
||||
title: () => (
|
||||
@@ -193,7 +193,7 @@ export const getTableColumns = ({
|
||||
})),
|
||||
);
|
||||
|
||||
// 用户字段列
|
||||
// user field column
|
||||
columns.push(
|
||||
...fieldList.map(item => ({
|
||||
title: () => (
|
||||
@@ -210,7 +210,7 @@ export const getTableColumns = ({
|
||||
})),
|
||||
);
|
||||
|
||||
// 操作列
|
||||
// action column
|
||||
columns.push({
|
||||
title: I18n.t('db_table_0126_021'),
|
||||
width: 100,
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/** table header样式 **/
|
||||
/** Table header style **/
|
||||
.semi-table-thead {
|
||||
// 拖拽列宽度的图标样式
|
||||
.semi-table-row {
|
||||
@@ -90,7 +90,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** table body部分样式 **/
|
||||
/** Table body part style **/
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
>.semi-table-row-cell {
|
||||
|
||||
@@ -153,7 +153,7 @@ export function DatabaseTableData({
|
||||
database_id: databaseId,
|
||||
table_type: tableType,
|
||||
record_data_alter: [values],
|
||||
// 编辑行时,要带上原始的 connector_id,后端需要判断数据是否来自/目标为“豆包”渠道
|
||||
// When editing the line, bring the original connector_id, and the backend needs to determine whether the data comes from/targets the "bean bag" channel
|
||||
ori_connector_id: originalConnectorId,
|
||||
});
|
||||
}
|
||||
@@ -230,7 +230,7 @@ export function DatabaseTableData({
|
||||
},
|
||||
rowKey: (record: TableRow) => record?.bstudio_id?.value as string,
|
||||
scroll: {
|
||||
// 128 = ToolButtonsBar(52) + 表头(28) + Pagination(48)
|
||||
// 128 = ToolButtonsBar (52) + Header (28) + Pagination (48)
|
||||
y: tableHeight > 128 ? tableHeight - 128 : 'auto',
|
||||
},
|
||||
pagination: {
|
||||
@@ -259,7 +259,7 @@ export function DatabaseTableData({
|
||||
),
|
||||
}}
|
||||
wrapperClassName={classNames(styles['table-wrapper'], {
|
||||
// database 数据表格在 Project IDE 中要使用 coz-bg-max 白色背景
|
||||
// Use coz-bg-max white background for database data tables in Project IDE
|
||||
[styles['table-wrapper-project']]: enterFrom === 'project',
|
||||
})}
|
||||
empty={
|
||||
|
||||
@@ -20,13 +20,13 @@ import { CSS } from '@dnd-kit/utilities';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
|
||||
/**
|
||||
* 拆分自 packages/data/database-v2/src/components/database-table-data/index.tsx
|
||||
* 原本实现基本是从 Semi 文档复制过来的,排序后的数据也没有提交给服务端,PM 似乎也不知道有这个功能,所以 ...
|
||||
* Split from packages/data/database-v2/src/components/database-table-data/index.tsx
|
||||
* The original implementation was basically copied from the Semi document, and the sorted data was not submitted to the server level. The PM did not seem to know about this function, so...
|
||||
* @see
|
||||
*/
|
||||
export const SortableRow = (
|
||||
// https://github.com/DouyinFE/semi-design/blob/v2.69.2/packages/semi-ui/table/Body/BaseRow.tsx#L396
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- semi 没有导出 table row props 的类型
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- semi does not export the type of table row props
|
||||
sortProps: HTMLAttributes<HTMLTableRowElement> & { 'data-row-key': string },
|
||||
) => {
|
||||
const {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { type TableMemoryItem } from '@coze-studio/bot-detail-store';
|
||||
import { type FieldItemType } from '@coze-arch/bot-api/memory';
|
||||
|
||||
// 期待的数据结构是什么样的?
|
||||
// What is the expected data structure?
|
||||
export interface TableRowCommonData {
|
||||
fieldName: string;
|
||||
required: boolean;
|
||||
|
||||
@@ -30,7 +30,7 @@ import keyExample from '../../assets/key-example.png';
|
||||
import s from './index.module.less';
|
||||
|
||||
function getTableStructureColumns(): ColumnProps<TableMemoryItem>[] {
|
||||
// 字段表头内容来自 ../database-table-structure/index.tsx:578
|
||||
// The field header content comes from../database-table-structure/index.tsx: 578
|
||||
return [
|
||||
{
|
||||
title: (
|
||||
@@ -140,7 +140,7 @@ export function DatabaseTableStructureReadonly({
|
||||
columns,
|
||||
dataSource,
|
||||
scroll: {
|
||||
// 表头的高度是 40px
|
||||
// The height of the watch header is 40px.
|
||||
y: tableHeight > 40 ? tableHeight - 40 : 'auto',
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -47,23 +47,23 @@ const formatValue = (dValue: string | Date | Date[] | string[] | undefined) => {
|
||||
|
||||
try {
|
||||
if (dValue instanceof Date) {
|
||||
// 单个Date对象
|
||||
// Single Date Object
|
||||
formattedValue = format(dValue, 'yyyy-MM-dd HH:mm:ss');
|
||||
} else if (Array.isArray(dValue)) {
|
||||
// Date[] 或 string[]
|
||||
// Date [] or string []
|
||||
formattedValue = dValue
|
||||
.map(item => {
|
||||
if (item instanceof Date) {
|
||||
return format(item, 'yyyy-MM-dd HH:mm:ss');
|
||||
} else if (typeof item === 'string') {
|
||||
// 假设字符串为有效日期格式
|
||||
// Assume string is in valid date format
|
||||
return format(new Date(item), 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
return '';
|
||||
})
|
||||
.join(', '); // 使用逗号分隔不同的日期
|
||||
.join(', '); // Use commas to separate different dates
|
||||
} else if (typeof dValue === 'string') {
|
||||
// 单个字符串
|
||||
// Single string
|
||||
formattedValue = format(new Date(dValue), 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -56,7 +56,7 @@ const FormDatePicker = withField(
|
||||
<DatePicker
|
||||
{...props}
|
||||
type="dateTime"
|
||||
// Semi DatePicker 使用 date-fns 格式
|
||||
// Semi DatePicker uses date-fns format
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
onChange={date =>
|
||||
props.onChange?.(dayjs(date as Date).format('YYYY-MM-DD HH:mm:ss'))
|
||||
@@ -149,7 +149,7 @@ export function RowEditModal({
|
||||
>
|
||||
<Form<Record<string, unknown>> allowEmpty ref={formRef}>
|
||||
{tableType === TableType.OnlineTable ? (
|
||||
// 只有“线上数据”支持修改“渠道”字段
|
||||
// Only "Online Data" supports modifying the "Channel" field
|
||||
<FormSelect
|
||||
{...getSystemFieldCommonProps(PLATFORM_FIELD)}
|
||||
optionList={connectorOptions}
|
||||
@@ -274,7 +274,7 @@ function getUserFieldCommonProps(field: TableFieldData): FieldCommonProps {
|
||||
required={field.required}
|
||||
/>
|
||||
),
|
||||
// DatabaseFieldTitle 中已经显示 required * 符号
|
||||
// The required * symbol is already displayed in DatabaseFieldTitle
|
||||
required: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -156,7 +156,7 @@ export const useSelectDatabaseModal = ({
|
||||
enterFrom === 'bot' ? TableType.DraftTable : TableType.OnlineTable,
|
||||
table_name: key_word,
|
||||
creator_id: filter_creator === 'all' ? '0' : filter_creator,
|
||||
// 暂时不做分页加载
|
||||
// Do not do paging loading for the time being
|
||||
limit: 50,
|
||||
offset: page_offset,
|
||||
order_by: [
|
||||
@@ -191,7 +191,7 @@ export const useSelectDatabaseModal = ({
|
||||
},
|
||||
);
|
||||
|
||||
// onScroll 判断 scrollRef 是否触底
|
||||
// onScroll Determines whether scrollRef bottoms out
|
||||
const handleScroll = () => {
|
||||
if (!scrollRef.current) {
|
||||
return;
|
||||
@@ -364,7 +364,7 @@ export const useSelectDatabaseModal = ({
|
||||
ref={scrollRef}
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{/* FIXME: 这里需要根据实际做渲染 */}
|
||||
{/* FIXME: This needs to be rendered according to the actual situation. */}
|
||||
{data?.list.map((item, index) => (
|
||||
<DatabaseListItem
|
||||
icon={item.icon_url}
|
||||
|
||||
@@ -21,25 +21,25 @@ import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { MemoryApi } from '@coze-arch/bot-api';
|
||||
|
||||
/**
|
||||
* 已经迁移的旧渠道 id 到新渠道 id 的映射
|
||||
* key(旧) -> value(新)
|
||||
* Mapping of migrated old channel IDs to new channel IDs
|
||||
* Key (old) - > value (new)
|
||||
*/
|
||||
const migratedConnectorIds: Record<string, string | undefined> = {
|
||||
// 微信服务号
|
||||
// WeChat service account
|
||||
'10000114': '10000120',
|
||||
// 微信订阅号
|
||||
// WeChat subscribed account
|
||||
'10000115': '10000121',
|
||||
};
|
||||
|
||||
export interface ConnectorOption {
|
||||
label: string;
|
||||
value: string;
|
||||
/** 该渠道 id 是否已经迁移 */
|
||||
/** Has the channel ID been migrated? */
|
||||
migrated?: boolean;
|
||||
}
|
||||
|
||||
export interface UseConnectorOptionsParams {
|
||||
/** 是否包含已迁移的旧渠道,默认不包含 */
|
||||
/** Whether to include the old channels that have been migrated, not by default */
|
||||
includeMigrated?: boolean;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export function useConnectorOptions({
|
||||
includeMigrated = false,
|
||||
}: UseConnectorOptionsParams = {}): ConnectorOption[] {
|
||||
const { space_id } = useParams<DynamicParams>();
|
||||
// 资源库 workflow 页面的 url 上没有 space_id 参数,需要从 searchParams 中获取
|
||||
// There is no space_id parameter on the url of the library workflow page, you need to get it from searchParams
|
||||
const [searchParams] = useSearchParams();
|
||||
const spaceId = space_id ?? searchParams.get('space_id') ?? '';
|
||||
const { data } = useRequest(
|
||||
@@ -73,7 +73,7 @@ export function useConnectorOptions({
|
||||
},
|
||||
{
|
||||
refreshDeps: [spaceId],
|
||||
// 设置缓存 key, 防止重复请求
|
||||
// Set cache key to prevent duplicate requests
|
||||
cacheKey: `db_connector_name_${spaceId}`,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
@@ -55,7 +55,7 @@ export const useExpertModeConfig = (params: {
|
||||
res = await MemoryApi.GetModeConfig({
|
||||
bot_id: botId,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 复制历史文件
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Copy history file
|
||||
} catch (error: any) {
|
||||
dataReporter.errorEvent(DataNamespace.DATABASE, {
|
||||
eventName: REPORT_EVENTS.DatabaseGetExpertConfig,
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useRef } from 'react';
|
||||
import { type TableData } from '../components/database-table-data/type';
|
||||
|
||||
export const useGetTableInstantaneousData = (tableData: TableData) => {
|
||||
// 缓存 Data 数据,用于在事件中获取数据
|
||||
// Cache data for fetching data in events
|
||||
const dataRef = useRef<TableData>(tableData);
|
||||
dataRef.current = tableData;
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ export const useLibraryCreateDatabaseModal = ({
|
||||
const { id, draft_id } = createRes.database_info ?? {};
|
||||
if (id && draft_id) {
|
||||
if (onFinish) {
|
||||
// bot 绑定数据库需要 draft_id ,其他场景一般只需要用 id
|
||||
// Bot binding database needs draft_id, other scenarios generally only need to use id
|
||||
onFinish(id, draft_id);
|
||||
return;
|
||||
} else {
|
||||
|
||||
@@ -25,7 +25,7 @@ export const getDefaultValue = (type: FieldItemType) => {
|
||||
} else if (type === FieldItemType.Text) {
|
||||
return '';
|
||||
} else if (type === FieldItemType.Date) {
|
||||
// TODO: @liushuoyan 这里可能存在时区的问题,联调的时候请注意
|
||||
// TODO: @liushuoyan There may be a time zone problem here, please pay attention when joint debugging
|
||||
return format(new Date(), 'yyyy-MM-dd HH:mm:ss');
|
||||
} else {
|
||||
return undefined;
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 符合预期
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- as expected
|
||||
export const isEmptyValue = (value: any) => value === '' || value === undefined;
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// int64 的最大值和最小值
|
||||
|
||||
// The maximum and minimum values of int64
|
||||
export const INT64_MAX = BigInt('9223372036854775807');
|
||||
export const INT64_MIN = BigInt('-9223372036854775808');
|
||||
|
||||
/**
|
||||
* 检查数值是否在 int64 范围内
|
||||
* @param value - 要检查的字符串
|
||||
* Check if the value is in the int64 range
|
||||
* @Param value - string to check
|
||||
* @returns
|
||||
* - 如果是有效的 int64 范围内的整数,返回 true
|
||||
* - 如果无效或超出范围,返回 false
|
||||
* If it is a valid integer in the int64 range, return true.
|
||||
* If invalid or out of range, return false
|
||||
*/
|
||||
export const isInInt64Range = (value: string): boolean => {
|
||||
if (
|
||||
@@ -41,7 +41,7 @@ export const isInInt64Range = (value: string): boolean => {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch -- 正常业务逻辑
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch -- normal business logic
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ import { type TableRow } from '../components/database-table-data/type';
|
||||
const FIXED_COLUMN_WIDTH = 60;
|
||||
const MIN_COLUMN_WIDTH = 100;
|
||||
/**
|
||||
* 表格列伸缩时的回调,用于限制伸缩边界
|
||||
* Callbacks when table columns are scaled to limit the scaling boundaries
|
||||
* @param column
|
||||
* @returns
|
||||
*/
|
||||
export const resizeFn = (
|
||||
column: ColumnProps<TableRow>,
|
||||
): ColumnProps<TableRow> => {
|
||||
// 多选框/序号列不可伸缩
|
||||
// The checkbox/serial number column is not retractable
|
||||
if (column.key === 'column-selection') {
|
||||
return {
|
||||
...column,
|
||||
@@ -36,14 +36,14 @@ export const resizeFn = (
|
||||
width: FIXED_COLUMN_WIDTH,
|
||||
};
|
||||
}
|
||||
// 固定列(操作列)不可伸缩
|
||||
// Fixed columns (action columns) are not scalable
|
||||
if (column.fixed) {
|
||||
return {
|
||||
...column,
|
||||
resizable: false,
|
||||
};
|
||||
}
|
||||
// 其余字段列可伸缩,但需要限制最小宽度
|
||||
// The remaining field columns are scalable, but the minimum width needs to be limited
|
||||
return {
|
||||
...column,
|
||||
width:
|
||||
|
||||
@@ -129,7 +129,7 @@ describe('MultiTable', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
// 第二个数据库应该被激活
|
||||
// The second database should be activated
|
||||
const tab = screen.getByText('Database 2').closest('div');
|
||||
expect(tab).toHaveClass(s['tab-bar-item']);
|
||||
});
|
||||
@@ -137,10 +137,10 @@ describe('MultiTable', () => {
|
||||
it('should handle database switching', () => {
|
||||
render(<MultiTable botID="test-bot" databaseList={mockDatabaseList} />);
|
||||
|
||||
// 点击第二个数据库标签
|
||||
// Click on the second database tab
|
||||
fireEvent.click(screen.getByText('Database 2'));
|
||||
|
||||
// 验证切换是否成功
|
||||
// Verify that the switch was successful
|
||||
const tab = screen.getByText('Database 2').closest('div');
|
||||
expect(tab).toHaveClass(s['tab-bar-item']);
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ export const getColumns = (
|
||||
const dataWidth = width ? width : initWidth;
|
||||
const isLast = index === _list.length - 1;
|
||||
switch (i.type) {
|
||||
// 文本
|
||||
// Text
|
||||
case FieldItemType.Text:
|
||||
res = {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -71,7 +71,7 @@ export const getColumns = (
|
||||
width: isLast ? undefined : dataWidth,
|
||||
};
|
||||
break;
|
||||
// 整数
|
||||
// integer
|
||||
case FieldItemType.Number:
|
||||
res = {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -82,7 +82,7 @@ export const getColumns = (
|
||||
width: isLast ? undefined : dataWidth,
|
||||
};
|
||||
break;
|
||||
// 数字
|
||||
// number
|
||||
case FieldItemType.Float:
|
||||
res = {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -93,7 +93,7 @@ export const getColumns = (
|
||||
width: isLast ? undefined : dataWidth,
|
||||
};
|
||||
break;
|
||||
// 时间
|
||||
// time
|
||||
case FieldItemType.Date:
|
||||
res = {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
@@ -104,7 +104,7 @@ export const getColumns = (
|
||||
width: isLast ? undefined : dataWidth,
|
||||
};
|
||||
break;
|
||||
// 布尔
|
||||
// Boolean
|
||||
case FieldItemType.Boolean:
|
||||
res = {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
|
||||
@@ -116,7 +116,7 @@ export const DataTable = forwardRef<DataTableRef, DatabaseTable>(
|
||||
const resizeList = columns.list.filter(
|
||||
item => item.dataIndex !== col.dataIndex,
|
||||
);
|
||||
// 计算拖拽列能拖拽的最小宽度,小于最小宽度则返回最小宽度
|
||||
// Calculate the minimum width that the drag column can drag, and return the minimum width if it is less than the minimum width
|
||||
const widthCount = resizeList.reduce(
|
||||
(prev, cur) => Number(prev) + Number(cur.width),
|
||||
0,
|
||||
|
||||
@@ -75,7 +75,7 @@ const ResetBtn: React.FC<DatabaseTable> = props => {
|
||||
close();
|
||||
},
|
||||
className: s['reset-confirm-modal'],
|
||||
// ToolPane的 z-index 是1000,所以此处需要加 1001 的z-index,避免被 database 数据面板遮住
|
||||
// ToolPane's z-index is 1000, so you need to add 1001 z-index here to avoid being obscured by the database data panel
|
||||
zIndex: 1001,
|
||||
});
|
||||
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Coze的渠道id,在某些场景下需要写死传递给后端
|
||||
// Coze's channel ID, in some scenarios, needs to be written dead and passed to the backend
|
||||
export const COZE_CONNECTOR_ID = '10000010';
|
||||
|
||||
@@ -53,7 +53,7 @@ export const useFileList = (
|
||||
};
|
||||
try {
|
||||
const res = await fileboxApi.FileList({
|
||||
// 前端从 1 开始计数,方便 Math.ceil 计算,传给后端时手动减 1
|
||||
// The front end starts counting from 1, which is convenient for Math.ceil calculation. When passing to the back end, manually subtract 1.
|
||||
page_num: page - 1,
|
||||
page_size: pageSize,
|
||||
bid: botId,
|
||||
|
||||
@@ -61,15 +61,15 @@ export const useUploadModal = (params: UseUploadModalParams) => {
|
||||
unitList.some(
|
||||
i =>
|
||||
/**
|
||||
* 1. 未上传成功的
|
||||
* 2. 校验失败的
|
||||
* 3. 名字为空的(名字为空暂不影响 validateMessage,所以需要单独判断)
|
||||
* 1. Unsuccessful upload
|
||||
* 2. Validation failed
|
||||
* 3. The name is empty (the name is empty will not affect the validateMessage for the time being, so it needs to be judged separately)
|
||||
*/
|
||||
i.status !== UploadStatus.SUCCESS || i.validateMessage || !i.name,
|
||||
);
|
||||
|
||||
const handleUnitListUpdate = (data: UnitItem[]) => {
|
||||
// 防止重命名后再上传被覆盖
|
||||
// Prevent renaming and then uploading from being overwritten.
|
||||
const newData = data.map(i => {
|
||||
let resultName = i.name;
|
||||
unitList.forEach(u => {
|
||||
|
||||
@@ -42,7 +42,7 @@ export const ImageList: FC<ImageListProps> = props => {
|
||||
<CardGroup spacing={12} className={s['card-group']}>
|
||||
{images?.map(i => {
|
||||
const {
|
||||
// MainURL 加载太慢了,列表中使用 ThumbnailURL 进行缩略图展示
|
||||
// MainURL is too slow to load, the list uses ThumbnailURL for thumbnail display
|
||||
ThumbnailURL: url,
|
||||
MainURL: previewUrl,
|
||||
FileID: id,
|
||||
@@ -68,7 +68,7 @@ export const ImageList: FC<ImageListProps> = props => {
|
||||
cover={
|
||||
<Image
|
||||
src={url}
|
||||
// 仅设置宽度,高度会按图片原比例自动缩放
|
||||
// Only set the width, and the height will be automatically scaled according to the original scale of the picture.
|
||||
width={209}
|
||||
className={s['card-cover']}
|
||||
preview={{
|
||||
|
||||
@@ -52,12 +52,12 @@ export const FileBoxList: FC<FileBoxListProps> = props => {
|
||||
},
|
||||
);
|
||||
|
||||
// 手动控制 data 加载时机
|
||||
// Manually control data loading timing
|
||||
useEffect(() => {
|
||||
if (botId) {
|
||||
reloadAsync();
|
||||
|
||||
// 重新加载时,回到最顶部
|
||||
// When reloading, return to the top
|
||||
ref.current?.scrollTo?.({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
@@ -85,11 +85,11 @@ export const FileBoxList: FC<FileBoxListProps> = props => {
|
||||
return (
|
||||
<div className={s['filebox-list']}>
|
||||
<div className={s.header}>
|
||||
{/* 切换图片/文档 */}
|
||||
{/* Switch images/documents */}
|
||||
<FileBoxFilter />
|
||||
|
||||
<Space spacing={12}>
|
||||
{/* 搜索框 */}
|
||||
{/* search box */}
|
||||
<UISearch
|
||||
placeholder={I18n.t(
|
||||
'card_builder_dataEditor_get_errormsg_please_enter',
|
||||
@@ -97,7 +97,7 @@ export const FileBoxList: FC<FileBoxListProps> = props => {
|
||||
onChange={debounceSearch}
|
||||
/>
|
||||
|
||||
{/* 上传按钮 */}
|
||||
{/* Upload button */}
|
||||
<UIButton type="primary" theme="solid" onClick={open}>
|
||||
{I18n.t('datasets_createFileModel_step2')}
|
||||
</UIButton>
|
||||
@@ -110,7 +110,7 @@ export const FileBoxList: FC<FileBoxListProps> = props => {
|
||||
childStyle={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
// 防止切换 fileListType 时 items 数量不一致,导致 loading 闪烁
|
||||
// Prevent inconsistent number of items when switching fileListType, causing loading to flicker
|
||||
display: loading ? 'none' : 'block',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -93,7 +93,7 @@ export const useMemoryDebugModal = ({
|
||||
</span>
|
||||
}
|
||||
>
|
||||
{/* 给 children 传递 onCancel 参数,用于从内部关闭弹窗 */}
|
||||
{/* Pass the onCancel parameter to children to close the pop-up window from within */}
|
||||
{React.isValidElement(item.component)
|
||||
? React.cloneElement(item.component, {
|
||||
onCancel: close,
|
||||
|
||||
@@ -252,7 +252,7 @@ export const VariableDebug = () => {
|
||||
{i.keyword}
|
||||
</Paragraph>
|
||||
</div>
|
||||
{/* 是否为系统字段 */}
|
||||
{/* Is it a system field? */}
|
||||
{i.is_system ? (
|
||||
<Paragraph
|
||||
data-dtestid={`${BotE2e.BotVariableDebugModalValueInput}.${i.keyword}`}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { sendTeaEvent, EVENT_NAMES } from '@coze-arch/bot-tea';
|
||||
|
||||
export const useSendTeaEventForMemoryDebug = (p: { isStore: boolean }) => {
|
||||
const { isStore = false } = p;
|
||||
// TODO@XML 看起来在商店也用到了,先不改
|
||||
// TODO@XML seems to be used in the store too, don't change it
|
||||
const params = useParams<DynamicParams>();
|
||||
const { bot_id = '', product_id = '' } = params;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
export const filterUnnecessaryContentFromSlice = (slice: string): string => {
|
||||
let res = slice;
|
||||
// 过滤img 标签
|
||||
// Filter img tags
|
||||
res = res.replaceAll(/<(\n)*img((?!(<(\n)*img))(.|\n))*>/g, '');
|
||||
return res;
|
||||
};
|
||||
|
||||
@@ -104,7 +104,7 @@ function RecallSlice(props: { llmOutput: LLMOutput; index: number }) {
|
||||
[meta.document],
|
||||
);
|
||||
|
||||
// 后面改成 staring
|
||||
// Change the back to staring.
|
||||
const sliceTag = `Recall slice ${index + 1}`;
|
||||
|
||||
const filteredSlice = filterUnnecessaryContentFromSlice(slice);
|
||||
|
||||
@@ -39,7 +39,7 @@ export const ParamName = (props: {
|
||||
const { groups } = useVariableContext();
|
||||
const formApi = useFormApi();
|
||||
|
||||
// 使用 ref 缓存最后一次的有效值, Tree组件隐藏的时候会销毁组件,Form表单的Field字段会删除,所以需要缓存
|
||||
// Use ref to cache the last valid value. When the Tree component is hidden, the component will be destroyed, and the Field field of the Form will be deleted, so it needs to be cached.
|
||||
useCacheField(data);
|
||||
|
||||
return (
|
||||
|
||||
@@ -25,24 +25,24 @@ export const requiredRules = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查变量名称是否重复
|
||||
* 1、检查变量名称在同组&同层级是否重复
|
||||
* 2、检查变量名称在不同组的Root节点名称是否重复
|
||||
* Check if variable names are duplicate
|
||||
* 1. Check whether the variable names are duplicated in the same group & level
|
||||
* 2. Check whether the variable names are duplicated in the root node names of different groups
|
||||
*/
|
||||
export const duplicateRules = {
|
||||
validate: (value: Variable, groups: VariableGroup[]): boolean => {
|
||||
if (!value.name) {
|
||||
return true;
|
||||
} // 如果名称为空则跳过检查
|
||||
} // Skip check if name is empty
|
||||
|
||||
// 1. 检查同组同层级是否重复
|
||||
// 1. Check whether the same group and level are duplicated
|
||||
const currentGroup = groups.find(group => group.groupId === value.groupId);
|
||||
|
||||
if (!currentGroup) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取当前节点所在的所有同层级节点(包括嵌套在其他节点children中的)
|
||||
// Get all nodes at the same level as the current node (including those nested in other node children)
|
||||
const findSiblings = (
|
||||
variables: Variable[],
|
||||
targetParentId: string | null,
|
||||
@@ -50,14 +50,14 @@ export const duplicateRules = {
|
||||
let result: Variable[] = [];
|
||||
|
||||
for (const variable of variables) {
|
||||
// 如果当前变量的parentId与目标parentId相同,且不是自身,则添加到结果中
|
||||
// If the parentId of the current variable is the same as the target parentId and is not itself, it is added to the result
|
||||
if (
|
||||
variable.parentId === targetParentId &&
|
||||
variable.variableId !== value.variableId
|
||||
) {
|
||||
result.push(variable);
|
||||
}
|
||||
// 递归检查children
|
||||
// Check children recursively
|
||||
if (variable.children?.length) {
|
||||
result = result.concat(
|
||||
findSiblings(variable.children, targetParentId),
|
||||
@@ -74,8 +74,8 @@ export const duplicateRules = {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 检查是否与其他组的根节点重名
|
||||
// 只有当前节点是根节点时才需要检查
|
||||
// 2. Check if it has the same name as the root node of other groups
|
||||
// Check only if the current node is the root node
|
||||
if (!value.parentId) {
|
||||
const otherGroupsRootNodes = groups
|
||||
.filter(group => group.groupId !== value.groupId)
|
||||
|
||||
@@ -49,28 +49,28 @@ export default function ParamOperator({
|
||||
}: ParamOperatorProps) {
|
||||
const isLimited = level >= 3;
|
||||
|
||||
// 是否可以添加子项
|
||||
// Is it possible to add children?
|
||||
const canAddChild = !readonly && ObjectLikeTypes.includes(data.type);
|
||||
// 子项按钮是否可用
|
||||
// Is the child button available?
|
||||
const enableAddChildButton =
|
||||
!readonly && hasObjectLike && canAddChild && needRenderAppendChild;
|
||||
// 是否显示删除按钮
|
||||
// Whether to display the delete button
|
||||
const showDeleteButton = !readonly;
|
||||
// 是否显示开启/关闭按钮
|
||||
// Whether to display the on/off button
|
||||
const enabledSwitch = level === 0;
|
||||
|
||||
const { variablePageCanEdit } = useVariableContext();
|
||||
|
||||
return (
|
||||
<div className="flex items-center h-[24px] flex-shrink-0 justify-start gap-x-2 w-[130px]">
|
||||
{/* 开启/关闭 */}
|
||||
{/* Open/close */}
|
||||
<Switch
|
||||
size="small"
|
||||
disabled={!variablePageCanEdit || !enabledSwitch}
|
||||
checked={data.enabled}
|
||||
onChange={onEnabledChange}
|
||||
/>
|
||||
{/* 添加子项 */}
|
||||
{/* Add child item */}
|
||||
{needRenderAppendChild ? (
|
||||
<div className="flex items-center justify-center">
|
||||
<Tooltip
|
||||
@@ -89,7 +89,7 @@ export default function ParamOperator({
|
||||
</Tooltip>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 删除 */}
|
||||
{/* delete */}
|
||||
<IconButton
|
||||
data-testid={VariableE2e.VariableTreeDeleteBtn}
|
||||
color="secondary"
|
||||
|
||||
@@ -33,15 +33,15 @@ export const generateVariableOption = (
|
||||
});
|
||||
|
||||
export interface VariableTypeOption {
|
||||
// 类型的值, 非叶子节点时可能为空
|
||||
// Value of type, possibly empty when not a leaf node
|
||||
value: number | string;
|
||||
// 选项的展示名称
|
||||
// The display name of the option
|
||||
label: ReactNode;
|
||||
// 回显的展示名称
|
||||
// Echoed display name
|
||||
display?: string;
|
||||
// 类型是否禁用
|
||||
// Is the type disabled?
|
||||
disabled?: boolean;
|
||||
// 子类型
|
||||
// subtype
|
||||
children?: VariableTypeOption[];
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ const filterTypes = (
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 到达层级限制时禁用 ObjectLike 类型,避免嵌套过深
|
||||
* 1. Disable the ObjectLike type when reaching the level limit to avoid too deep nesting
|
||||
*/
|
||||
const disabled = Boolean(
|
||||
level &&
|
||||
@@ -98,7 +98,7 @@ export const getVariableTypeList = options =>
|
||||
filterTypes(allVariableTypeList, options);
|
||||
|
||||
/**
|
||||
* 获取类型在选项列表中的路径,作为 cascader 的 value
|
||||
* Get the path of the type in the options list as the cascader value
|
||||
*/
|
||||
export const getCascaderVal = (
|
||||
originalVal: ViewVariableType,
|
||||
|
||||
@@ -24,7 +24,7 @@ export enum ChangeMode {
|
||||
Replace,
|
||||
}
|
||||
|
||||
// JSON类型
|
||||
// JSON type
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const JSONLikeTypes = [
|
||||
ViewVariableType.Object,
|
||||
|
||||
@@ -63,20 +63,20 @@ export default function CustomTreeNode(props: CustomTreeNodeProps) {
|
||||
onCollapse,
|
||||
validateExistKeyword = false,
|
||||
} = props;
|
||||
// 当前值
|
||||
// current value
|
||||
const value = cloneDeep(data) as Variable;
|
||||
const treeNodeRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 删除时
|
||||
// When deleting
|
||||
const onDelete = () => {
|
||||
onChange(ChangeMode.Delete, value);
|
||||
};
|
||||
|
||||
// 新增子项时
|
||||
// When adding a child
|
||||
const onAppend = () => {
|
||||
onChange(ChangeMode.Append, value);
|
||||
};
|
||||
// 类型切换时
|
||||
// When switching types
|
||||
const onSelectChange = (
|
||||
val?: string | number | Array<unknown> | Record<string, unknown>,
|
||||
) => {
|
||||
@@ -86,7 +86,7 @@ export default function CustomTreeNode(props: CustomTreeNodeProps) {
|
||||
if (!isNumber(val)) {
|
||||
return;
|
||||
}
|
||||
// 清除默认值
|
||||
// Clear default
|
||||
value.defaultValue = '';
|
||||
value.children = [];
|
||||
onChange(ChangeMode.Update, { ...value, type: val as ViewVariableType });
|
||||
|
||||
@@ -143,7 +143,7 @@ export const JSONEditor: FC<JSONEditorProps> = props => {
|
||||
|
||||
const isValid = useMemo(() => validate(value), [value]);
|
||||
|
||||
// 同步 value 和 schema
|
||||
// Synchronizing values and schemas
|
||||
useEffect(() => {
|
||||
const _schema = convert(value);
|
||||
setSchema(_schema);
|
||||
@@ -185,7 +185,7 @@ export const JSONEditor: FC<JSONEditorProps> = props => {
|
||||
key={id}
|
||||
value={value}
|
||||
defaultLanguage="json"
|
||||
/** 通过 css 样式覆盖 icube-dark 主题 */
|
||||
/** Override icube-dark theme with css style */
|
||||
className={lightStyles.light}
|
||||
options={{
|
||||
fontSize: 13,
|
||||
|
||||
@@ -47,19 +47,19 @@ export const JSONImport: FC<JSONImportProps> = props => {
|
||||
const [jsonString, setJsonString] = useState('');
|
||||
|
||||
const handleImport = (data: SchemaNode[]) => {
|
||||
const allowDepth = MAX_LEVEL; // 最大深度限制
|
||||
const allowNameLength = MAX_NAME_LENGTH; // 名称长度限制
|
||||
const maxVariableCount = MAX_JSON_VARIABLE_COUNT; // 最大变量数量限制
|
||||
const allowDepth = MAX_LEVEL; // Maximum depth limit
|
||||
const allowNameLength = MAX_NAME_LENGTH; // Name length limit
|
||||
const maxVariableCount = MAX_JSON_VARIABLE_COUNT; // Maximum number of variables limit
|
||||
const variables = exportVariableService(
|
||||
data,
|
||||
{
|
||||
groupId: treeData.groupId,
|
||||
channel: treeData.channel,
|
||||
},
|
||||
treeData, // 传入原始变量以保持variableId
|
||||
treeData, // Pass in the original variable to maintain the variableId.
|
||||
);
|
||||
|
||||
// 裁切非法数据
|
||||
// Crop illegal data
|
||||
const dataCutoff = cutOffInvalidData({
|
||||
data: variables,
|
||||
allowDepth,
|
||||
@@ -67,12 +67,12 @@ export const JSONImport: FC<JSONImportProps> = props => {
|
||||
maxVariableCount,
|
||||
});
|
||||
|
||||
// 先深拷贝原始数据
|
||||
// First deep copy the original data source
|
||||
const clonedTreeData = cloneDeep(treeData);
|
||||
// 合并新旧数据
|
||||
// Merge old and new data
|
||||
const mergedData = merge(clonedTreeData, dataCutoff[0]);
|
||||
|
||||
// 更新数据
|
||||
// update data
|
||||
return onOk(mergedData);
|
||||
};
|
||||
|
||||
|
||||
@@ -65,14 +65,14 @@ export const getEditorViewVariableJson = (treeData: TreeNodeCustomData) => {
|
||||
);
|
||||
}
|
||||
|
||||
// 如果没有name,返回空对象
|
||||
// If there is no name, return an empty object
|
||||
if (!name) {
|
||||
return '{}';
|
||||
}
|
||||
|
||||
const isArray = isArrayType(type);
|
||||
|
||||
// 递归处理children
|
||||
// Recursive processing of children
|
||||
const processChildren = (
|
||||
nodes?: TreeNodeCustomData[],
|
||||
parentType?: ViewVariableType,
|
||||
@@ -87,7 +87,7 @@ export const getEditorViewVariableJson = (treeData: TreeNodeCustomData) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 如果是数组类型,根据第一个子元素的类型生成默认值
|
||||
// If it is an array type, generate a default value based on the type of the first child element
|
||||
const result = {};
|
||||
if (firstChild.children && firstChild.children.length > 0) {
|
||||
result[firstChild.name] = processChildren(
|
||||
@@ -117,7 +117,7 @@ export const getEditorViewVariableJson = (treeData: TreeNodeCustomData) => {
|
||||
);
|
||||
};
|
||||
|
||||
// 生成最终的JSON结构
|
||||
// Generate the final JSON structure
|
||||
const result = {
|
||||
[name]: processChildren(children),
|
||||
};
|
||||
|
||||
@@ -23,10 +23,10 @@ import { type Variable } from '@/store';
|
||||
import { type SchemaNode } from '../../../json-editor/service/convert-schema-service';
|
||||
|
||||
/**
|
||||
* 将转换后的数据转换为Variable
|
||||
* @param data 转换后的数据
|
||||
* @param baseInfo 基础信息
|
||||
* @param originalVariable 原始变量,用于保持variableId
|
||||
* Converting Converted Data to Variables
|
||||
* @param data converted data
|
||||
* @param baseInfo
|
||||
* @param originalVariable to hold variableId
|
||||
* @returns Variable[]
|
||||
*/
|
||||
export const exportVariableService = (
|
||||
@@ -44,7 +44,7 @@ export const exportVariableService = (
|
||||
parentId = '',
|
||||
originalNode?: Variable,
|
||||
): Variable => {
|
||||
// 使用store中的createVariable方法创建基础变量
|
||||
// Create the underlying variable using the createVariable method in the store
|
||||
const baseVariable = store.createVariable({
|
||||
variableType: node.type as ViewVariableType,
|
||||
groupId: baseInfo.groupId,
|
||||
@@ -52,17 +52,17 @@ export const exportVariableService = (
|
||||
channel: baseInfo.channel,
|
||||
});
|
||||
|
||||
// 如果存在原始节点,保持其variableId
|
||||
// If the original node exists, keep its variableId.
|
||||
if (originalNode) {
|
||||
baseVariable.variableId = originalNode.variableId;
|
||||
baseVariable.description = originalNode.description;
|
||||
}
|
||||
|
||||
// 更新变量的基本信息
|
||||
// Update basic information about variables
|
||||
baseVariable.name = node.name;
|
||||
baseVariable.defaultValue = node.defaultValue;
|
||||
|
||||
// 递归处理子节点,尝试匹配原始子节点
|
||||
// Recursively process the sub-node and try to match the original sub-node.
|
||||
if (node.children?.length) {
|
||||
baseVariable.children = node.children.map((child, index) => {
|
||||
const originalChild = originalNode?.children?.[index];
|
||||
@@ -75,7 +75,7 @@ export const exportVariableService = (
|
||||
|
||||
const variables = data.map(node => convertNode(node, '', originalVariable));
|
||||
|
||||
// 使用store中的updateMeta方法更新meta信息
|
||||
// Update meta information using the updateMeta method in the store
|
||||
store.updateMeta({ variables });
|
||||
|
||||
return variables;
|
||||
|
||||
@@ -19,7 +19,7 @@ import { nanoid } from 'nanoid';
|
||||
import type { TreeNodeCustomData } from '../../../type';
|
||||
import { traverse, type TraverseContext } from './traverse';
|
||||
|
||||
/** 计算路径 */
|
||||
/** Compute Path */
|
||||
const getTreePath = (context: TraverseContext): string => {
|
||||
const parents = context
|
||||
.getParents()
|
||||
@@ -32,14 +32,14 @@ const getTreePath = (context: TraverseContext): string => {
|
||||
return parents.map(node => node.value.name).join('/');
|
||||
};
|
||||
|
||||
/** 新旧数据保留 key 防止变量系统引用失效 */
|
||||
/** Old and new data keep keys to prevent variable system references from invalidating */
|
||||
export const mergeData = (params: {
|
||||
newData: TreeNodeCustomData;
|
||||
oldData: TreeNodeCustomData;
|
||||
}): TreeNodeCustomData => {
|
||||
const { newData, oldData } = params;
|
||||
|
||||
// 计算旧数据中路径与key的映射
|
||||
// Compute the mapping of paths and keys in old data
|
||||
const treeDataPathKeyMap = new Map<
|
||||
string,
|
||||
{
|
||||
@@ -60,7 +60,7 @@ export const mergeData = (params: {
|
||||
});
|
||||
});
|
||||
|
||||
// 新数据复用旧数据的key,失败则重新生成
|
||||
// The new data reuses the key of the old data, and if it fails, it is regenerated.
|
||||
const newDataWithKey = traverse(newData, context => {
|
||||
if (
|
||||
typeof context.node.value !== 'object' ||
|
||||
|
||||
@@ -37,9 +37,9 @@ export interface TraverseContext {
|
||||
export type TraverseHandler = (context: TraverseContext) => void;
|
||||
|
||||
/**
|
||||
* 深度遍历对象,对每个值做处理
|
||||
* @param value 遍历对象
|
||||
* @param handle 处理函数
|
||||
* Traverse the object in depth, processing each value
|
||||
* @param value over object
|
||||
* @param handling function
|
||||
*/
|
||||
export const traverse = <T extends TraverseValue = TraverseValue>(
|
||||
value: T,
|
||||
@@ -56,9 +56,9 @@ export const traverse = <T extends TraverseValue = TraverseValue>(
|
||||
|
||||
namespace TraverseUtils {
|
||||
/**
|
||||
* 深度遍历对象,对每个值做处理
|
||||
* @param node 遍历节点
|
||||
* @param handle 处理函数
|
||||
* Traverse the object in depth, processing each value
|
||||
* @param node traverse node
|
||||
* @param handling function
|
||||
*/
|
||||
export const traverseNodes = (
|
||||
node: TraverseNode,
|
||||
@@ -66,11 +66,11 @@ namespace TraverseUtils {
|
||||
): void => {
|
||||
const { value } = node;
|
||||
if (!value) {
|
||||
// 异常处理
|
||||
// exception handling
|
||||
return;
|
||||
}
|
||||
if (Object.prototype.toString.call(value) === '[object Object]') {
|
||||
// 对象,遍历对象的每个属性
|
||||
// Object, iterate through each property of the object
|
||||
Object.entries(value).forEach(([key, item]) =>
|
||||
traverseNodes(
|
||||
{
|
||||
@@ -83,8 +83,8 @@ namespace TraverseUtils {
|
||||
),
|
||||
);
|
||||
} else if (Array.isArray(value)) {
|
||||
// 数组,遍历数组的每个元素
|
||||
// 从数组的末尾开始遍历,这样即使中途移除了某个元素,也不会影响到未处理的元素的索引
|
||||
// Array, iterate through each element of the array
|
||||
// The iteration starts at the end of the array, so that even if an element is removed halfway through, it will not affect the index of the unprocessed element
|
||||
for (let index = value.length - 1; index >= 0; index--) {
|
||||
const item: string = value[index];
|
||||
traverseNodes(
|
||||
@@ -116,14 +116,14 @@ namespace TraverseUtils {
|
||||
});
|
||||
|
||||
const setValue = (node: TraverseNode, value: unknown) => {
|
||||
// 设置值函数
|
||||
// 引用类型,需要借助父元素修改值
|
||||
// 由于是递归遍历,所以需要根据node来判断是给对象的哪个属性赋值,还是给数组的哪个元素赋值
|
||||
// Set Value Function
|
||||
// Reference type, you need to modify the value with the help of the parent element
|
||||
// Since it is a recursive traversal, it is necessary to determine which property of the object to assign a value to, or which element of the array to assign a value to, according to node
|
||||
if (!value || !node) {
|
||||
return;
|
||||
}
|
||||
node.value = value;
|
||||
// 从上级作用域node中取出container,key,index
|
||||
// Remove container, key, index from upper scope node
|
||||
const { container, key, index } = node;
|
||||
if (key && container) {
|
||||
container[key] = value;
|
||||
@@ -161,7 +161,7 @@ namespace TraverseUtils {
|
||||
if (typeof pathItem === 'string') {
|
||||
const re = /\W/g;
|
||||
if (re.test(pathItem)) {
|
||||
// 包含特殊字符
|
||||
// Contains special characters
|
||||
return `${stringifyPath}["${pathItem}"]`;
|
||||
}
|
||||
return `${stringifyPath}.${pathItem}`;
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
/** 每一级树缩进宽度 */
|
||||
/** Indent width of each level of tree */
|
||||
export const TreeIndentWidth = 30;
|
||||
/** 树节点展开收起按钮宽度 */
|
||||
/** Tree Node Expand Collapse Button Width */
|
||||
export const TreeCollapseWidth = 24;
|
||||
|
||||
// 名称最长50字符
|
||||
// Name Maximum 50 characters
|
||||
export const MAX_NAME_LENGTH = 50;
|
||||
|
||||
// 最大深度限制
|
||||
// Maximum depth limit
|
||||
export const MAX_LEVEL = 3;
|
||||
// 最大变量数量限制
|
||||
// Maximum number of variables limit
|
||||
export const MAX_JSON_VARIABLE_COUNT = 1;
|
||||
// 最大JSON长度限制30kb
|
||||
// Maximum JSON length limit 30kb
|
||||
export const MAX_JSON_LENGTH = 30 * 1024;
|
||||
|
||||
@@ -51,7 +51,7 @@ export interface VariableTreeProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
showAddButton?: boolean;
|
||||
/** 默认变量类型 */
|
||||
/** Default variable type */
|
||||
defaultVariableType?: ViewVariableType;
|
||||
defaultCollapse?: boolean;
|
||||
children?: React.ReactNode;
|
||||
@@ -172,7 +172,7 @@ export function Index(
|
||||
});
|
||||
};
|
||||
|
||||
// 树节点的 change 方法
|
||||
// Tree node change method
|
||||
const onTreeNodeChange = (mode: ChangeMode, param: TreeNodeCustomData) => {
|
||||
const findResult = findAndModifyVariable(
|
||||
groupId,
|
||||
@@ -194,7 +194,7 @@ export function Index(
|
||||
});
|
||||
addChildVariable(childVariable);
|
||||
|
||||
// 当前节点下新增节点 展开当前节点
|
||||
// Add a new node under the current node and expand the current node
|
||||
if (findResult?.variableId) {
|
||||
expandTreeNode(findResult.variableId);
|
||||
}
|
||||
@@ -231,13 +231,13 @@ export function Index(
|
||||
}
|
||||
case ChangeMode.UpdateEnabled: {
|
||||
findResult.enabled = param.enabled;
|
||||
// 一键关闭所有子节点
|
||||
// Close all sub-nodes with one click
|
||||
traverse<TreeNodeCustomData>(findResult, node => {
|
||||
if (!param.enabled) {
|
||||
node.enabled = param.enabled;
|
||||
}
|
||||
});
|
||||
// 子点开启,父节点也开启
|
||||
// The child point is turned on, and the parent node is also turned on.
|
||||
if (findResult.parentId && findResult.enabled) {
|
||||
const parentData = findAndModifyVariable(
|
||||
groupId,
|
||||
@@ -284,11 +284,11 @@ export function Index(
|
||||
<VariableTreeContext.Provider value={{ groupId, variables: flatTreeData }}>
|
||||
<div
|
||||
className={classNames(
|
||||
// 基础容器样式
|
||||
// basic container style
|
||||
'relative h-full',
|
||||
// 交互状态
|
||||
// interaction state
|
||||
!readonly && 'cursor-default',
|
||||
// 自定义类名
|
||||
// custom class name
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
@@ -301,20 +301,20 @@ export function Index(
|
||||
}}
|
||||
disabled={readonly}
|
||||
className={classNames(
|
||||
// 基础滚动行为
|
||||
// basic scrolling behavior
|
||||
'overflow-x-auto',
|
||||
|
||||
// Tree 列表基础样式
|
||||
// Tree list base style
|
||||
[
|
||||
// 列表容器样式
|
||||
// list container style
|
||||
'[&_.semi-tree-option-list]:overflow-visible',
|
||||
'[&_.semi-tree-option-list]:p-0',
|
||||
'[&_.semi-tree-option-list>div:first-child]:mt-0',
|
||||
// 选项样式
|
||||
// Option style
|
||||
'[&_.semi-tree-option]:!pl-2',
|
||||
].join(' '),
|
||||
|
||||
// 交互状态样式
|
||||
// interaction state style
|
||||
readonly
|
||||
? '[&_.semi-tree-option-list-block_.semi-tree-option:hover]:bg-inherit'
|
||||
: [
|
||||
@@ -371,5 +371,5 @@ export function Index(
|
||||
);
|
||||
}
|
||||
|
||||
// 导出可调用ref方法的组件
|
||||
// Export components that can call the ref method
|
||||
export const VariableTree = React.forwardRef(Index);
|
||||
|
||||
@@ -22,7 +22,7 @@ import { type ChangeMode } from './components/custom-tree-node/constants';
|
||||
|
||||
export interface RecursedParamDefinition {
|
||||
name?: string;
|
||||
/** Tree 组件要求每一个节点都有 key,而 key 不适合用名称(前后缀)等任何方式赋值,最终确定由接口转换层一次性提供随机 key */
|
||||
/** The Tree component requires each node to have a key, and the key is not suitable for assignment in any way such as name (before and after). Finally, the interface conversion layer provides a random key at one time. */
|
||||
fieldRandomKey?: string;
|
||||
desc?: string;
|
||||
type: ViewVariableType;
|
||||
@@ -35,14 +35,14 @@ export interface CustomTreeNodeFuncRef {
|
||||
data: TreeNodeCustomData;
|
||||
level: number;
|
||||
readonly: boolean;
|
||||
// 通用change方法
|
||||
// General change method
|
||||
onChange: (mode: ChangeMode, param: TreeNodeCustomData) => void;
|
||||
// 定制的类型改变的change方法,主要用于自定义render使用
|
||||
// 添加子项
|
||||
// Customized type change method, mainly used for custom rendering
|
||||
// Add child item
|
||||
onAppend: () => void;
|
||||
// 删除该项
|
||||
// Delete this item
|
||||
onDelete: () => void;
|
||||
// 类型改变时内部的调用方法,主要用于从类Object类型转为其他类型时需要删除所有子项
|
||||
// The internal call method when the type changes, mainly used to delete all children when converting from the class Object type to other types
|
||||
onSelectChange: (
|
||||
val?: string | number | Array<unknown> | Record<string, unknown>,
|
||||
) => void;
|
||||
|
||||
@@ -32,7 +32,7 @@ interface ChildrenFindResult {
|
||||
|
||||
export type FindDataResult = RootFindResult | ChildrenFindResult | null;
|
||||
/**
|
||||
* 根据target数组,找到key在该项的值和位置,主要是获取位置,方便操作parent的children
|
||||
* According to the target array, find the value and position of the key in the item, mainly to obtain the position, which is convenient for operating the children of the parent.
|
||||
*/
|
||||
export function findCustomTreeNodeDataResult(
|
||||
target: Array<TreeNodeCustomData>,
|
||||
@@ -40,7 +40,7 @@ export function findCustomTreeNodeDataResult(
|
||||
): FindDataResult {
|
||||
const dataInRoot = target.find(item => item.variableId === variableId);
|
||||
if (dataInRoot) {
|
||||
// 如果是根节点
|
||||
// If it is the root node
|
||||
return {
|
||||
isRoot: true,
|
||||
parentData: null,
|
||||
@@ -81,7 +81,7 @@ export function findCustomTreeNodeDataResult(
|
||||
return findDataInChildrenLoop(target);
|
||||
}
|
||||
|
||||
// 将groupVariableMeta打平为viewVariableTreeNode[]
|
||||
// Flatten groupVariableMeta to viewVariableTreeNode []
|
||||
export function flatGroupVariableMeta(
|
||||
groupVariableMeta: VariableGroup[],
|
||||
maxDepth = Infinity,
|
||||
|
||||
@@ -37,7 +37,7 @@ export const VariablesPage = () => {
|
||||
type="text"
|
||||
className={classNames(
|
||||
'h-full flex flex-col',
|
||||
// 滚动条位置调整到 tab 内容中
|
||||
// Scroll bar position is adjusted to tab content
|
||||
'[&_.semi-tabs-content]:p-0 [&_.semi-tabs-content]:grow [&_.semi-tabs-content]:overflow-hidden',
|
||||
'[&_.semi-tabs-pane-active]:h-full',
|
||||
'[&_.semi-tabs-pane-motion-overlay]:h-full [&_.semi-tabs-pane-motion-overlay]:overflow-auto',
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { useVariableGroupsStore } from '../../store';
|
||||
/**
|
||||
* 提交变量
|
||||
* commit variable
|
||||
* @param projectID
|
||||
* @returns
|
||||
*/
|
||||
@@ -38,9 +38,9 @@ export async function submit(projectID: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并确保 projectID 是非空字符串
|
||||
* @param projectID 可能为空的项目ID
|
||||
* @returns projectID 是否为非空字符串
|
||||
* Check and make sure projectID is a non-empty string
|
||||
* @param projectID possibly empty project ID
|
||||
* @Returns whether projectID is a non-empty string
|
||||
*/
|
||||
export const checkProjectID = (projectID: unknown): projectID is string =>
|
||||
typeof projectID === 'string' && projectID.length > 0;
|
||||
|
||||
@@ -85,27 +85,27 @@ export interface VariableGroupsAction {
|
||||
parentId: string;
|
||||
channel: VariableChannel;
|
||||
}) => Variable;
|
||||
// 更新变量, 根据groupId和variableId更新
|
||||
// Update variables, according to groupId and variableId
|
||||
updateVariable: (newVariable: Variable) => void;
|
||||
// 更新变量的meta信息
|
||||
// Update the meta information of the variable
|
||||
updateMeta: (params: {
|
||||
variables: Variable[];
|
||||
level?: number;
|
||||
parentId?: string;
|
||||
}) => void;
|
||||
// 新增根节点变量
|
||||
// Add root node variable
|
||||
addRootVariable: (variable: Omit<Variable, 'channel'>) => void;
|
||||
// 新增子节点变量
|
||||
// Add sub-node variable
|
||||
addChildVariable: (variable: Variable) => void;
|
||||
// 删除变量
|
||||
// Delete variable
|
||||
deleteVariable: (variable: Variable) => void;
|
||||
// 保存后作为历史变量对待
|
||||
// After being preserved, it is treated as a historical variable
|
||||
saveHistory: () => void;
|
||||
// 获取DTO variable
|
||||
// Get DTO variable
|
||||
getDtoVariable: (variable: Variable) => ProjectMemory.Variable;
|
||||
// 获取groups下所有的变量
|
||||
// Get all the variables under groups
|
||||
getAllRootVariables: () => Variable[];
|
||||
// 获取groups下所有的变量
|
||||
// Get all the variables under groups
|
||||
getAllVariables: () => Variable[];
|
||||
transformDto2Vo: (data: ProjectMemory.GroupVariableInfo[]) => VariableGroup[];
|
||||
initStore: (data: {
|
||||
@@ -113,7 +113,7 @@ export interface VariableGroupsAction {
|
||||
canEdit: boolean;
|
||||
}) => void;
|
||||
clear: () => void;
|
||||
// 在变量树中查找变量,并可选地修改或删除
|
||||
// Locate variables in the variable tree and optionally modify or delete them
|
||||
findAndModifyVariable: (
|
||||
groupId: string,
|
||||
predicate: (variable: Variable) => boolean,
|
||||
@@ -328,7 +328,7 @@ export const useVariableGroupsStore = create<
|
||||
},
|
||||
transformDto2Vo: data => {
|
||||
const transformedData = getGroupListByDto(data);
|
||||
// 在数据转换完成后,立即更新meta信息
|
||||
// After the data conversion is completed, update the meta information immediately
|
||||
transformedData.forEach(group => {
|
||||
get().updateMeta({ variables: group.varInfoList });
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ const getSubGroupListByDto = ({
|
||||
subGroupList?.map(subGroup => ({
|
||||
...getBaseGroupInfoByDto({
|
||||
...subGroup,
|
||||
DefaultChannel: group.DefaultChannel, // 服务端返回的 subGroup 没有 DefaultChannel需要手动设置
|
||||
DefaultChannel: group.DefaultChannel, // The subGroup returned by the server level has no DefaultChannel and needs to be set manually
|
||||
}),
|
||||
groupId,
|
||||
varInfoList: getGroupVariableListByDto({
|
||||
|
||||
@@ -24,7 +24,7 @@ import { type VariableSchemaDTO, VariableTypeDTO } from '../types';
|
||||
import { type Variable } from '../store';
|
||||
|
||||
/**
|
||||
* 前端变量类型
|
||||
* Front-end variable type
|
||||
*/
|
||||
export enum ViewVariableType {
|
||||
String = 1,
|
||||
@@ -32,7 +32,7 @@ export enum ViewVariableType {
|
||||
Boolean,
|
||||
Number,
|
||||
Object = 6,
|
||||
// 上面是 api 中定义的 InputType。下面是整合后的。从 99 开始,避免和后端定义撞车
|
||||
// The above is the InputType defined in the api. The following is the integrated one. Start from 99 to avoid collisions with the backend definition.
|
||||
ArrayString = 99,
|
||||
ArrayInteger,
|
||||
ArrayBoolean,
|
||||
@@ -101,7 +101,7 @@ export const getDtoVariable = (
|
||||
schema: '',
|
||||
};
|
||||
|
||||
// 处理数组类型
|
||||
// Working with array types
|
||||
if (type === VariableTypeDTO.List && arrayItemType) {
|
||||
if (arrayItemType === VariableTypeDTO.Object) {
|
||||
schema.schema = {
|
||||
@@ -118,7 +118,7 @@ export const getDtoVariable = (
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对象类型
|
||||
// Handling object types
|
||||
if (type === VariableTypeDTO.Object) {
|
||||
schema.schema = viewVariable.children?.map(child => {
|
||||
const childDTO = getDtoVariable(child);
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface VariableSchemaDTO {
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端变量类型
|
||||
* Front-end variable type
|
||||
*/
|
||||
export enum ViewVariableType {
|
||||
String = 1,
|
||||
@@ -42,7 +42,7 @@ export enum ViewVariableType {
|
||||
Boolean,
|
||||
Number,
|
||||
Object = 6,
|
||||
// 上面是 api 中定义的 InputType。下面是整合后的。从 99 开始,避免和后端定义撞车
|
||||
// The above is the InputType defined in the api. The following is the integrated one. Start from 99 to avoid collisions with the backend definition.
|
||||
ArrayString = 99,
|
||||
ArrayInteger,
|
||||
ArrayBoolean,
|
||||
@@ -73,7 +73,7 @@ export const VARIABLE_TYPE_ALIAS_MAP: Record<ViewVariableType, string> = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace ViewVariableType {
|
||||
/**
|
||||
* 获取所有变量类型的补集
|
||||
* Get the complement of all variable types
|
||||
* @param inputTypes
|
||||
*/
|
||||
export function getComplement(inputTypes: ViewVariableType[]) {
|
||||
|
||||
Reference in New Issue
Block a user