feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { mergeConfig } from 'vite';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
viteFinal: config =>
|
||||
mergeConfig(config, {
|
||||
plugins: [
|
||||
svgr({
|
||||
svgrOptions: {
|
||||
native: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
};
|
||||
export default config;
|
||||
@@ -0,0 +1,14 @@
|
||||
/** @type { import('@storybook/react').Preview } */
|
||||
const preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
16
frontend/packages/agent-ide/bot-config-area/README.md
Normal file
16
frontend/packages/agent-ide/bot-config-area/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# @coze-agent-ide/bot-config-area
|
||||
|
||||
> Project template for react component with storybook.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] eslint & ts
|
||||
- [x] esm bundle
|
||||
- [x] umd bundle
|
||||
- [x] storybook
|
||||
|
||||
## Commands
|
||||
|
||||
- init: `rush update`
|
||||
- dev: `npm run dev`
|
||||
- build: `npm run build`
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"operationSettings": [
|
||||
{
|
||||
"operationName": "test:cov",
|
||||
"outputFolderNames": ["coverage"]
|
||||
},
|
||||
{
|
||||
"operationName": "ts-check",
|
||||
"outputFolderNames": ["dist"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
const { defineConfig } = require('@coze-arch/eslint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
packageRoot: __dirname,
|
||||
preset: 'web',
|
||||
rules: {},
|
||||
});
|
||||
58
frontend/packages/agent-ide/bot-config-area/package.json
Normal file
58
frontend/packages/agent-ide/bot-config-area/package.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "@coze-agent-ide/bot-config-area",
|
||||
"version": "0.0.1",
|
||||
"description": "@coze-agent-ide/bot-config-area",
|
||||
"license": "Apache-2.0",
|
||||
"author": "haozhenfei@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-agent-ide/bot-creator-context": "workspace:*",
|
||||
"@coze-agent-ide/bot-editor-context-store": "workspace:*",
|
||||
"@coze-agent-ide/model-manager": "workspace:*",
|
||||
"@coze-agent-ide/space-bot": "workspace:*",
|
||||
"@coze-agent-ide/tool": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/bot-typings": "workspace:*",
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/stylelint-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/lodash-es": "^4.17.10",
|
||||
"@types/react": "18.2.37",
|
||||
"@types/react-dom": "18.2.15",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"react": "~18.2.0",
|
||||
"react-dom": "~18.2.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
23
frontend/packages/agent-ide/bot-config-area/src/index.ts
Normal file
23
frontend/packages/agent-ide/bot-config-area/src/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { DialogueConfigView } from './model-config-view/dialogue-config-view';
|
||||
export { SingleAgentModelView } from './model-config-view/single-agent-model-view';
|
||||
export { MonetizeConfigButton } from './monetize-config/button';
|
||||
export { MonetizeConfigPanel } from './monetize-config/panel';
|
||||
export { QueryCollect } from './query-collect';
|
||||
export { ModelConfigView } from './model-config-view';
|
||||
export type { SingleAgentModelViewProps } from './model-config-view/single-agent-model-view';
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC, type ReactNode } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Popover } from '@coze-arch/bot-semi';
|
||||
import { CollapsibleIconButton } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { InputSlider } from '@coze-studio/components';
|
||||
import { useModelStore } from '@coze-studio/bot-detail-store/model';
|
||||
import { ModelFormItem } from '@coze-agent-ide/model-manager';
|
||||
import { IconCozChatSetting } from '@coze-arch/coze-design/icons';
|
||||
|
||||
const DialogueConfig: FC<{ tips: ReactNode }> = ({ tips }) => {
|
||||
const { model, setModelByImmer } = useModelStore(
|
||||
useShallow(state => ({
|
||||
model: state,
|
||||
setModelByImmer: state.setModelByImmer,
|
||||
})),
|
||||
);
|
||||
|
||||
const handleChange = (value: number) => {
|
||||
setModelByImmer(draft => {
|
||||
if (!draft.config.ShortMemPolicy) {
|
||||
draft.config.ShortMemPolicy = { HistoryRound: value };
|
||||
return;
|
||||
}
|
||||
draft.config.ShortMemPolicy.HistoryRound = value;
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="p-[24px]">
|
||||
<div className="leading-[32px] coz-fg-plus text-[20px] font-[500]">
|
||||
{I18n.t('workflow_agent_dialog_set')}
|
||||
</div>
|
||||
{tips ? (
|
||||
<div className="mt-[16px] coz-fg-secondary text-[14px] leading-[20px]">
|
||||
{tips}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-[16px] coz-fg-plus text-[14px] leading-[20px] font-[500]">
|
||||
{I18n.t('workflow_agent_dialog_set_chathistory')}
|
||||
</div>
|
||||
<ModelFormItem
|
||||
popoverContent={I18n.t('model_config_history_round_explain')}
|
||||
label={I18n.t('model_config_history_round')}
|
||||
>
|
||||
<InputSlider
|
||||
step={1}
|
||||
min={0}
|
||||
max={100}
|
||||
decimalPlaces={0}
|
||||
value={model.config.ShortMemPolicy?.HistoryRound}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</ModelFormItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const itemKey = Symbol.for('DialogueConfigView');
|
||||
|
||||
export const DialogueConfigView: FC<{
|
||||
tips: ReactNode;
|
||||
}> = ({ tips }) => (
|
||||
<Popover
|
||||
className="overflow-hidden rounded-[12px] w-[600px]"
|
||||
trigger="click"
|
||||
autoAdjustOverflow={true}
|
||||
content={<DialogueConfig tips={tips} />}
|
||||
>
|
||||
<CollapsibleIconButton
|
||||
itemKey={itemKey}
|
||||
data-testid="bot.ide.bot_creator.set_model_view_button"
|
||||
icon={<IconCozChatSetting className="text-[16px]" />}
|
||||
text={I18n.t('workflow_agent_dialog_set')}
|
||||
/>
|
||||
</Popover>
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { DialogueConfigView } from './dialogue-config-view';
|
||||
export { SingleAgentModelView } from './single-agent-model-view';
|
||||
export { ModelConfigView } from './model-config-view';
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { BotMode } from '@coze-arch/bot-api/playground_api';
|
||||
import { useGetSingleAgentCurrentModel } from '@coze-agent-ide/model-manager';
|
||||
|
||||
import { SingleAgentModelView } from './single-agent-model-view';
|
||||
import { DialogueConfigView } from './dialogue-config-view';
|
||||
|
||||
export const ModelConfigView: React.FC<{
|
||||
mode: BotMode;
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
}> = ({ mode, modelListExtraHeaderSlot }) => {
|
||||
const currentModel = useGetSingleAgentCurrentModel();
|
||||
|
||||
if (mode === BotMode.SingleMode) {
|
||||
return currentModel?.model_type ? (
|
||||
<SingleAgentModelView
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
if (mode === BotMode.MultiMode || mode === BotMode.WorkflowMode) {
|
||||
return (
|
||||
<DialogueConfigView
|
||||
tips={
|
||||
mode === BotMode.WorkflowMode
|
||||
? I18n.t('workflow_agent_dialog_set_desc')
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useModelStore } from '@coze-studio/bot-detail-store/model';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { type Model } from '@coze-arch/bot-api/developer_api';
|
||||
import { ModelSelect } from '@coze-agent-ide/model-manager/model-select-v2';
|
||||
import {
|
||||
useModelCapabilityCheckModal,
|
||||
useGetSingleAgentCurrentModel,
|
||||
getModelOptionList,
|
||||
} from '@coze-agent-ide/model-manager';
|
||||
import { useBotEditor } from '@coze-agent-ide/bot-editor-context-store';
|
||||
import {
|
||||
useBotCreatorContext,
|
||||
BotCreatorScene,
|
||||
} from '@coze-agent-ide/bot-creator-context';
|
||||
|
||||
export interface SingleAgentModelViewProps {
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
triggerRender?: (model?: Model, popoverVisible?: boolean) => React.ReactNode;
|
||||
}
|
||||
|
||||
export function SingleAgentModelView(props: SingleAgentModelViewProps) {
|
||||
const { modelListExtraHeaderSlot, triggerRender } = props;
|
||||
const spaceId = useSpaceStore(store => store.space.id);
|
||||
const { scene } = useBotCreatorContext();
|
||||
const currentModel = useGetSingleAgentCurrentModel();
|
||||
const currentModelId = currentModel?.model_type
|
||||
? String(currentModel.model_type)
|
||||
: undefined;
|
||||
|
||||
const { storeSet } = useBotEditor();
|
||||
const modelStore = storeSet.useModelStore(
|
||||
useShallow(state => ({
|
||||
onlineModelList: state.onlineModelList,
|
||||
offlineModelMap: state.offlineModelMap,
|
||||
getModelPreset: state.getModelPreset,
|
||||
})),
|
||||
);
|
||||
|
||||
const [currentModelIdState, setCurrentModelIdState] = useState<
|
||||
string | undefined
|
||||
>(currentModelId);
|
||||
|
||||
const { modelConfig, setModelByImmer } = useModelStore(
|
||||
useShallow(state => ({
|
||||
modelConfig: state.config,
|
||||
setModelByImmer: state.setModelByImmer,
|
||||
})),
|
||||
);
|
||||
|
||||
const { modalNode, checkAndOpenModal } = useModelCapabilityCheckModal({
|
||||
onOk: modelId => {
|
||||
setCurrentModelIdState(modelId);
|
||||
},
|
||||
});
|
||||
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
|
||||
const modelList = getModelOptionList({
|
||||
onlineModelList: modelStore.onlineModelList,
|
||||
offlineModelMap: modelStore.offlineModelMap,
|
||||
currentModelId: String(currentModel?.model_type),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentModelIdState(currentModelId);
|
||||
}, [currentModelId]);
|
||||
|
||||
return currentModelIdState ? (
|
||||
<>
|
||||
<ModelSelect
|
||||
popoverClassName="h-auto !max-h-[70vh]"
|
||||
disabled={isReadonly}
|
||||
enableJumpDetail={
|
||||
scene === BotCreatorScene.Bot && spaceId && !IS_OPEN_SOURCE
|
||||
? { spaceId }
|
||||
: undefined
|
||||
}
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
selectedModelId={currentModelIdState}
|
||||
modelList={modelList}
|
||||
onModelChange={m => {
|
||||
const modelId = String(m.model_type);
|
||||
const checkPassed = checkAndOpenModal(modelId);
|
||||
if (checkPassed) {
|
||||
setCurrentModelIdState(modelId);
|
||||
}
|
||||
return checkPassed;
|
||||
}}
|
||||
modelConfigProps={{
|
||||
hideDiversityCollapseButton: true,
|
||||
agentType: 'single',
|
||||
currentConfig: modelConfig,
|
||||
onConfigChange: v => {
|
||||
setModelByImmer(draft => {
|
||||
draft.config = {
|
||||
model: currentModelIdState,
|
||||
...v,
|
||||
};
|
||||
});
|
||||
},
|
||||
modelStore,
|
||||
}}
|
||||
triggerRender={triggerRender}
|
||||
modalSlot={modalNode}
|
||||
/>
|
||||
</>
|
||||
) : null;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CollapsibleIconButton } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { useMonetizeConfigStore } from '@coze-studio/bot-detail-store';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozWallet } from '@coze-arch/coze-design/icons';
|
||||
import { Popover } from '@coze-arch/coze-design';
|
||||
|
||||
import { MonetizeConfigPanel } from '../panel';
|
||||
|
||||
const itemKey = Symbol.for('MonetizeConfigButton');
|
||||
|
||||
export function MonetizeConfigButton() {
|
||||
const isOn = useMonetizeConfigStore(store => store.isOn);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
trigger="click"
|
||||
autoAdjustOverflow={true}
|
||||
content={<MonetizeConfigPanel />}
|
||||
>
|
||||
<CollapsibleIconButton
|
||||
itemKey={itemKey}
|
||||
icon={<IconCozWallet className="text-[16px]" />}
|
||||
text={isOn ? I18n.t('monetization_on') : I18n.t('monetization_off')}
|
||||
color={isOn ? 'highlight' : 'secondary'}
|
||||
/>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { useMonetizeConfigReadonly } from '@coze-agent-ide/space-bot/hook';
|
||||
import {
|
||||
MonetizeCreditRefreshCycle,
|
||||
MonetizeDescription,
|
||||
MonetizeFreeChatCount,
|
||||
MonetizeSwitch,
|
||||
} from '@coze-studio/components/monetize';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useMonetizeConfigStore } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
MonetizationEntityType,
|
||||
type BotMonetizationRefreshPeriod,
|
||||
} from '@coze-arch/idl/benefit';
|
||||
import { benefitApi } from '@coze-arch/bot-api';
|
||||
|
||||
export function MonetizeConfigPanel() {
|
||||
const botId = useBotInfoStore(store => store.botId);
|
||||
const {
|
||||
isOn,
|
||||
freeCount,
|
||||
refreshCycle,
|
||||
setIsOn,
|
||||
setFreeCount,
|
||||
setRefreshCycle,
|
||||
} = useMonetizeConfigStore();
|
||||
const isReadonly = useMonetizeConfigReadonly();
|
||||
|
||||
const { run: debouncedSaveBotConfig } = useDebounceFn(
|
||||
({
|
||||
isEnable,
|
||||
freeChats,
|
||||
}: {
|
||||
isEnable: boolean;
|
||||
freeChats: number;
|
||||
refreshCycle: BotMonetizationRefreshPeriod;
|
||||
}) => {
|
||||
benefitApi.PublicSaveBotDraftMonetizationConfig({
|
||||
entity_id: botId,
|
||||
entity_type: MonetizationEntityType.Bot,
|
||||
is_enable: isEnable,
|
||||
free_chat_allowance_count: freeChats,
|
||||
refresh_period: refreshCycle,
|
||||
});
|
||||
},
|
||||
{ wait: 300 },
|
||||
);
|
||||
|
||||
const refreshCycleDisabled = !isOn || isReadonly || freeCount <= 0;
|
||||
|
||||
return (
|
||||
<div className="w-[480px] p-[24px] flex flex-col gap-[24px]">
|
||||
<MonetizeSwitch
|
||||
disabled={isReadonly}
|
||||
isOn={isOn}
|
||||
onChange={value => {
|
||||
setIsOn(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: value,
|
||||
freeChats: freeCount,
|
||||
refreshCycle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<MonetizeDescription isOn={isOn} />
|
||||
<MonetizeFreeChatCount
|
||||
isOn={isOn}
|
||||
disabled={isReadonly}
|
||||
freeCount={freeCount}
|
||||
onFreeCountChange={value => {
|
||||
setFreeCount(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: isOn,
|
||||
freeChats: value,
|
||||
refreshCycle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<MonetizeCreditRefreshCycle
|
||||
freeCount={freeCount}
|
||||
disabled={refreshCycleDisabled}
|
||||
refreshCycle={refreshCycle}
|
||||
onRefreshCycleChange={value => {
|
||||
setRefreshCycle(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: isOn,
|
||||
freeChats: freeCount,
|
||||
refreshCycle: value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC, type MouseEvent, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { get } from 'lodash-es';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozTamplate } from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
type FormApi,
|
||||
IconButton,
|
||||
Popover,
|
||||
Typography,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { type GenerateUserQueryCollectPolicyRequest } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import { Tips } from './tips';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: I18n.t('bot_dev_privacy_setting_conversation'),
|
||||
value: I18n.t('bot_dev_privacy_setting_conversation'),
|
||||
},
|
||||
];
|
||||
const defaultOptionsValue = [I18n.t('bot_dev_privacy_setting_conversation')];
|
||||
interface GenerateByTemplateProps {
|
||||
handleGenerate: (v: GenerateUserQueryCollectPolicyRequest) => void;
|
||||
loading: boolean;
|
||||
templateLink: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
export const GenerateByTemplate: FC<GenerateByTemplateProps> = ({
|
||||
handleGenerate,
|
||||
loading,
|
||||
templateLink,
|
||||
link,
|
||||
}) => {
|
||||
const { botId } = useBotInfoStore($store => ({
|
||||
botId: $store.botId,
|
||||
}));
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [configInfo, setConfigInfo] =
|
||||
useState<GenerateUserQueryCollectPolicyRequest>();
|
||||
const [isFailToValid, setIsFailToValid] = useState(true);
|
||||
|
||||
const formApi = useRef<FormApi<GenerateUserQueryCollectPolicyRequest>>();
|
||||
|
||||
const onFormValueChange = (values: GenerateUserQueryCollectPolicyRequest) => {
|
||||
const developerName = get(values, 'developer_name');
|
||||
const contactInformation = get(values, 'contact_information');
|
||||
setIsFailToValid(!(developerName && contactInformation));
|
||||
setConfigInfo({
|
||||
...values,
|
||||
});
|
||||
};
|
||||
|
||||
const onVisibleChange = (isVisble: boolean) => {
|
||||
if (isVisble) {
|
||||
setDefaultValue();
|
||||
}
|
||||
};
|
||||
|
||||
const setDefaultValue = () => {
|
||||
if (configInfo) {
|
||||
formApi.current?.setValue('developer_name', configInfo.developer_name);
|
||||
formApi.current?.setValue(
|
||||
'contact_information',
|
||||
configInfo.contact_information,
|
||||
);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (link) {
|
||||
setConfigInfo({ developer_name: '', contact_information: '' });
|
||||
setVisible(false);
|
||||
}
|
||||
}, [link]);
|
||||
|
||||
const onClickGenerate = () => {
|
||||
handleGenerate({ ...configInfo, bot_id: botId });
|
||||
};
|
||||
const onOpen = (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setVisible(true);
|
||||
};
|
||||
return (
|
||||
<Popover
|
||||
position="right"
|
||||
trigger="custom"
|
||||
stopPropagation={true}
|
||||
onVisibleChange={onVisibleChange}
|
||||
visible={visible}
|
||||
onClickOutSide={() => setVisible(false)}
|
||||
content={
|
||||
<div className="p-[16px] w-[320px]">
|
||||
<div className="coz-fg-plus text-[20px] font-medium leading-[32px]">
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_1')}
|
||||
</div>
|
||||
<div className="coz-fg-primary text-[14px] font-normal leading-[20px] pb-[12px]">
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_2', {
|
||||
privacy_template: (
|
||||
<Typography.Text link onClick={() => window.open(templateLink)}>
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_3')}
|
||||
</Typography.Text>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Form<GenerateUserQueryCollectPolicyRequest>
|
||||
getFormApi={api => (formApi.current = api)}
|
||||
labelPosition="top"
|
||||
showValidateIcon={false}
|
||||
className={s['form-wrap']}
|
||||
onValueChange={values =>
|
||||
onFormValueChange(
|
||||
values as GenerateUserQueryCollectPolicyRequest,
|
||||
)
|
||||
}
|
||||
autoComplete="off"
|
||||
disabled={loading}
|
||||
>
|
||||
<Form.Input
|
||||
field="developer_name"
|
||||
label={I18n.t('bot_dev_privacy_setting_developer_name')}
|
||||
style={{ width: '100%' }}
|
||||
trigger="blur"
|
||||
maxLength={50}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect3',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect3',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Form.Select
|
||||
field="collect_detail"
|
||||
label={{
|
||||
text: I18n.t('bot_dev_privacy_setting_developer_collect1'),
|
||||
extra: (
|
||||
<Tips
|
||||
content={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect7',
|
||||
)}
|
||||
size="small"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
optionList={options}
|
||||
disabled
|
||||
initValue={defaultOptionsValue}
|
||||
style={{ width: '100%' }}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect4',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect4',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Form.Input
|
||||
field="contact_information"
|
||||
label={I18n.t('bot_dev_privacy_setting_developer_collect2')}
|
||||
style={{ width: '100%' }}
|
||||
trigger="blur"
|
||||
maxLength={50}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect5',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect5',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="flex justify-end mt-[12px]">
|
||||
<Button
|
||||
loading={loading}
|
||||
onClick={onClickGenerate}
|
||||
disabled={isFailToValid}
|
||||
>
|
||||
{I18n.t(
|
||||
loading
|
||||
? 'bot_dev_privacy_setting_generate_link2'
|
||||
: 'bot_dev_privacy_setting_generate_link1',
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
icon={<IconCozTamplate />}
|
||||
iconPosition="left"
|
||||
color="secondary"
|
||||
size="small"
|
||||
onClick={onOpen}
|
||||
>
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template')}
|
||||
</IconButton>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
.query-collect-modal {
|
||||
:global {
|
||||
.semi-modal-header {
|
||||
align-items: center;
|
||||
|
||||
.semi-button-borderless {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 11px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--coze-bg-6), var(--coze-bg-6-alpha));
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(var(--coze-bg-8), var(--coze-bg-8-alpha));
|
||||
}
|
||||
|
||||
.semi-button-content {
|
||||
color: rgba(var(--coze-fg-2), var(--coze-fg-2-alpha));
|
||||
|
||||
.semi-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-footer {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.semi-switch:not(.semi-switch-checked){
|
||||
background-color: var(--semi-color-fill-0);
|
||||
}
|
||||
|
||||
.semi-switch:not(.semi-switch-checked):hover {
|
||||
background-color: var(--semi-color-fill-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-wrap {
|
||||
:global {
|
||||
.semi-form-field {
|
||||
padding: 0;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.semi-form-field-label {
|
||||
margin-bottom: 6px;
|
||||
padding: 0 8px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.semi-form-field-error-message {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.semi-input-prefix-text {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.semi-input-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.semi-input-suffix {
|
||||
.coz-icon-button {
|
||||
display: flex;
|
||||
padding-right: 4px;
|
||||
|
||||
.coz-button.coz-btn-small{
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-form-field-label-required .semi-form-field-label-text::after{
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.semi-input-wrapper__with-suffix .semi-input{
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { CollapsibleIconButton } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { updateQueryCollect } from '@coze-studio/bot-detail-store/save-manager';
|
||||
import { useQueryCollectStore } from '@coze-studio/bot-detail-store/query-collect';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
useGenerateLink,
|
||||
useGetUserQueryCollectOption,
|
||||
} from '@coze-agent-ide/space-bot/hook';
|
||||
import { IconCozEye } from '@coze-arch/coze-design/icons';
|
||||
import { Modal, Switch, Form, type FormApi } from '@coze-arch/coze-design';
|
||||
|
||||
import { getUrlValue, isValidUrl } from './utils';
|
||||
import { Tips } from './tips';
|
||||
import { GenerateByTemplate } from './generate-by-template';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
const itemKey = Symbol.for('QueryCollect');
|
||||
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
export const QueryCollect: FC = () => {
|
||||
const { privatePolicy, isCollect, setQueryCollect } = useQueryCollectStore(
|
||||
useShallow($store => ({
|
||||
isCollect: $store.is_collected,
|
||||
privatePolicy: $store.private_policy,
|
||||
setQueryCollect: $store.setQueryCollect,
|
||||
})),
|
||||
);
|
||||
const { queryCollectOption, supportText } = useGetUserQueryCollectOption();
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
const { link, loading, runGenerate } = useGenerateLink();
|
||||
const formApi = useRef<FormApi<{ policyLink: string }>>();
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [privacyUrl, setPrivacyUrl] = useState(privatePolicy);
|
||||
const privacyErrMsg = useRef('');
|
||||
|
||||
const onClose = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
const onOk = async () => {
|
||||
const policyLink = formApi.current?.getValue('policyLink');
|
||||
const queryCollectConf = {
|
||||
is_collected: checked,
|
||||
// cp-disable-next-line
|
||||
private_policy: checked ? `https://${policyLink}` : '',
|
||||
};
|
||||
const {
|
||||
data: { check_not_pass_msg, check_not_pass },
|
||||
} = await updateQueryCollect(queryCollectConf);
|
||||
privacyErrMsg.current = check_not_pass ? (check_not_pass_msg ?? '') : '';
|
||||
await formApi.current?.validate();
|
||||
setQueryCollect(queryCollectConf);
|
||||
setVisible(false);
|
||||
};
|
||||
const openModal = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (link) {
|
||||
formApi.current?.setValue('policyLink', getUrlValue(link));
|
||||
formApi.current?.validate();
|
||||
}
|
||||
}, [link]);
|
||||
|
||||
useEffect(() => {
|
||||
setChecked(isCollect);
|
||||
formApi.current?.setValue('policyLink', getUrlValue(privatePolicy ?? ''));
|
||||
}, [visible, privatePolicy, isCollect]);
|
||||
|
||||
useEffect(() => {
|
||||
privacyErrMsg.current = '';
|
||||
}, [privacyUrl]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CollapsibleIconButton
|
||||
itemKey={itemKey}
|
||||
text={I18n.t('bot_dev_privacy_title')}
|
||||
icon={<IconCozEye className="text-[16px]" />}
|
||||
onClick={openModal}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
width={480}
|
||||
visible={visible}
|
||||
onCancel={onClose}
|
||||
maskClosable={false}
|
||||
title={
|
||||
<span className="text-[20px]">{I18n.t('bot_dev_privacy_title')}</span>
|
||||
}
|
||||
cancelText={I18n.t('cancel')}
|
||||
okText={I18n.t('confirm')}
|
||||
className={s['query-collect-modal']}
|
||||
onOk={onOk}
|
||||
okButtonProps={{
|
||||
disabled: loading || isReadonly,
|
||||
style: { marginLeft: '8px' },
|
||||
}}
|
||||
>
|
||||
<div className="py-[16px]">
|
||||
<div className="flex items-center justify-between py-[16px] pl-[12px] pr-[24px] rounded-[8px] border border-solid border-[var(--coz-stroke-plus)]">
|
||||
<div className="flex items-center justify-center gap-[3px] ">
|
||||
<span className="coz-fg-plus text-[14px] font-normal leading-[20px] ">
|
||||
{I18n.t('bot_dev_privacy_setting_title')}
|
||||
</span>
|
||||
<Tips
|
||||
content={
|
||||
I18n.t('bot_dev_privacy_setting_channel') + supportText
|
||||
}
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
<Switch
|
||||
checked={checked}
|
||||
size="small"
|
||||
onChange={v => setChecked(v)}
|
||||
disabled={loading || isReadonly}
|
||||
/>
|
||||
</div>
|
||||
<div className="coz-fg-secondary text-[12px] font-normal leading-[16px] px-[8px] pt-[2px] pb-[18px]">
|
||||
{I18n.t('bot_dev_privacy_setting_desc')}
|
||||
</div>
|
||||
<div style={{ display: checked ? 'block' : 'none' }}>
|
||||
<Form<{ policyLink: string }>
|
||||
getFormApi={api => (formApi.current = api)}
|
||||
labelPosition="top"
|
||||
showValidateIcon={false}
|
||||
className={s['form-wrap']}
|
||||
autoComplete="off"
|
||||
disabled={loading || isReadonly}
|
||||
>
|
||||
<Form.Input
|
||||
field="policyLink"
|
||||
label={I18n.t('bot_dev_privacy_setting_link1')}
|
||||
style={{ width: '100%' }}
|
||||
trigger="blur"
|
||||
// cp-disable-next-line
|
||||
prefix="https://"
|
||||
stopValidateWithError
|
||||
maxLength={50}
|
||||
disabled={loading || isReadonly}
|
||||
placeholder={I18n.t('privacy_link_placeholder')}
|
||||
onChange={setPrivacyUrl}
|
||||
suffix={
|
||||
IS_OVERSEA || isReadonly ? null : (
|
||||
<GenerateByTemplate
|
||||
handleGenerate={runGenerate}
|
||||
loading={loading}
|
||||
templateLink={
|
||||
queryCollectOption?.private_policy_template || ''
|
||||
}
|
||||
link={link}
|
||||
/>
|
||||
)
|
||||
}
|
||||
rules={[
|
||||
{
|
||||
validator: (_, value) => !checked || isValidUrl(value),
|
||||
message: I18n.t('bot_dev_privacy_setting_invalid_link'),
|
||||
},
|
||||
{
|
||||
validator: () => !checked || !privacyErrMsg.current,
|
||||
message: () => privacyErrMsg.current,
|
||||
},
|
||||
]}
|
||||
helpText={
|
||||
<div className="coz-fg-secondary text-[12px] font-normal leading-[16px] px-[8px] pt-[2px]">
|
||||
{I18n.t('bot_dev_privacy_setting_link2')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
import { Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
export const Tips = ({
|
||||
content,
|
||||
size = 'medium',
|
||||
}: {
|
||||
content: string;
|
||||
size: 'small' | 'medium';
|
||||
}) => (
|
||||
<Tooltip content={content}>
|
||||
<div
|
||||
className={classNames(
|
||||
size === 'small'
|
||||
? 'w-[16px] h-[16px] rounded-[4px]'
|
||||
: 'w-[24px] h-[24px] rounded-[8px]',
|
||||
'flex items-center justify-center hover:coz-mg-secondary-hovered cursor-pointer',
|
||||
)}
|
||||
>
|
||||
<IconCozInfoCircle className="coz-fg-secondary" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const DOMAIN_REGEXP = /^([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})$/;
|
||||
|
||||
export function isValidUrl(url: string): boolean {
|
||||
try {
|
||||
// cp-disable-next-line
|
||||
const urlObject = new URL(`https://${url}`);
|
||||
return DOMAIN_REGEXP.test(urlObject.hostname);
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch -- 根据函数功能无需 throw error
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// cp-disable-next-line
|
||||
export const getUrlValue = (url: string) => url?.replace(/^https:\/\//, '');
|
||||
18
frontend/packages/agent-ide/bot-config-area/src/typings.d.ts
vendored
Normal file
18
frontend/packages/agent-ide/bot-config-area/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
declare const IS_OVERSEA: boolean;
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DemoComponent } from '../src';
|
||||
|
||||
export default {
|
||||
title: 'Example/Demo',
|
||||
component: DemoComponent,
|
||||
parameters: {
|
||||
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
||||
layout: 'centered',
|
||||
},
|
||||
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
||||
tags: ['autodocs'],
|
||||
// More on argTypes: https://storybook.js.org/docs/api/argtypes
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
||||
export const Base = {
|
||||
args: {
|
||||
name: 'tecvan',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Meta } from "@storybook/blocks";
|
||||
|
||||
<Meta title="Hello world" />
|
||||
|
||||
<div className="sb-container">
|
||||
<div className='sb-section-title'>
|
||||
# Hello world
|
||||
|
||||
Hello world
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
{`
|
||||
.sb-container {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.sb-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.sb-section-title {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-store/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/idl/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../bot-editor-context-store/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../components/bot-semi/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/eslint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/stylelint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/ts-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/vitest-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../context/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../model-manager/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../space-bot/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/components/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/stores/bot-detail/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../tool/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/packages/agent-ide/bot-config-area/tsconfig.json
Normal file
15
frontend/packages/agent-ide/bot-config-area/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": ["__tests__", "vitest.config.ts", "stories"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
frontend/packages/agent-ide/bot-config-area/vitest.config.ts
Normal file
22
frontend/packages/agent-ide/bot-config-area/vitest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'web',
|
||||
});
|
||||
Reference in New Issue
Block a user