mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
pref: useScrollPagination support debounce and throttle. (#4355)
* pref: useScrollPagination support debounce and throttle. * fix: useScrollPagination loading * fix: isloading * fix: org search path hide
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
|||||||
} from 'ahooks';
|
} from 'ahooks';
|
||||||
import MyBox from '../components/common/MyBox';
|
import MyBox from '../components/common/MyBox';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { useRequest2 } from './useRequest';
|
||||||
|
|
||||||
type ItemHeight<T> = (index: number, data: T) => number;
|
type ItemHeight<T> = (index: number, data: T) => number;
|
||||||
const thresholdVal = 100;
|
const thresholdVal = 100;
|
||||||
@@ -183,22 +184,21 @@ export function useScrollPagination<
|
|||||||
>(
|
>(
|
||||||
api: (data: TParams) => Promise<TData>,
|
api: (data: TParams) => Promise<TData>,
|
||||||
{
|
{
|
||||||
refreshDeps,
|
|
||||||
scrollLoadType = 'bottom',
|
scrollLoadType = 'bottom',
|
||||||
|
|
||||||
pageSize = 10,
|
pageSize = 10,
|
||||||
params = {},
|
params = {},
|
||||||
EmptyTip,
|
EmptyTip,
|
||||||
showErrorToast = true
|
showErrorToast = true,
|
||||||
|
...props
|
||||||
}: {
|
}: {
|
||||||
refreshDeps?: any[];
|
|
||||||
scrollLoadType?: 'top' | 'bottom';
|
scrollLoadType?: 'top' | 'bottom';
|
||||||
|
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
params?: Record<string, any>;
|
params?: Record<string, any>;
|
||||||
EmptyTip?: React.JSX.Element;
|
EmptyTip?: React.JSX.Element;
|
||||||
showErrorToast?: boolean;
|
showErrorToast?: boolean;
|
||||||
}
|
} & Parameters<typeof useRequest2>[1]
|
||||||
) {
|
) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -213,6 +213,7 @@ export function useScrollPagination<
|
|||||||
const loadData = useLockFn(
|
const loadData = useLockFn(
|
||||||
async (init = false, ScrollContainerRef?: RefObject<HTMLDivElement>) => {
|
async (init = false, ScrollContainerRef?: RefObject<HTMLDivElement>) => {
|
||||||
if (noMore && !init) return;
|
if (noMore && !init) return;
|
||||||
|
setTrue();
|
||||||
|
|
||||||
if (init) {
|
if (init) {
|
||||||
setData([]);
|
setData([]);
|
||||||
@@ -221,8 +222,6 @@ export function useScrollPagination<
|
|||||||
|
|
||||||
const offset = init ? 0 : data.length;
|
const offset = init ? 0 : data.length;
|
||||||
|
|
||||||
setTrue();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api({
|
const res = await api({
|
||||||
offset,
|
offset,
|
||||||
@@ -274,7 +273,7 @@ export function useScrollPagination<
|
|||||||
({
|
({
|
||||||
children,
|
children,
|
||||||
ScrollContainerRef,
|
ScrollContainerRef,
|
||||||
isLoading,
|
isLoading: isLoadingProp,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
@@ -283,7 +282,7 @@ export function useScrollPagination<
|
|||||||
} & BoxProps) => {
|
} & BoxProps) => {
|
||||||
const ref = ScrollContainerRef || ScrollRef;
|
const ref = ScrollContainerRef || ScrollRef;
|
||||||
const loadText = useMemo(() => {
|
const loadText = useMemo(() => {
|
||||||
if (isLoading) return t('common:common.is_requesting');
|
if (isLoading || isLoadingProp) return t('common:common.is_requesting');
|
||||||
if (noMore) return t('common:common.request_end');
|
if (noMore) return t('common:common.request_end');
|
||||||
return t('common:common.request_more');
|
return t('common:common.request_more');
|
||||||
}, [isLoading, noMore]);
|
}, [isLoading, noMore]);
|
||||||
@@ -338,13 +337,13 @@ export function useScrollPagination<
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Reload data
|
// Reload data
|
||||||
useRequest(
|
useRequest2(
|
||||||
async () => {
|
async () => {
|
||||||
loadData(true);
|
loadData(true);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
manual: false,
|
manual: false,
|
||||||
refreshDeps
|
...props
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -79,7 +79,10 @@ function MemberModal({
|
|||||||
withOrgs: true,
|
withOrgs: true,
|
||||||
status: 'active',
|
status: 'active',
|
||||||
searchKey
|
searchKey
|
||||||
}
|
},
|
||||||
|
throttleWait: 500,
|
||||||
|
debounceWait: 200,
|
||||||
|
refreshDeps: [searchKey]
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -100,13 +103,6 @@ function MemberModal({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const search = _.debounce(() => {
|
|
||||||
refreshList();
|
|
||||||
refreshGroups();
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
useEffect(search, [searchKey]);
|
|
||||||
|
|
||||||
const [selectedOrgList, setSelectedOrgIdList] = useState<OrgListItemType[]>([]);
|
const [selectedOrgList, setSelectedOrgIdList] = useState<OrgListItemType[]>([]);
|
||||||
|
|
||||||
const [selectedMemberList, setSelectedMemberList] = useState<
|
const [selectedMemberList, setSelectedMemberList] = useState<
|
||||||
|
@@ -62,11 +62,11 @@ function GroupEditModal({
|
|||||||
status: 'active',
|
status: 'active',
|
||||||
withOrgs: true,
|
withOrgs: true,
|
||||||
searchKey
|
searchKey
|
||||||
}
|
},
|
||||||
|
throttleWait: 500,
|
||||||
|
debounceWait: 200,
|
||||||
|
refreshDeps: [searchKey]
|
||||||
});
|
});
|
||||||
const refetchMemberList = _.debounce(refreshList, 200);
|
|
||||||
|
|
||||||
useEffect(() => refetchMemberList, [searchKey]);
|
|
||||||
|
|
||||||
const groupId = useMemo(() => String(group._id), [group._id]);
|
const groupId = useMemo(() => String(group._id), [group._id]);
|
||||||
|
|
||||||
|
@@ -48,14 +48,14 @@ export function ChangeOwnerModal({
|
|||||||
{
|
{
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
params: {
|
params: {
|
||||||
searchKey: searchKey
|
searchKey
|
||||||
}
|
},
|
||||||
|
refreshDeps: [searchKey],
|
||||||
|
debounceWait: 200,
|
||||||
|
throttleWait: 500
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const search = _.debounce(refreshList, 500);
|
|
||||||
useEffect(() => search, [searchKey]);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenMemberListMenu,
|
isOpen: isOpenMemberListMenu,
|
||||||
onClose: onCloseMemberListMenu,
|
onClose: onCloseMemberListMenu,
|
||||||
|
@@ -102,17 +102,12 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
|
|||||||
withPermission: true,
|
withPermission: true,
|
||||||
withOrgs: true,
|
withOrgs: true,
|
||||||
searchKey
|
searchKey
|
||||||
}
|
},
|
||||||
|
refreshDeps: [searchKey, status],
|
||||||
|
throttleWait: 500,
|
||||||
|
debounceWait: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshList = _.debounce(() => {
|
|
||||||
refetchMemberList();
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refreshList();
|
|
||||||
}, [searchKey, status]);
|
|
||||||
|
|
||||||
const onRefreshMembers = useCallback(() => {
|
const onRefreshMembers = useCallback(() => {
|
||||||
refetchMemberList();
|
refetchMemberList();
|
||||||
}, [refetchMemberList]);
|
}, [refetchMemberList]);
|
||||||
|
@@ -3,7 +3,6 @@ import { Box, Button, Flex, Grid, HStack, ModalBody, ModalFooter } from '@chakra
|
|||||||
import type { GroupMemberRole } from '@fastgpt/global/support/permission/memberGroup/constant';
|
import type { GroupMemberRole } from '@fastgpt/global/support/permission/memberGroup/constant';
|
||||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import type { IconNameType } from '@fastgpt/web/components/common/Icon/type';
|
|
||||||
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
|
||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||||
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||||
@@ -31,32 +30,32 @@ function OrgMemberManageModal({
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [searchKey, setSearchKey] = useState('');
|
||||||
|
|
||||||
const {
|
const { data: allMembers, ScrollData: MemberScrollData } = useScrollPagination(getTeamMembers, {
|
||||||
data: allMembers,
|
|
||||||
ScrollData: MemberScrollData,
|
|
||||||
isLoading: isLoadingMembers
|
|
||||||
} = useScrollPagination(getTeamMembers, {
|
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
params: {
|
params: {
|
||||||
withOrgs: true,
|
withOrgs: true,
|
||||||
withPermission: false,
|
withPermission: false,
|
||||||
status: 'active'
|
status: 'active',
|
||||||
}
|
searchKey
|
||||||
|
},
|
||||||
|
throttleWait: 500,
|
||||||
|
debounceWait: 200,
|
||||||
|
refreshDeps: [searchKey]
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const { data: orgMembers, ScrollData: OrgMemberScrollData } = useScrollPagination(
|
||||||
data: orgMembers,
|
getTeamMembers,
|
||||||
ScrollData: OrgMemberScrollData,
|
{
|
||||||
isLoading: isLoadingOrgMembers
|
pageSize: 100000,
|
||||||
} = useScrollPagination(getTeamMembers, {
|
params: {
|
||||||
pageSize: 100000,
|
orgId: currentOrg._id,
|
||||||
params: {
|
withOrgs: false,
|
||||||
orgId: currentOrg._id,
|
withPermission: false
|
||||||
withOrgs: false,
|
}
|
||||||
withPermission: false
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
const [selected, setSelected] = useState<{ name: string; tmbId: string; avatar: string }[]>([]);
|
const [selected, setSelected] = useState<{ name: string; tmbId: string; avatar: string }[]>([]);
|
||||||
|
|
||||||
@@ -70,8 +69,6 @@ function OrgMemberManageModal({
|
|||||||
);
|
);
|
||||||
}, [orgMembers]);
|
}, [orgMembers]);
|
||||||
|
|
||||||
const [searchKey, setSearchKey] = useState('');
|
|
||||||
|
|
||||||
const { run: onUpdate, loading: isLoadingUpdate } = useRequest2(
|
const { run: onUpdate, loading: isLoadingUpdate } = useRequest2(
|
||||||
() => {
|
() => {
|
||||||
return putUpdateOrgMembers({
|
return putUpdateOrgMembers({
|
||||||
@@ -147,7 +144,7 @@ function OrgMemberManageModal({
|
|||||||
setSearchKey(e.target.value);
|
setSearchKey(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<MemberScrollData mt={3} flexGrow="1" overflow={'auto'} isLoading={isLoadingMembers}>
|
<MemberScrollData mt={3} flexGrow="1" overflow={'auto'}>
|
||||||
{allMembers.map((member) => {
|
{allMembers.map((member) => {
|
||||||
return (
|
return (
|
||||||
<MemberItemCard
|
<MemberItemCard
|
||||||
@@ -163,12 +160,7 @@ function OrgMemberManageModal({
|
|||||||
</MemberScrollData>
|
</MemberScrollData>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex flexDirection="column" p="4" overflowY="auto" overflowX="hidden">
|
<Flex flexDirection="column" p="4" overflowY="auto" overflowX="hidden">
|
||||||
<OrgMemberScrollData
|
<OrgMemberScrollData mt={3} flexGrow="1" overflow={'auto'}>
|
||||||
mt={3}
|
|
||||||
flexGrow="1"
|
|
||||||
overflow={'auto'}
|
|
||||||
isLoading={isLoadingOrgMembers}
|
|
||||||
>
|
|
||||||
<Box mt={2}>{`${t('common:chosen')}:${selected.length}`}</Box>
|
<Box mt={2}>{`${t('common:chosen')}:${selected.length}`}</Box>
|
||||||
{selected.map((member) => {
|
{selected.map((member) => {
|
||||||
return (
|
return (
|
||||||
|
@@ -81,7 +81,7 @@ function OrgTable({ Tabs }: { Tabs: React.ReactNode }) {
|
|||||||
const {
|
const {
|
||||||
currentOrg,
|
currentOrg,
|
||||||
orgs,
|
orgs,
|
||||||
isLoadingOrgs,
|
isLoading,
|
||||||
paths,
|
paths,
|
||||||
onClickOrg,
|
onClickOrg,
|
||||||
members,
|
members,
|
||||||
@@ -134,18 +134,14 @@ function OrgTable({ Tabs }: { Tabs: React.ReactNode }) {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<MyBox
|
<MyBox flex={'1 0 0'} h={0} display={'flex'} flexDirection={'column'}>
|
||||||
flex={'1 0 0'}
|
|
||||||
h={0}
|
|
||||||
display={'flex'}
|
|
||||||
flexDirection={'column'}
|
|
||||||
isLoading={isLoadingOrgs}
|
|
||||||
>
|
|
||||||
<Box mb={3}>
|
<Box mb={3}>
|
||||||
<Path paths={paths} rootName={userInfo?.team?.teamName} onClick={onPathClick} />
|
{!searchKey && (
|
||||||
|
<Path paths={paths} rootName={userInfo?.team?.teamName} onClick={onPathClick} />
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Flex flex={'1 0 0'} h={0} w={'100%'} gap={'4'}>
|
<Flex flex={'1 0 0'} h={0} w={'100%'} gap={'4'}>
|
||||||
<MemberScrollData flex="1">
|
<MemberScrollData flex="1" isLoading={isLoading}>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
<Thead>
|
<Thead>
|
||||||
|
@@ -185,8 +185,7 @@ const TeamCloud = ({
|
|||||||
const {
|
const {
|
||||||
ScrollData,
|
ScrollData,
|
||||||
data: scrollDataList,
|
data: scrollDataList,
|
||||||
setData,
|
setData
|
||||||
isLoading
|
|
||||||
} = useScrollPagination(getWorkflowVersionList, {
|
} = useScrollPagination(getWorkflowVersionList, {
|
||||||
pageSize: 30,
|
pageSize: 30,
|
||||||
params: {
|
params: {
|
||||||
@@ -230,7 +229,7 @@ const TeamCloud = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollData isLoading={isLoading || isLoadingVersion} flex={'1 0 0'} px={5}>
|
<ScrollData flex={'1 0 0'} px={5} isLoading={isLoadingVersion}>
|
||||||
{scrollDataList.map((item, index) => {
|
{scrollDataList.map((item, index) => {
|
||||||
const firstPublishedIndex = scrollDataList.findIndex((data) => data.isPublish);
|
const firstPublishedIndex = scrollDataList.findIndex((data) => data.isPublish);
|
||||||
|
|
||||||
|
@@ -41,14 +41,11 @@ function useOrg({ withPermission = true }: { withPermission?: boolean } = {}) {
|
|||||||
() => getOrgList({ orgId: currentOrg._id, withPermission: withPermission, searchKey }),
|
() => getOrgList({ orgId: currentOrg._id, withPermission: withPermission, searchKey }),
|
||||||
{
|
{
|
||||||
manual: false,
|
manual: false,
|
||||||
refreshDeps: [userInfo?.team?.teamId, path, currentOrg._id]
|
refreshDeps: [userInfo?.team?.teamId, path, currentOrg._id, searchKey],
|
||||||
|
debounceWait: 200,
|
||||||
|
throttleWait: 500
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const search = _.debounce(() => {
|
|
||||||
if (!searchKey) return;
|
|
||||||
refetchOrgs();
|
|
||||||
}, 200);
|
|
||||||
useEffect(() => search, [searchKey]);
|
|
||||||
|
|
||||||
const paths = useMemo(() => {
|
const paths = useMemo(() => {
|
||||||
if (!currentOrg) return [];
|
if (!currentOrg) return [];
|
||||||
@@ -63,14 +60,19 @@ function useOrg({ withPermission = true }: { withPermission?: boolean } = {}) {
|
|||||||
}, [currentOrg, orgStack]);
|
}, [currentOrg, orgStack]);
|
||||||
|
|
||||||
const onClickOrg = (org: OrgListItemType) => {
|
const onClickOrg = (org: OrgListItemType) => {
|
||||||
setOrgStack([...orgStack, org]);
|
if (searchKey) {
|
||||||
setSearchKey('');
|
setOrgStack([org]);
|
||||||
|
setSearchKey('');
|
||||||
|
} else {
|
||||||
|
setOrgStack([...orgStack, org]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: members = [],
|
data: members = [],
|
||||||
ScrollData: MemberScrollData,
|
ScrollData: MemberScrollData,
|
||||||
refreshList: refetchMembers
|
refreshList: refetchMembers,
|
||||||
|
isLoading: isLoadingMembers
|
||||||
} = useScrollPagination(getTeamMembers, {
|
} = useScrollPagination(getTeamMembers, {
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
params: {
|
params: {
|
||||||
@@ -106,11 +108,13 @@ function useOrg({ withPermission = true }: { withPermission?: boolean } = {}) {
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isLoading = isLoadingOrgs || isLoadingMembers;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
orgStack,
|
orgStack,
|
||||||
currentOrg,
|
currentOrg,
|
||||||
orgs,
|
orgs,
|
||||||
isLoadingOrgs,
|
isLoading,
|
||||||
paths,
|
paths,
|
||||||
onClickOrg,
|
onClickOrg,
|
||||||
members,
|
members,
|
||||||
|
Reference in New Issue
Block a user