chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
@@ -65,7 +65,7 @@ export const ApiBind = (props: ApiBindProps) => {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化时校验一次是否有workflow
|
||||
// Check if there is a workflow once during initialization.
|
||||
if (checked && !workflowOptionsLoading) {
|
||||
formApi.validate(['api_workflow']);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// @file 开源版暂不支持商店渠道绑定,用于未来拓展
|
||||
// @File open source version does not support store channel binding for future expansion
|
||||
import { type MouseEventHandler } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// @file 开源版暂不支持模版渠道绑定,用于未来拓展
|
||||
|
||||
// @File open source version does not support template channel binding for future expansion
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { type MouseEventHandler, useEffect, useRef, useState } from 'react';
|
||||
|
||||
@@ -62,7 +62,7 @@ export function TemplateBind({
|
||||
|
||||
const { project_id = '' } = useParams<DynamicParams>();
|
||||
|
||||
// 回填模板配置
|
||||
// Backfill template configuration
|
||||
const fillTemplateFrom = async () => {
|
||||
const productInfo = await ProductApi.PublicGetProductEntityInfo({
|
||||
entity_id: project_id,
|
||||
@@ -78,7 +78,7 @@ export function TemplateBind({
|
||||
templateConfigured: formValues.agreement === true,
|
||||
connectors: {
|
||||
...connectors,
|
||||
// @ts-expect-error 可以接受 Partial
|
||||
// @ts-expect-error can accept Partial
|
||||
[record.id]: templateFormToBindInfo(formValues),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import {
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
@@ -86,7 +86,7 @@ export const TemplateConfigForm = forwardRef<
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
>(({ record, userInfo }, ref) => {
|
||||
const [FLAGS] = useFlags();
|
||||
// 即将支持,敬请期待
|
||||
// Support soon, so stay tuned.
|
||||
const customRequest = FLAGS['bot.studio.project_publish_imagex']
|
||||
? uploadCustomRequestImageX
|
||||
: uploadCustomRequest;
|
||||
@@ -96,7 +96,7 @@ export const TemplateConfigForm = forwardRef<
|
||||
const editorRef = useRef<Editor>();
|
||||
const onEditorInit = (editor: Editor) => {
|
||||
editorRef.current = editor;
|
||||
// EditorFullInput 的 form value 为纯文本,但这里需要提交 editor-kit 富文本内容
|
||||
// EditorFullInput's form value is plain text, but here you need to submit editor-kit rich text content
|
||||
editor.on(EditorEventType.CONTENT_CHANGE, _ => {
|
||||
formRef.current?.formApi?.setValue(
|
||||
'readme',
|
||||
@@ -121,7 +121,7 @@ export const TemplateConfigForm = forwardRef<
|
||||
new DeltaSet(normalizeSchema(readme as DeltaSetOptions)),
|
||||
);
|
||||
}
|
||||
// @ts-expect-error -- values 就是 TemplateForm 类型
|
||||
// @ts-expect-error -- values is the TemplateForm type
|
||||
Object.keys(values).forEach(key => formApi.setError(key, null));
|
||||
},
|
||||
validate: () => formRef.current?.formApi?.validate(),
|
||||
@@ -148,7 +148,7 @@ export const TemplateConfigForm = forwardRef<
|
||||
className="mt-[16px]"
|
||||
rules={[
|
||||
{
|
||||
// 必须勾选同意协议才能通过验证
|
||||
// The consent agreement must be checked to pass the verification.
|
||||
validator: (_rule: unknown, value: unknown) =>
|
||||
(value as boolean) === true,
|
||||
message: I18n.t('template_buy_paid_agreement_toast'),
|
||||
@@ -195,7 +195,7 @@ export const TemplateConfigForm = forwardRef<
|
||||
(value as FileItem[] | undefined)?.every(
|
||||
item => !item._sizeInvalid && item.status === 'success',
|
||||
) === true,
|
||||
message: '', // 校验文件大小是否符合限制 && 上传是否成功,Upload 组件会显示错误信息
|
||||
message: '', // Verify whether the file size meets the limit & & whether the upload was successful, the Upload component will display an error message
|
||||
},
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface TemplatePreviewCardProps {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
// 基本是复制的 packages/studio/template/pages/src/components/template-list-card/index.tsx
|
||||
// Basically copied packages/studio/template/pages/src/components/template-list-card/index.tsx
|
||||
export function TemplatePreviewCard({
|
||||
userInfo,
|
||||
cover,
|
||||
|
||||
@@ -42,9 +42,9 @@ export interface TemplateForm {
|
||||
name: string;
|
||||
covers: Partial<FileItem>[];
|
||||
description: string;
|
||||
// EditorFullInput 的纯文本 form value ,仅为满足类型要求,不在业务中使用
|
||||
// EditorFullInput plain text form value, only to meet the type requirements, not used in business
|
||||
readme_text: string;
|
||||
// 实际需要传给后端的 editor-kit 富文本内容
|
||||
// The editor-kit rich text content that actually needs to be passed to the backend
|
||||
readme: string;
|
||||
preview_type: DisplayScreen;
|
||||
category: string;
|
||||
@@ -64,13 +64,13 @@ export function entityInfoToTemplateForm(
|
||||
const isZh = I18n.language.startsWith('zh');
|
||||
const meta = info.meta_info ?? {};
|
||||
const form: Partial<TemplateForm> = {
|
||||
// 默认勾选同意模板付费协议:已经上架过 或 已经配置过模板信息(readme 非空)
|
||||
// By default, check Agree to the template payment agreement: already on the shelves, or already configured template information (readme is not empty)
|
||||
agreement: meta.status !== ProductStatus.NeverListed || meta.readme !== '',
|
||||
name: meta.name,
|
||||
covers: meta.covers?.map(c => ({
|
||||
url: c.url,
|
||||
response: c,
|
||||
// 补充 FileItem 的其他属性,供表单校验使用
|
||||
// Supplements other properties of FileItem for form validation
|
||||
status: 'success',
|
||||
_sizeInvalid: false,
|
||||
})),
|
||||
|
||||
@@ -36,7 +36,7 @@ interface UnbindButtonProps {
|
||||
|
||||
const PROJECT_AGENT_TYPE = 1;
|
||||
|
||||
// 用于Api or WebSdk 的撤销发布
|
||||
// Unpublish for APIs or WebSDKs
|
||||
export const UndoButton = (props: UnbindButtonProps) => {
|
||||
const {
|
||||
bindId,
|
||||
|
||||
@@ -90,8 +90,8 @@ export function WebSdkBind({ checked, record, onClick }: WebSdkBindProps) {
|
||||
renderOptionItem={(option: optionRenderProps) => (
|
||||
<OptionWithTooltip option={option} tooltip={option.tooltip} />
|
||||
)}
|
||||
// onChange 负责处理数据清空的逻辑
|
||||
// onSelect 处理数据选择的逻辑
|
||||
// onChange is responsible for handling the logic of data emptying
|
||||
// onSelect handles data selection logic
|
||||
onChange={values => {
|
||||
if (typeof values !== 'undefined') {
|
||||
return;
|
||||
@@ -106,7 +106,7 @@ export function WebSdkBind({ checked, record, onClick }: WebSdkBindProps) {
|
||||
required: checked,
|
||||
message: I18n.t('project_release_Please_select'),
|
||||
},
|
||||
// 校验已选择的 chatflow 是否存在 && 未被禁用
|
||||
// Verify that the selected chatflow exists & & is not disabled
|
||||
{
|
||||
validator: (_rule: unknown, value: unknown) => {
|
||||
if (!checked) {
|
||||
|
||||
@@ -45,7 +45,7 @@ const TipTag: React.FC<TipTagProps> = ({ showText, tip, tagProps }) => (
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
/** 需要展示配置状态的渠道类别 */
|
||||
/** Channel categories that need to display configuration status */
|
||||
const Classes = [
|
||||
ConnectorClassification.SocialPlatform,
|
||||
ConnectorClassification.MiniProgram,
|
||||
@@ -64,7 +64,7 @@ export const ConfigStatus = ({ record }: { record: PublishConnectorInfo }) => {
|
||||
|
||||
return (
|
||||
<div className="flex gap-[6px]">
|
||||
{/* 配置状态 */}
|
||||
{/* configuration status */}
|
||||
<Tag color={color} size="mini" className="font-[500]">
|
||||
{text}
|
||||
</Tag>
|
||||
|
||||
@@ -58,7 +58,7 @@ export function ConnectorAction(props: ConnectorActionProps) {
|
||||
mouseEvent.stopPropagation();
|
||||
};
|
||||
|
||||
// 绑定/解除绑定是同一个回调,可以根据 bind_id 是否为空来区分
|
||||
// The bind/unbind is the same callback, which can be distinguished by whether the bind_id is empty or not
|
||||
const kvBindSuccessCallback = (value?: PublishConnectorInfo) => {
|
||||
if (value) {
|
||||
const isUnbind = !value.bind_id;
|
||||
@@ -100,7 +100,7 @@ export function ConnectorAction(props: ConnectorActionProps) {
|
||||
case ConnectorBindType.KvBind:
|
||||
case ConnectorBindType.KvAuthBind:
|
||||
return (
|
||||
// 使用 basis-full 强制 flex row 换行
|
||||
// Force flex row wrap with basis-full
|
||||
<div
|
||||
className={classNames(
|
||||
'basis-full self-end',
|
||||
@@ -155,7 +155,7 @@ export function ConnectorAction(props: ConnectorActionProps) {
|
||||
onClick={stopEventPropagation}
|
||||
/>
|
||||
);
|
||||
// 开源版暂不支持商店渠道绑定,用于未来拓展
|
||||
// The open-source version does not support store channel binding for the time being, for future expansion
|
||||
case ConnectorBindType.StoreBind:
|
||||
return (
|
||||
<StoreBind
|
||||
@@ -164,9 +164,9 @@ export function ConnectorAction(props: ConnectorActionProps) {
|
||||
onClick={stopEventPropagation}
|
||||
/>
|
||||
);
|
||||
// 开源版暂不支持模板渠道绑定,用于未来拓展
|
||||
// bind_type=9 用作扣子第一方渠道的标识,需要按照渠道 ID 展示绑定方式
|
||||
// TODO 后端更新 ConnectorBindType 类型定义
|
||||
// The open-source version does not support template channel binding for future expansion
|
||||
// bind_type = 9 is used as the logo of the first-party channel of the button, and the binding method needs to be displayed according to the channel ID.
|
||||
// TODO backend updates ConnectorBindType type definition
|
||||
case ConnectorBindType.TemplateBind: {
|
||||
if (record.id === TEMPLATE_CONNECTOR_ID) {
|
||||
return <TemplateBind record={record} onClick={stopEventPropagation} />;
|
||||
|
||||
@@ -45,13 +45,13 @@ import { ConfigStatus } from './config-status';
|
||||
import { UndoButton } from './bind-actions/undo-button';
|
||||
|
||||
enum DisabledReason {
|
||||
/** 社交渠道未选择 chatflow */
|
||||
/** Chatflow is not selected for social channels. */
|
||||
SocialPlatform,
|
||||
/** 未绑定 未授权 */
|
||||
/** Unbound, Unauthorized */
|
||||
NotConfigured,
|
||||
/** 后端下发的原因 */
|
||||
/** The reason for the back-end delivery */
|
||||
NotAllowed,
|
||||
/** 未配置模板 */
|
||||
/** No template configured */
|
||||
Template,
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ function getConnectorDisabledConfig({
|
||||
ConnectorClassification.SocialPlatform &&
|
||||
!socialPlatformConfig?.selected_workflows?.[0]?.workflow_id
|
||||
) {
|
||||
// 发布到社交渠道,且未选择 chatflow
|
||||
// Post to social channels without Chatflow selected.
|
||||
return {
|
||||
reason: DisabledReason.SocialPlatform,
|
||||
text: I18n.t('project_release_chatflow4'),
|
||||
@@ -88,18 +88,18 @@ function getConnectorDisabledConfig({
|
||||
reason: DisabledReason.NotConfigured,
|
||||
text: I18n.t('project_release_set_desc'),
|
||||
};
|
||||
// 未绑定 未授权
|
||||
// Unbound, Unauthorized
|
||||
if (getConnectorNotConfigured(connector)) {
|
||||
return notConfigured;
|
||||
}
|
||||
// 后端下发的不能发布的原因
|
||||
// The reason why it cannot be released after being issued by the backend.
|
||||
if (!connector.allow_publish && connector.not_allow_publish_reason) {
|
||||
return {
|
||||
reason: DisabledReason.NotAllowed,
|
||||
text: connector.not_allow_publish_reason,
|
||||
};
|
||||
}
|
||||
// 未配置模板
|
||||
// No template configured
|
||||
if (connector.id === TEMPLATE_CONNECTOR_ID && !templateConfigured) {
|
||||
return {
|
||||
reason: DisabledReason.Template,
|
||||
@@ -127,9 +127,9 @@ function getConnectorDisabledConfig({
|
||||
}
|
||||
}
|
||||
|
||||
// 与后端约定的额外描述信息
|
||||
// Additional descriptive information agreed upon with the backend
|
||||
interface DescriptionExtra {
|
||||
// 渠道名称 hover 的 tooltip
|
||||
// Channel name hover tooltip
|
||||
text?: string;
|
||||
}
|
||||
|
||||
@@ -172,15 +172,15 @@ export function ConnectorCard({
|
||||
connectorPublishConfig,
|
||||
connectorConfigMap: connectors,
|
||||
});
|
||||
// 开源版暂不支持社交平台渠道,用于未来拓展。
|
||||
// 社交渠道未选择“处理消息的对话流”时,需要将整个卡片展示为禁用态
|
||||
// The open-source version does not support social platform channels for future expansion.
|
||||
// When the social channel does not select "Process message conversation flow", the entire card needs to be displayed as disabled.
|
||||
const cardDisabled = disabledConfig?.reason === DisabledReason.SocialPlatform;
|
||||
|
||||
const descriptionExtra = (typeSafeJSONParse(
|
||||
connectorInfo.description_extra,
|
||||
) ?? {}) as DescriptionExtra;
|
||||
|
||||
// 如果禁用状态发生了变动,取消勾选当前渠道
|
||||
// If the disabled status changes, uncheck the current channel
|
||||
useEffect(() => {
|
||||
if (checked && disabledConfig) {
|
||||
onCheckedChange(false);
|
||||
@@ -321,7 +321,7 @@ export function ConnectorCard({
|
||||
<ConnectorAction
|
||||
record={connectorInfo}
|
||||
checked={checked}
|
||||
// 这个组件内部有 modal 不能使用条件渲染
|
||||
// This component has modal inside and cannot use conditional rendering.
|
||||
authActionWrapperClassName={classNames(!isShowAction && 'hidden')}
|
||||
/>
|
||||
{connectorInfo.connector_classification ===
|
||||
@@ -334,7 +334,7 @@ export function ConnectorCard({
|
||||
onClick={stopEventPropagation}
|
||||
/>
|
||||
) : null}
|
||||
{/* 开源版暂不支持MCP服务渠道,用于未来拓展 */}
|
||||
{/* The open-source version does not support MCP service channels for future expansion */}
|
||||
{connectorInfo.connector_classification ===
|
||||
ConnectorClassification.CozeSpaceExtensionLibrary &&
|
||||
connectorInfo.bind_type === ConnectorBindType.TemplateBind && (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.highlight {
|
||||
border-radius: 4px;
|
||||
animation: highlight-animation 3s forwards; /* 持续3秒的动画 */
|
||||
animation: highlight-animation 3s forwards; /* Animation lasting 3 seconds */
|
||||
}
|
||||
|
||||
@keyframes highlight-animation {
|
||||
|
||||
@@ -49,7 +49,7 @@ export function ConnectorGroupHeader({
|
||||
type,
|
||||
onAnimationEnd,
|
||||
}: ConnectorGroupHeaderProps) {
|
||||
// 付费墙
|
||||
// paywall
|
||||
const isAPIOrSDK = type === ConnectorClassification.APIOrSDK;
|
||||
const isAvailable = useBenefitAvailable({
|
||||
scene: PremiumPaywallScene.API,
|
||||
|
||||
@@ -61,7 +61,7 @@ export const ConnectorTabbar = forwardRef<
|
||||
<div
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
// ! 80px 高度影响 styles.mask 计算
|
||||
// ! 80Px height affects styles.mask calculation
|
||||
'flex items-center gap-x-8px h-[80px] relative',
|
||||
styles.mask,
|
||||
className,
|
||||
|
||||
@@ -23,7 +23,7 @@ import { Button } from '@coze-arch/coze-design';
|
||||
|
||||
import { UseMcpConfigModal } from '@/hooks/use-mcp-config-modal';
|
||||
|
||||
/** MCP配置按钮+弹窗 */
|
||||
/** MCP configuration button + pop-up window */
|
||||
export const McpConfigBtn = ({ record }: { record: PublishConnectorInfo }) => {
|
||||
const { node, open } = UseMcpConfigModal({ record });
|
||||
return (
|
||||
|
||||
@@ -83,9 +83,9 @@ export const SocialPlatformChatflow: React.FC<{ className?: string }> = ({
|
||||
handleSelectChatflow(option as ChatflowOptionProps)
|
||||
}
|
||||
rules={[
|
||||
// 有选择 SocialPlatform 时, chatflow 必填
|
||||
// Chatflow is required when SocialPlatform is selected
|
||||
{ required: hasSelectedSocialPlatforms },
|
||||
// 校验已选择的 chatflow 是否存在 && 未被禁用
|
||||
// Verify that the selected chatflow exists & & is not disabled
|
||||
{
|
||||
validator: (_rule: unknown, value: unknown) => {
|
||||
if (!hasSelectedSocialPlatforms) {
|
||||
|
||||
@@ -72,7 +72,7 @@ const getActiveConnectorTarget = ({
|
||||
|
||||
return activeConnector?.target;
|
||||
};
|
||||
/** 经验值 */
|
||||
/** experience point */
|
||||
const LOCK_TIME = 300;
|
||||
|
||||
export const useConnectorScroll = () => {
|
||||
@@ -97,14 +97,14 @@ export const useConnectorScroll = () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* 需要 3 个条件同时满足
|
||||
* 1. 随着页面滚动到不同锚点,tab 栏激活对应区域的按钮
|
||||
* 2. 点击 tab 栏 对应按钮激活 直接滚动到页面对应区域
|
||||
* 3. 当页面高度不足滚动时,点击 tab 栏也要激活对应按钮
|
||||
* All three conditions need to be met simultaneously
|
||||
* 1. As the page scrolls to different anchors, the tab bar activates the button for the corresponding area
|
||||
* 2. Click the tab bar, activate the corresponding button, and scroll directly to the corresponding area of the page
|
||||
* 3. When the page height is insufficient to scroll, click the tab bar to activate the corresponding button
|
||||
*
|
||||
* 由于滚动是 smooth 效果 条件 2 与 3 会发生冲突 当用户点击 tab 栏滚动时需要进行 lock
|
||||
* lock 时 条件 1 不触发
|
||||
* 需要给条件 3 一个兜底的解锁机制
|
||||
* Since the scroll is a smooth effect, conditions 2 and 3 will conflict, and the lock needs to be performed when the user clicks the tab bar to scroll.
|
||||
* Condition 1 does not fire when locked
|
||||
* Need to give condition 3 an unlocking mechanism with a bottom line
|
||||
*/
|
||||
const manualScrollLockRef = useRef(false);
|
||||
|
||||
@@ -116,12 +116,12 @@ export const useConnectorScroll = () => {
|
||||
manualScrollLockRef.current = false;
|
||||
};
|
||||
|
||||
/** 停止滚动 LOCK_TIME 后解锁 */
|
||||
/** Unlock after LOCK_TIME */
|
||||
const manualScrollUnLockDebounce = useDebounceFn(manualScrollUnLock, {
|
||||
wait: LOCK_TIME,
|
||||
});
|
||||
|
||||
/** 兜底解锁机制 如果用户点击 tab 栏但没有解锁 LOCK_TIME 后也应该解锁 */
|
||||
/** The bottom unlocking mechanism, if the user clicks the tab bar but does not unlock the LOCK_TIME should also be unlocked */
|
||||
const baseUnLockDebounce = useDebounceFn(manualScrollUnLock, {
|
||||
wait: LOCK_TIME,
|
||||
});
|
||||
@@ -149,7 +149,7 @@ export const useConnectorScroll = () => {
|
||||
changeActiveConnectorTarget();
|
||||
|
||||
const onScroll = () => {
|
||||
// 页面发生了滚动则不需要兜底机制
|
||||
// If the page scrolls, no safety net mechanism is required
|
||||
baseUnLockDebounce.cancel();
|
||||
manualScrollUnLockDebounce.run();
|
||||
changeActiveConnectorTarget();
|
||||
|
||||
@@ -100,7 +100,7 @@ export function PublishBasicInfo() {
|
||||
'left-0',
|
||||
'!coz-bg-max',
|
||||
)}
|
||||
// 比渠道 tab 高就可以, 避免遮挡
|
||||
// It is higher than the channel tab to avoid occlusion.
|
||||
textAreaStyle={{ zIndex: CONNECTOR_TAB_BAR_Z_INDEX + 1 }}
|
||||
onChange={value => {
|
||||
setProjectPublishInfo({
|
||||
|
||||
@@ -64,7 +64,7 @@ export function PublishConnectors() {
|
||||
const { project_id = '' } = useParams<DynamicParams>();
|
||||
|
||||
const {
|
||||
connectorList, // 开源版仅支持API 和 Chat SDK 渠道
|
||||
connectorList, // The open-source version only supports API and Chat SDK channels
|
||||
connectorUnionMap,
|
||||
monetizeConfig,
|
||||
selectedConnectorIds,
|
||||
@@ -122,7 +122,7 @@ export function PublishConnectors() {
|
||||
}
|
||||
};
|
||||
|
||||
// Collapse Panel 展开状态下,不在 header 中展示已选渠道的图标
|
||||
// Collapse Panel does not display the icon of the selected channel in the header when expanded
|
||||
const getGroupHeaderList = (groupId: ConnectorClassification) => {
|
||||
const group = connectorGroups.find(g => g.type === groupId);
|
||||
if (!group) {
|
||||
@@ -189,7 +189,7 @@ export function PublishConnectors() {
|
||||
))}
|
||||
</ConnectorTabbar>
|
||||
{connectorGroups.map((i, index) => {
|
||||
// 开源版暂不支持社交平台渠道
|
||||
// The open-source version does not support social platform channels for the time being
|
||||
const isSocialPlatform =
|
||||
i.type === ConnectorClassification.SocialPlatform;
|
||||
return (
|
||||
@@ -208,7 +208,7 @@ export function PublishConnectors() {
|
||||
closeAnimation(i.type);
|
||||
}}
|
||||
/>
|
||||
{/* 开源版暂不支持社交平台渠道 */}
|
||||
{/* The open-source version does not support social platform channels for the time being */}
|
||||
{isSocialPlatform ? (
|
||||
<SocialPlatformChatflow className="mb-8px" />
|
||||
) : null}
|
||||
|
||||
@@ -44,7 +44,7 @@ export const PublishRecord: FC<{
|
||||
type: IntelligenceType.Project,
|
||||
spaceId,
|
||||
intelligenceId: projectId,
|
||||
// 即将支持,敬请期待
|
||||
// Support soon, so stay tuned.
|
||||
enable: FLAGS['bot.studio.publish_management'] && !IS_OPEN_SOURCE,
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ export const PublishRecord: FC<{
|
||||
<div className="text-[12px] coz-fg-dim leading-[16px]">
|
||||
{I18n.t('project_release_already_released_desc')}
|
||||
</div>
|
||||
{/* 即将支持,敬请期待 */}
|
||||
{/* Support soon, so stay tuned. */}
|
||||
{FLAGS['bot.studio.publish_management'] && !IS_OPEN_SOURCE ? (
|
||||
<div className="text-[12px] coz-fg-dim leading-[16px]">
|
||||
{I18n.t('release_management_detail1', {
|
||||
|
||||
@@ -77,7 +77,7 @@ export function PublishTitleBar() {
|
||||
);
|
||||
const [publishing, setPublishing] = useState(false);
|
||||
const { publishHeaderHeight, setPublishHeaderHeight } = usePublishContainer();
|
||||
// 发布结果轮询
|
||||
// publish results poll
|
||||
const { run: getPublishRecordDetail, cancel } = useRequest(
|
||||
async (params: GetPublishRecordDetailRequest) =>
|
||||
await intelligenceApi.GetPublishRecordDetail(params),
|
||||
@@ -123,7 +123,7 @@ export function PublishTitleBar() {
|
||||
selectedConnectorIds.forEach(id => {
|
||||
const connectorId = unions[id] ?? id;
|
||||
publishConnectors[connectorId] = connectors[connectorId] ?? {};
|
||||
// 社交平台的 chatflow 选项统一
|
||||
// Unified chatflow options for social platforms
|
||||
if (
|
||||
connectorList.find(c => c.id === connectorId)
|
||||
?.connector_classification ===
|
||||
@@ -154,7 +154,7 @@ export function PublishTitleBar() {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// 校验的错误还需要Toast提示出来
|
||||
// Verification errors also need to be Toast Notification
|
||||
if (typeof Object.values(error as Error)[0] === 'string') {
|
||||
Toast.error(Object.values(error as Error)[0]);
|
||||
}
|
||||
|
||||
@@ -20,35 +20,35 @@ import {
|
||||
ConnectorConfigStatus,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
// 未配置/授权场景
|
||||
// Unconfigured/Authorized Scenario
|
||||
export const getConnectorNotConfigured = (
|
||||
connector: PublishConnectorInfo,
|
||||
): boolean => {
|
||||
const { bind_type, config_status } = connector;
|
||||
// 未绑定&未授权
|
||||
// Unbound & Unauthorized
|
||||
const notConfigured =
|
||||
[
|
||||
ConnectorBindType.KvBind,
|
||||
ConnectorBindType.AuthBind,
|
||||
ConnectorBindType.KvAuthBind,
|
||||
ConnectorBindType.TemplateBind, // mcp未配置时禁用,模版始终为已配置
|
||||
ConnectorBindType.TemplateBind, // Disable when mcp is not configured, the template is always configured
|
||||
].includes(bind_type) &&
|
||||
config_status === ConnectorConfigStatus.NotConfigured;
|
||||
return notConfigured;
|
||||
};
|
||||
|
||||
// 不能发布的场景:
|
||||
// 1. 未绑定&未授权
|
||||
// 2. 后端下发的不能发布(如:没有workflow不能发api,有私有插件不能发模板,审核中不能发布的渠道)
|
||||
// Scenarios that cannot be published:
|
||||
// 1. Unbound & Unauthorized
|
||||
// 2. Those sent by the backend cannot be released (such as: APIs cannot be sent without workflow, templates cannot be sent with private plugins, and channels that cannot be released during review)
|
||||
export const getDisabledPublish = (
|
||||
connector: PublishConnectorInfo,
|
||||
): boolean => {
|
||||
const { allow_publish } = connector;
|
||||
// 未绑定&未授权
|
||||
// Unbound & Unauthorized
|
||||
const notConfigured = getConnectorNotConfigured(connector);
|
||||
|
||||
const connectorDisabled = notConfigured || !allow_publish;
|
||||
|
||||
// 审核中不能发布渠道的场景后端下发 allow_publish
|
||||
// The backend of the scenario where the channel cannot be released during the review is issued allow_publish
|
||||
return connectorDisabled;
|
||||
};
|
||||
|
||||
@@ -72,12 +72,12 @@ export function formatConnectorGroups(
|
||||
}
|
||||
if (c.connector_union_id) {
|
||||
const unionId = c.connector_union_id;
|
||||
// 如果当前 union_id 已经被添加到分组中,则跳过
|
||||
// If the current union_id has already been added to the group, skip
|
||||
if (group.connectors.some(i => i.connector_union_id === unionId)) {
|
||||
continue;
|
||||
}
|
||||
let connectorInfo = c;
|
||||
// 优先取 union 选中的 connector,否则取第一个
|
||||
// Give priority to the connector selected by the union, otherwise take the first one.
|
||||
const unionSelection = connectors.find(i => i.id === unions[unionId]);
|
||||
if (unionSelection) {
|
||||
connectorInfo = unionSelection;
|
||||
|
||||
@@ -56,7 +56,7 @@ const getKvBindStatus = (record: PublishConnectorInfo): ConfigStatusUI => {
|
||||
[ConnectorConfigStatus.NotConfigured]: I18n.t(
|
||||
'bot_publish_columns_status_not_configured',
|
||||
),
|
||||
// 业务不会走到下面3个case
|
||||
// Business will not go to the following 3 cases
|
||||
[ConnectorConfigStatus.Configuring]: '',
|
||||
[ConnectorConfigStatus.Disconnected]: '',
|
||||
[ConnectorConfigStatus.NeedReconfiguring]: '',
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
|
||||
export const incrementVersionNumber = (input: string) => {
|
||||
// 定义正则表达式,匹配 "数字.数字.数字" 的模式
|
||||
// Define regular expressions that match the pattern of "number. number. number"
|
||||
const regex = /(\d+)\.(\d+)\.(\d+)/g;
|
||||
|
||||
// 使用 replace 方法和回调函数对匹配的部分进行替换
|
||||
// Use the replace method and callback function to replace the matching part
|
||||
// eslint-disable-next-line max-params
|
||||
const result = input.replace(regex, (_match, p1, p2, p3) => {
|
||||
// 将最后一个数字加 1
|
||||
// Add 1 to the last number.
|
||||
const incrementedP3 = parseInt(String(p3), 10) + 1;
|
||||
// 返回新的字符串
|
||||
// Return a new string
|
||||
return `${p1}.${p2}.${incrementedP3}`;
|
||||
});
|
||||
|
||||
|
||||
@@ -60,17 +60,17 @@ export async function initPublishStore(
|
||||
const { connector_ids = [], connector_publish_config = {} } =
|
||||
last_publish_info;
|
||||
|
||||
// 初始化默认选中的渠道
|
||||
// Initialize the default selected channel
|
||||
const initSelectedConnectors: string[] = [];
|
||||
const initConnectors: Record<string, Record<string, string>> = {};
|
||||
for (const id of connector_ids) {
|
||||
const connector = connector_list.find(c => c.id === id);
|
||||
// 过滤掉不允许发布的渠道
|
||||
// Filter out channels that are not allowed to publish
|
||||
if (!connector || getDisabledPublish(connector)) {
|
||||
continue;
|
||||
}
|
||||
if (connector.connector_union_id) {
|
||||
// 对于 union 的 connector ,选中其 union id
|
||||
// For the connector of union, select its union id.
|
||||
initSelectedConnectors.push(connector.connector_union_id);
|
||||
initConnectors[connector.id] = connector.bind_info;
|
||||
} else {
|
||||
@@ -79,7 +79,7 @@ export async function initPublishStore(
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化每个 union 选中的 connector,如果上次没发布该渠道,则选中第一个
|
||||
// Initialize the connector selected by each union, and select the first one if the channel was not published last time
|
||||
const initUnions: Record<string, string> = {};
|
||||
for (const [unionId, info] of Object.entries(connector_union_info_map)) {
|
||||
initUnions[unionId] =
|
||||
@@ -87,9 +87,9 @@ export async function initPublishStore(
|
||||
?.connector_id ?? info.connector_options[0].connector_id;
|
||||
}
|
||||
|
||||
// 回填社交渠道选择的 chatflow,优先级:
|
||||
// 1. draft 中保存的 chatflow
|
||||
// 2. 上次发布的第一个 SocialPlatform 选择的 chatflow
|
||||
// Backfill the chatflow of social channel selection, priority:
|
||||
// 1. Saved chatflows in drafts
|
||||
// 2. Chatflow selected by the first SocialPlatform released last time
|
||||
let lastSocialPlatformChatflow: ConnectorPublishConfig | undefined;
|
||||
if (draft?.socialPlatformConfig?.selected_workflows?.[0].workflow_id) {
|
||||
lastSocialPlatformChatflow = draft.socialPlatformConfig;
|
||||
@@ -109,7 +109,7 @@ export async function initPublishStore(
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 draft 中保存的信息回填 WebSDK 渠道选择的 chatflow
|
||||
// Backfill the chatflow selected by the WebSDK channel based on the information saved in the draft
|
||||
if (draft?.sdkConfig?.selected_workflows?.[0].workflow_id) {
|
||||
connector_publish_config[WEB_SDK_CONNECTOR_ID] = draft.sdkConfig;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ export async function initPublishStore(
|
||||
);
|
||||
|
||||
const lastPublishVersionNumber = last_publish_info.version_number;
|
||||
// 用户没有 draft 并且存在发布过的版本 则将上一次发布的版本号进行处理
|
||||
// If the user does not have a draft and there is a published version, the last released version number will be processed
|
||||
const fixedVersionNumber = getFixedVersionNumber({
|
||||
lastPublishVersionNumber,
|
||||
draftVersionNumber: draft?.versionNumber,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { type StoreBindKey } from '@/store';
|
||||
|
||||
type SelfMapping<T extends string> = {
|
||||
[K in T]: K; // 关键语法:将每个字面量类型映射为自己
|
||||
[K in T]: K; // Key syntax: Mapping each literal type to itself
|
||||
};
|
||||
|
||||
type KeyMapping = SelfMapping<StoreBindKey>;
|
||||
@@ -25,7 +25,7 @@ type KeyMapping = SelfMapping<StoreBindKey>;
|
||||
export const isStoreBindConfigured = (
|
||||
config: Record<string, string>,
|
||||
): boolean => {
|
||||
// 防止 StoreBindKey 有变动导致 bug
|
||||
// Prevent StoreBindKey changes from causing bugs
|
||||
const { category_id, display_screen }: KeyMapping = {
|
||||
category_id: 'category_id',
|
||||
display_screen: 'display_screen',
|
||||
|
||||
Reference in New Issue
Block a user