feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import {
|
||||
type PluginMockSetCommonParams,
|
||||
type PluginMockDataGenerateMode,
|
||||
} from '@coze-arch/bot-tea';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import {
|
||||
Space,
|
||||
Toast,
|
||||
UIButton,
|
||||
UIModal,
|
||||
Typography,
|
||||
Divider,
|
||||
} from '@coze-arch/bot-semi';
|
||||
import { SpaceType } from '@coze-arch/bot-api/playground_api';
|
||||
import { type mockset, type infra } from '@coze-arch/bot-api/debugger_api';
|
||||
import {
|
||||
calcStringSize,
|
||||
type MockDataInfo,
|
||||
MAX_SUBMIT_LENGTH,
|
||||
getEnvironment,
|
||||
} from '@coze-studio/mockset-shared';
|
||||
import {
|
||||
MocksetEditor,
|
||||
type EditorAreaActions,
|
||||
} from '@coze-studio/mockset-editor-adapter';
|
||||
|
||||
import {
|
||||
PRE_DEFINED_NO_EMPTY_KEY,
|
||||
useTransSchema,
|
||||
} from '../hook/use-trans-schema';
|
||||
import { useSaveMockData } from '../hook/use-save-mock-data';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export enum CreationMode {
|
||||
/** 弹窗形式 */
|
||||
MODAL = 'modal',
|
||||
/** 嵌入页面 */
|
||||
CARD = 'card',
|
||||
}
|
||||
|
||||
interface MockDataCreateCardProps {
|
||||
mode: CreationMode;
|
||||
mockInfo?: MockDataInfo;
|
||||
// mode 为 modal 时生效
|
||||
visible?: boolean;
|
||||
// mode 为 modal 时生效
|
||||
onCancel?: () => void;
|
||||
onSuccess: (data?: mockset.MockRule[]) => void;
|
||||
bizCtx: infra.BizCtx;
|
||||
forceGenerate?: {
|
||||
mode: PluginMockDataGenerateMode;
|
||||
count: number;
|
||||
};
|
||||
}
|
||||
|
||||
/** 创建or编辑 mock data - */
|
||||
export function MockDataCreateCard({
|
||||
mode,
|
||||
mockInfo,
|
||||
visible,
|
||||
onCancel,
|
||||
onSuccess,
|
||||
bizCtx,
|
||||
forceGenerate,
|
||||
}: MockDataCreateCardProps) {
|
||||
const { schema } = mockInfo || {};
|
||||
const editorsRef = useRef<EditorAreaActions>(null);
|
||||
const [disableSubmit, setDisableSubmit] = useState(false);
|
||||
const [disableSubmitWhenGenerating, setDisableSubmitWhenGenerating] =
|
||||
useState(false);
|
||||
|
||||
const { testValueValid, formattedResultExample: initialExample } =
|
||||
useTransSchema(schema);
|
||||
const { mock_set_id, tool_id } = useParams<DynamicParams>();
|
||||
|
||||
// space信息
|
||||
const spaceType = useSpaceStore(store => store.space.space_type);
|
||||
const isPersonal = spaceType === SpaceType.Personal;
|
||||
|
||||
const basicParams: PluginMockSetCommonParams = {
|
||||
environment: getEnvironment(),
|
||||
workspace_id: bizCtx.bizSpaceID || '',
|
||||
workspace_type: isPersonal ? 'personal_workspace' : 'team_workspace',
|
||||
tool_id: tool_id || '',
|
||||
mock_set_id: mock_set_id || '',
|
||||
};
|
||||
|
||||
const { save, loading } = useSaveMockData({
|
||||
mockSetId: mock_set_id,
|
||||
basicParams,
|
||||
bizCtx,
|
||||
onSuccess,
|
||||
});
|
||||
|
||||
const confirmHandler = () => {
|
||||
const values = editorsRef.current?.getValue();
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const value of values) {
|
||||
if (!value) {
|
||||
Toast.error('no data');
|
||||
return;
|
||||
}
|
||||
|
||||
if (calcStringSize(value) > MAX_SUBMIT_LENGTH) {
|
||||
Toast.error({
|
||||
content: I18n.t('mockset_toast_data_size_limit'),
|
||||
showClose: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!testValueValid(value)) {
|
||||
Toast.error({
|
||||
content: I18n.t('mockdata_field_empty', {
|
||||
fieldName: PRE_DEFINED_NO_EMPTY_KEY,
|
||||
}),
|
||||
showClose: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const mockDataId = String(mockInfo?.mock?.id || 0);
|
||||
|
||||
save(values, mockDataId);
|
||||
};
|
||||
|
||||
const validateHandler = (isValid: boolean[]) => {
|
||||
setDisableSubmit(isValid.some(v => !v));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const unloadHandler = e => {
|
||||
const info = I18n.t('mockset_tip_data_will_lose');
|
||||
e.preventDefault();
|
||||
e.returnValue = info;
|
||||
return info;
|
||||
};
|
||||
|
||||
if (
|
||||
(mode === CreationMode.MODAL && visible) ||
|
||||
mode === CreationMode.CARD
|
||||
) {
|
||||
window.addEventListener('beforeunload', unloadHandler);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', unloadHandler);
|
||||
};
|
||||
}, [mode, visible]);
|
||||
|
||||
useEffect(() => {
|
||||
if (forceGenerate) {
|
||||
editorsRef.current?.forceStartGenerate?.(
|
||||
forceGenerate.mode,
|
||||
forceGenerate.count,
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return mode === CreationMode.MODAL ? (
|
||||
<UIModal
|
||||
visible={visible}
|
||||
title={
|
||||
mockInfo?.mock ? I18n.t('edit_mock_data') : I18n.t('add_mock_data')
|
||||
}
|
||||
className={s['mock-creation-modal']}
|
||||
keepDOM={false}
|
||||
footer={
|
||||
<>
|
||||
<span className="mr-[8px]">{I18n.t('mockset_save_description')}</span>
|
||||
<Divider layout="vertical" margin="0px" />
|
||||
<UIButton type={'tertiary'} key="Cancel" onClick={onCancel}>
|
||||
{I18n.t('cancel')}
|
||||
</UIButton>
|
||||
<UIButton
|
||||
type={'primary'}
|
||||
theme={'solid'}
|
||||
key="Confirm"
|
||||
onClick={confirmHandler}
|
||||
loading={loading}
|
||||
disabled={disableSubmit || disableSubmitWhenGenerating}
|
||||
>
|
||||
{I18n.t('confirm')}
|
||||
</UIButton>
|
||||
</>
|
||||
}
|
||||
width={1000}
|
||||
maskClosable={false}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
<MocksetEditor
|
||||
className={s['mock-creation-modal-editor']}
|
||||
mockInfo={{
|
||||
mergedResultExample: initialExample,
|
||||
...mockInfo,
|
||||
}}
|
||||
readOnly={false}
|
||||
ref={editorsRef}
|
||||
onValidate={validateHandler}
|
||||
environment={{
|
||||
spaceId: bizCtx.bizSpaceID,
|
||||
mockSetId: mock_set_id,
|
||||
basicParams,
|
||||
}}
|
||||
isCreateScene={!mockInfo?.mock}
|
||||
onGenerationStatusChange={isGenerating =>
|
||||
setDisableSubmitWhenGenerating(isGenerating)
|
||||
}
|
||||
/>
|
||||
</UIModal>
|
||||
) : (
|
||||
<div className={s['mock-creation-card']}>
|
||||
<div className={s['mock-creation-card-editor']}>
|
||||
<MocksetEditor
|
||||
mockInfo={{
|
||||
mergedResultExample: initialExample,
|
||||
...mockInfo,
|
||||
}}
|
||||
ref={editorsRef}
|
||||
onValidate={validateHandler}
|
||||
environment={{
|
||||
spaceId: bizCtx.bizSpaceID,
|
||||
mockSetId: mock_set_id,
|
||||
basicParams,
|
||||
}}
|
||||
isCreateScene={!mockInfo?.mock}
|
||||
onGenerationStatusChange={isGenerating =>
|
||||
setDisableSubmitWhenGenerating(isGenerating)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={s['mock-creation-card-operation']}>
|
||||
<Space>
|
||||
<Typography.Text>
|
||||
{I18n.t('mockset_save_description')}
|
||||
</Typography.Text>
|
||||
<Divider layout="vertical" margin="0px" />
|
||||
<UIButton
|
||||
type={'primary'}
|
||||
theme={'solid'}
|
||||
onClick={confirmHandler}
|
||||
loading={loading}
|
||||
disabled={disableSubmit || disableSubmitWhenGenerating}
|
||||
>
|
||||
{I18n.t('mockset_save')}
|
||||
</UIButton>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user