feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 React, { useRef, useState } from 'react';
|
||||
|
||||
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Modal, Search } from '@coze-arch/coze-design';
|
||||
|
||||
import { useIntelligenceSearch } from '../hooks/use-case/use-intelligence-search';
|
||||
import { IntelligenceList } from './intelligence-list';
|
||||
|
||||
export interface SelectIntelligenceModalProps {
|
||||
visible: boolean;
|
||||
spaceId: string;
|
||||
onSelect?: (intelligence: IntelligenceData) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export const SelectIntelligenceModal: React.FC<
|
||||
SelectIntelligenceModalProps
|
||||
> = ({ visible, onCancel, onSelect, spaceId }) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
|
||||
const { loading, data, loadingMore, noMore } = useIntelligenceSearch({
|
||||
spaceId,
|
||||
searchValue,
|
||||
containerRef,
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
width={640}
|
||||
height={588}
|
||||
className="[&_.semi-modal-header]:flex [&_.semi-modal-header]:items-center [&_.semi-modal-header]:px-3 [&_.semi-modal-content]:!px-3 [&_.semi-modal-content]:!coz-bg-max"
|
||||
footer={null}
|
||||
title={
|
||||
<div className="flex items-center justify-between w-full mr-4">
|
||||
<div className="coz-fg-plus text-[20px] font-medium">
|
||||
{I18n.t('select_agent_title')}
|
||||
</div>
|
||||
<Search
|
||||
placeholder={I18n.t('Search')}
|
||||
value={searchValue}
|
||||
onChange={setSearchValue}
|
||||
showClear
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div ref={containerRef} className="max-h-[480px] h-full overflow-auto">
|
||||
<IntelligenceList
|
||||
loading={loading}
|
||||
loadingMore={loadingMore}
|
||||
noMore={noMore}
|
||||
data={data}
|
||||
searchValue={searchValue}
|
||||
onSelect={intelligenceData => {
|
||||
onSelect?.(intelligenceData);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Typography } from '@coze-arch/coze-design';
|
||||
import { formatDate, getFormatDateType } from '@coze-arch/bot-utils';
|
||||
|
||||
import { highlightService } from '../services/use-case-services/highlight-text.service';
|
||||
|
||||
interface IntelligenceItemProps {
|
||||
intelligence: IntelligenceData;
|
||||
searchValue: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const IntelligenceItem: React.FC<IntelligenceItemProps> = ({
|
||||
intelligence,
|
||||
searchValue,
|
||||
onClick,
|
||||
}) => {
|
||||
const { basic_info } = intelligence;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="rounded-lg hover:coz-mg-secondary-hovered cursor-pointer h-[80px] box-border"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-center gap-[14px] px-3 h-full">
|
||||
<img
|
||||
src={basic_info?.icon_url}
|
||||
className="flex-shrink-0 w-[52px] h-[52px] rounded-lg"
|
||||
alt={basic_info?.name}
|
||||
/>
|
||||
<div className="w-full overflow-hidden flex flex-col gap-1 justify-center border-b-[0.6px] border-solid border-0 coz-stroke-primary pb-3 pt-2 h-full">
|
||||
<div className="font-medium text-sm">
|
||||
<Typography.Text className="text-[16px] !font-medium w-full">
|
||||
{highlightService.highlightText(
|
||||
basic_info?.name || '',
|
||||
searchValue,
|
||||
)}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
{basic_info?.description ? (
|
||||
<div className="text-sm leading-4 coz-fg-secondary">
|
||||
<Typography.Text
|
||||
className="text-sm w-full"
|
||||
ellipsis={{
|
||||
rows: 1,
|
||||
}}
|
||||
>
|
||||
{highlightService.highlightText(
|
||||
basic_info?.description || '',
|
||||
searchValue,
|
||||
)}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="text-xs coz-fg-secondary flex items-center gap-1">
|
||||
<div className="text-xs coz-fg-secondary">
|
||||
{I18n.t('bot_list_rank_tag_edited')}
|
||||
</div>
|
||||
<div className="text-xs coz-fg-secondary">
|
||||
{formatDate(
|
||||
Number(basic_info?.update_time),
|
||||
getFormatDateType(Number(basic_info?.update_time)),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozLoading, IconCozEmpty } from '@coze-arch/coze-design/icons';
|
||||
import { Spin, IconButton } from '@coze-arch/coze-design';
|
||||
|
||||
import { IntelligenceItem } from './intelligence-item';
|
||||
|
||||
interface IntelligenceListProps {
|
||||
loading: boolean;
|
||||
loadingMore: boolean;
|
||||
noMore: boolean;
|
||||
data?: {
|
||||
list: IntelligenceData[];
|
||||
hasMore: boolean;
|
||||
};
|
||||
searchValue: string;
|
||||
onSelect: (intelligence: IntelligenceData) => void;
|
||||
}
|
||||
|
||||
export const IntelligenceList: React.FC<IntelligenceListProps> = ({
|
||||
loading,
|
||||
loadingMore,
|
||||
noMore,
|
||||
data,
|
||||
searchValue,
|
||||
onSelect,
|
||||
}) => {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex justify-center py-8">
|
||||
<Spin />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!data?.list.length) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center items-center w-full h-full">
|
||||
<IconCozEmpty className="w-[48px] h-[48px] coz-fg-dim" />
|
||||
<div className="text-sm coz-fg-primary mt-2">
|
||||
{I18n.t('select_agent_no_result')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
{/* 上遮罩 */}
|
||||
<div className="sticky top-0 left-0 right-0 h-[20px] bg-gradient-to-b from-[rgba(255,255,255,1)] to-transparent pointer-events-none z-10" />
|
||||
|
||||
{/* 列表内容 */}
|
||||
<div className="styled-scrollbar">
|
||||
{data.list.map(intelligence => (
|
||||
<IntelligenceItem
|
||||
key={intelligence.basic_info?.id}
|
||||
intelligence={intelligence}
|
||||
searchValue={searchValue}
|
||||
onClick={() => onSelect(intelligence)}
|
||||
/>
|
||||
))}
|
||||
|
||||
{loadingMore ? (
|
||||
<div className="flex items-center justify-center h-[38px] my-[20px] text-[12px]">
|
||||
<IconButton icon={<IconCozLoading />} loading color="secondary" />
|
||||
<div>{I18n.t('Loading')}...</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{noMore && data.list.length > 0 ? (
|
||||
<div className="h-[38px] my-[20px]" />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{/* 下遮罩 */}
|
||||
<div className="sticky bottom-0 left-0 right-0 h-[20px] bg-gradient-to-t from-[rgba(255,255,255,1)] to-transparent pointer-events-none z-10" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 { useInfiniteScroll } from 'ahooks';
|
||||
|
||||
import { type IntelligenceList } from '../../services/use-case-services/intelligence-search.service';
|
||||
import { intelligenceSearchService } from '../../services/use-case-services/intelligence-search.service';
|
||||
|
||||
interface UseIntelligenceSearchProps {
|
||||
spaceId: string;
|
||||
searchValue: string;
|
||||
containerRef: React.RefObject<HTMLElement>;
|
||||
}
|
||||
|
||||
export const useIntelligenceSearch = ({
|
||||
spaceId,
|
||||
searchValue,
|
||||
containerRef,
|
||||
}: UseIntelligenceSearchProps) =>
|
||||
useInfiniteScroll<IntelligenceList>(
|
||||
async d =>
|
||||
await intelligenceSearchService.searchIntelligence({
|
||||
spaceId,
|
||||
searchValue,
|
||||
cursorId: d?.nextCursorId,
|
||||
}),
|
||||
{
|
||||
target: containerRef,
|
||||
isNoMore: d => !d?.hasMore,
|
||||
reloadDeps: [searchValue],
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 { useState } from 'react';
|
||||
|
||||
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
import { SelectIntelligenceModal } from '../../components';
|
||||
|
||||
interface ModalProps {
|
||||
spaceId: string;
|
||||
onSelect?: (intelligence: IntelligenceData) => void;
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
export const useModal = (props: ModalProps) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const close = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const open = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
return {
|
||||
node: visible ? (
|
||||
<SelectIntelligenceModal
|
||||
visible={visible}
|
||||
spaceId={props.spaceId}
|
||||
onSelect={props.onSelect}
|
||||
onCancel={close}
|
||||
/>
|
||||
) : null,
|
||||
close,
|
||||
open,
|
||||
};
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
export { SelectIntelligenceModal } from './components';
|
||||
export { useModal } from './hooks/use-case/use-modal';
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
export class HighlightTextService {
|
||||
highlightText(text: string, keyword: string) {
|
||||
if (!keyword) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const parts = text.split(new RegExp(`(${keyword})`, 'gi'));
|
||||
|
||||
return (
|
||||
<>
|
||||
{parts.map((part, i) =>
|
||||
part.toLowerCase() === keyword.toLowerCase() ? (
|
||||
<span key={i} className="coz-fg-hglt-yellow">
|
||||
{part}
|
||||
</span>
|
||||
) : (
|
||||
part
|
||||
),
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const highlightService = new HighlightTextService();
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 {
|
||||
search,
|
||||
IntelligenceStatus,
|
||||
type IntelligenceData,
|
||||
SearchScope,
|
||||
IntelligenceType,
|
||||
BotMode,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { intelligenceApi } from '@coze-arch/bot-api';
|
||||
|
||||
export interface IntelligenceList {
|
||||
list: IntelligenceData[];
|
||||
hasMore: boolean;
|
||||
nextCursorId?: string;
|
||||
}
|
||||
|
||||
export const intelligenceSearchService = {
|
||||
async searchIntelligence(params: {
|
||||
spaceId: string;
|
||||
searchValue: string;
|
||||
cursorId?: string;
|
||||
}): Promise<IntelligenceList> {
|
||||
const resp = await intelligenceApi.GetDraftIntelligenceList({
|
||||
space_id: params.spaceId,
|
||||
name: params.searchValue,
|
||||
size: 20,
|
||||
cursor_id: params.cursorId,
|
||||
order_by: search.OrderBy.UpdateTime,
|
||||
types: [IntelligenceType.Bot],
|
||||
status: [IntelligenceStatus.Using],
|
||||
search_scope: SearchScope.CreateByMe,
|
||||
option: {
|
||||
need_replica: true,
|
||||
},
|
||||
});
|
||||
const intelligenceList = resp?.data?.intelligences ?? [];
|
||||
// 只保留single mode bot
|
||||
const singleModeBotList = intelligenceList.filter(
|
||||
intelligence => intelligence.other_info?.bot_mode === BotMode.SingleMode,
|
||||
);
|
||||
|
||||
if (resp?.code === 0 && resp?.data) {
|
||||
return {
|
||||
list: singleModeBotList,
|
||||
hasMore: Boolean(resp.data.has_more),
|
||||
nextCursorId: resp.data.next_cursor_id,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
list: [],
|
||||
hasMore: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user