Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit17641cd

Browse files
authored
Merge branch 'dev' into ui/environments-breadcrumbs
2 parents17f3c7d +cda5657 commit17641cd

File tree

3 files changed

+138
-126
lines changed

3 files changed

+138
-126
lines changed

‎client/packages/lowcoder/src/app.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ import {
3131
ADMIN_AUTH_URL,
3232
PUBLIC_APP_EDITOR_URL,
3333
}from"constants/routesURL";
34-
importReact,{useMemo}from"react";
34+
importReact,{useEffect,useMemo}from"react";
3535
import{createRoot}from"react-dom/client";
3636
import{Helmet}from"react-helmet";
37-
import{connect,Provider}from"react-redux";
37+
import{connect,Provider,useDispatch,useSelector}from"react-redux";
3838
import{Redirect,Route,Router,Switch}from"react-router-dom";
3939
importtype{AppState}from"redux/reducers";
40-
import{fetchConfigAction}from"redux/reduxActions/configActions";
40+
import{fetchConfigAction,fetchDeploymentIdAction}from"redux/reduxActions/configActions";
4141
import{fetchUserAction}from"redux/reduxActions/userActions";
4242
import{reduxStore}from"redux/store/store";
4343
import{developEnv}from"util/envUtils";
@@ -50,10 +50,10 @@ import { loadComps } from "comps";
5050
import{initApp}from"util/commonUtils";
5151
import{favicon}from"assets/images";
5252
import{hasQueryParam}from"util/urlUtils";
53-
import{isFetchUserFinished}from"redux/selectors/usersSelectors";// getCurrentUser,
53+
import{getUser,isFetchUserFinished}from"redux/selectors/usersSelectors";// getCurrentUser,
5454
import{getIsCommonSettingFetched}from"redux/selectors/commonSettingSelectors";
5555
import{SystemWarning}from"./components/SystemWarning";
56-
import{getBrandingConfig}from"./redux/selectors/configSelectors";
56+
import{getBrandingConfig,getDeploymentId}from"./redux/selectors/configSelectors";
5757
import{buildMaterialPreviewURL}from"./util/materialUtils";
5858
importGlobalInstancesfrom'components/GlobalInstances';
5959
// import posthog from 'posthog-js'
@@ -64,6 +64,7 @@ import { fetchBrandingSetting } from "./redux/reduxActions/enterpriseActions";
6464
import{EnterpriseProvider}from"./util/context/EnterpriseContext";
6565
import{SimpleSubscriptionContextProvider}from"./util/context/SimpleSubscriptionContext";
6666
import{getBrandingSetting}from"./redux/selectors/enterpriseSelectors";
67+
import{fetchSubscriptionsAction}from"./redux/reduxActions/subscriptionActions";
6768

6869
constLazyUserAuthComp=React.lazy(()=>import("pages/userAuth"));
6970
constLazyInviteLanding=React.lazy(()=>import("pages/common/inviteLanding"));
@@ -81,6 +82,22 @@ const Wrapper = React.memo((props: {
8182
language:string,
8283
fontFamily?:string
8384
})=>{
85+
constdeploymentId=useSelector(getDeploymentId);
86+
constuser=useSelector(getUser);
87+
constdispatch=useDispatch();
88+
89+
useEffect(()=>{
90+
if(user.currentOrgId){
91+
dispatch(fetchDeploymentIdAction());
92+
}
93+
},[user.currentOrgId]);
94+
95+
useEffect(()=>{
96+
if(Boolean(deploymentId)){
97+
dispatch(fetchSubscriptionsAction())
98+
}
99+
},[deploymentId]);
100+
84101
consttheme=useMemo(()=>{
85102
return{
86103
hashed:false,

‎client/packages/lowcoder/src/comps/controls/iconscoutControl.tsx

Lines changed: 116 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
useIcon,
1313
wrapperToControlItem,
1414
}from"lowcoder-design";
15-
import{memo,ReactNode,useCallback,useMemo,useRef,useState}from"react";
15+
import{ReactNode,useCallback,useEffect,useMemo,useRef,useState}from"react";
1616
importstyledfrom"styled-components";
1717
importPopoverfrom"antd/es/popover";
1818
import{CloseIcon,SearchIcon}from"icons";
@@ -225,62 +225,85 @@ export const IconPicker = (props: {
225225
IconType?:"OnlyAntd"|"All"|"default"|undefined;
226226
})=>{
227227
constdraggableRef=useRef<HTMLDivElement>(null);
228-
const[visible,setVisible]=useState(false)
229-
const[loading,setLoading]=useState(false)
230-
const[downloading,setDownloading]=useState(false)
231-
const[searchText,setSearchText]=useState<string>('')
232-
const[searchResults,setSearchResults]=useState<Array<any>>([]);
233-
const{ subscriptions}=useSimpleSubscriptionContext();
234-
228+
const[visible,setVisible]=useState(false);
229+
const[loading,setLoading]=useState(false);
230+
const[downloading,setDownloading]=useState(false);
231+
const[searchText,setSearchText]=useState<string>('');
232+
const[searchResults,setSearchResults]=useState<Array<any>>([]);
235233
const[page,setPage]=useState(1);
236234
const[hasMore,setHasMore]=useState(true);
235+
constabortControllerRef=useRef<AbortController|null>(null);
236+
const{ subscriptions}=useSimpleSubscriptionContext();
237237

238-
239-
constmediaPackSubscription=subscriptions.find(
240-
sub=>sub.product===SubscriptionProductsEnum.MEDIAPACKAGE&&sub.status==='active'
238+
constmediaPackSubscription=useMemo(()=>
239+
subscriptions.find(
240+
sub=>sub.product===SubscriptionProductsEnum.MEDIAPACKAGE&&sub.status==='active'
241+
),
242+
[subscriptions]
241243
);
242244

243245
constonChangeRef=useRef(props.onChange);
244246
onChangeRef.current=props.onChange;
245247

248+
// Cleanup function for async operations
249+
useEffect(()=>{
250+
return()=>{
251+
if(abortControllerRef.current){
252+
abortControllerRef.current.abort();
253+
}
254+
};
255+
},[]);
256+
246257
constonChangeIcon=useCallback(
247258
(key:string,value:string,url:string)=>{
248259
onChangeRef.current(key,value,url);
249260
setVisible(false);
250-
},[]
261+
},
262+
[]
251263
);
252264

253-
constfetchResults=async(query:string,pageNum:number=1)=>{
265+
constfetchResults=useCallback(async(query:string,pageNum:number=1)=>{
266+
if(abortControllerRef.current){
267+
abortControllerRef.current.abort();
268+
}
269+
abortControllerRef.current=newAbortController();
270+
254271
setLoading(true);
272+
try{
273+
const[freeResult,premiumResult]=awaitPromise.all([
274+
searchAssets({
275+
...IconScoutSearchParams,
276+
asset:props.assetType,
277+
price:'free',
278+
query,
279+
page:pageNum,
280+
}),
281+
searchAssets({
282+
...IconScoutSearchParams,
283+
asset:props.assetType,
284+
price:'premium',
285+
query,
286+
page:pageNum,
287+
})
288+
]);
255289

256-
constfreeResult=awaitsearchAssets({
257-
...IconScoutSearchParams,
258-
asset:props.assetType,
259-
price:'free',
260-
query,
261-
page:pageNum,
262-
});
263-
264-
constpremiumResult=awaitsearchAssets({
265-
...IconScoutSearchParams,
266-
asset:props.assetType,
267-
price:'premium',
268-
query,
269-
page:pageNum,
270-
});
271-
272-
constcombined=[...freeResult.data, ...premiumResult.data];
273-
constisLastPage=combined.length<IconScoutSearchParams.per_page*2;
274-
275-
setSearchResults(prev=>
276-
pageNum===1 ?combined :[...prev, ...combined]
277-
);
278-
setHasMore(!isLastPage);
279-
setLoading(false);
280-
};
281-
290+
constcombined=[...freeResult.data, ...premiumResult.data];
291+
constisLastPage=combined.length<IconScoutSearchParams.per_page*2;
292+
293+
setSearchResults(prev=>
294+
pageNum===1 ?combined :[...prev, ...combined]
295+
);
296+
setHasMore(!isLastPage);
297+
}catch(error:any){
298+
if(error.name!=='AbortError'){
299+
console.error('Error fetching results:',error);
300+
}
301+
}finally{
302+
setLoading(false);
303+
}
304+
},[props.assetType]);
282305

283-
constdownloadAsset=async(
306+
constdownloadAsset=useCallback(async(
284307
uuid:string,
285308
downloadUrl:string,
286309
callback:(assetUrl:string)=>void,
@@ -293,29 +316,29 @@ export const IconPicker = (props: {
293316
});
294317
}
295318
}catch(error){
296-
console.error(error);
319+
console.error('Error downloading asset:',error);
297320
setDownloading(false);
298321
}
299-
}
322+
},[]);
300323

301-
constfetchDownloadUrl=async(uuid:string,preview:string)=>{
324+
constfetchDownloadUrl=useCallback(async(uuid:string,preview:string)=>{
302325
try{
303326
setDownloading(true);
304327
constresult=awaitgetAssetLinks(uuid,{
305328
format:props.assetType===AssetType.LOTTIE ?'lottie' :'svg',
306329
});
307330

308-
downloadAsset(uuid,result.download_url,(assetUrl:string)=>{
331+
awaitdownloadAsset(uuid,result.download_url,(assetUrl:string)=>{
309332
setDownloading(false);
310333
onChangeIcon(uuid,assetUrl,preview);
311334
});
312335
}catch(error){
313-
console.error(error);
336+
console.error('Error fetching download URL:',error);
314337
setDownloading(false);
315338
}
316-
}
339+
},[props.assetType,downloadAsset,onChangeIcon]);
317340

318-
consthandleChange=(e:{target:{value:any;};})=>{
341+
consthandleChange=useCallback((e:{target:{value:any;};})=>{
319342
constquery=e.target.value;
320343
setSearchText(query);// Update search text immediately
321344

@@ -324,9 +347,15 @@ export const IconPicker = (props: {
324347
}else{
325348
setSearchResults([]);// Clear results if input is too short
326349
}
327-
};
328-
329-
constdebouncedFetchResults=useMemo(()=>debounce(fetchResults,700),[]);
350+
},[]);
351+
352+
constdebouncedFetchResults=useMemo(
353+
()=>debounce((query:string)=>{
354+
setPage(1);
355+
fetchResults(query,1);
356+
},700),
357+
[fetchResults]
358+
);
330359

331360
constrowRenderer=useCallback(
332361
({ index, key, style}:ListRowProps)=>{
@@ -408,39 +437,41 @@ export const IconPicker = (props: {
408437
</IconRow>
409438
);
410439
},
411-
[columnNum,mediaPackSubscription,props.assetType,fetchDownloadUrl]
440+
[columnNum,mediaPackSubscription,props.assetType,fetchDownloadUrl,searchResults]
412441
);
413-
414442

415443
constpopupTitle=useMemo(()=>{
416444
if(props.assetType===AssetType.ILLUSTRATION)returntrans("iconScout.searchImage");
417445
if(props.assetType===AssetType.LOTTIE)returntrans("iconScout.searchAnimation");
418446
returntrans("iconScout.searchIcon");
419447
},[props.assetType]);
420448

421-
constMemoizedIconList=memo(({
422-
searchResults,
423-
rowRenderer,
424-
onScroll,
425-
columnNum,
449+
consthandleScroll=useCallback(({
450+
clientHeight,
451+
scrollHeight,
452+
scrollTop,
426453
}:{
427-
searchResults:any[];
428-
rowRenderer:(props:ListRowProps)=>React.ReactNode;
429-
onScroll:(params:{clientHeight:number;scrollHeight:number;scrollTop:number})=>void;
430-
columnNum:number;
454+
clientHeight:number;
455+
scrollHeight:number;
456+
scrollTop:number;
431457
})=>{
432-
return(
433-
<IconList
434-
width={550}
435-
height={400}
436-
rowHeight={140}
437-
rowCount={Math.ceil(searchResults.length/columnNum)}
438-
rowRenderer={rowRenderer}
439-
onScroll={onScroll}
440-
/>
441-
);
442-
});
443-
458+
if(hasMore&&!loading&&scrollHeight-scrollTop<=clientHeight+10){
459+
constnextPage=page+1;
460+
setPage(nextPage);
461+
fetchResults(searchText,nextPage);
462+
}
463+
},[hasMore,loading,page,searchText,fetchResults]);
464+
465+
constmemoizedIconListElement=useMemo(()=>(
466+
<IconList
467+
width={550}
468+
height={400}
469+
rowHeight={140}
470+
rowCount={Math.ceil(searchResults.length/columnNum)}
471+
rowRenderer={rowRenderer}
472+
onScroll={handleScroll}
473+
/>
474+
),[searchResults.length,rowRenderer,handleScroll,columnNum]);
444475

445476
return(
446477
<Popover
@@ -471,11 +502,6 @@ export const IconPicker = (props: {
471502
/>
472503
<StyledSearchIcon/>
473504
</SearchDiv>
474-
{loading&&(
475-
<Flexalign="center"justify="center"style={{flex:1}}>
476-
<Spinindicator={<LoadingOutlinedstyle={{fontSize:25}}spin/>}/>
477-
</Flex>
478-
)}
479505
<Spinspinning={downloading}indicator={<LoadingOutlinedstyle={{fontSize:25}}/>}>
480506
{!loading&&Boolean(searchText)&&!Boolean(searchResults?.length)&&(
481507
<Flexalign="center"justify="center"style={{flex:1}}>
@@ -484,33 +510,16 @@ export const IconPicker = (props: {
484510
</Typography.Text>
485511
</Flex>
486512
)}
487-
{!loading&&Boolean(searchText)&&Boolean(searchResults?.length)&&(
513+
{Boolean(searchText)&&Boolean(searchResults?.length)&&(
488514
<IconListWrapper>
489-
490-
<IconList
491-
width={550}
492-
height={400}
493-
rowHeight={140}
494-
rowCount={Math.ceil(searchResults.length/columnNum)}
495-
rowRenderer={rowRenderer}
496-
onScroll={({
497-
clientHeight,
498-
scrollHeight,
499-
scrollTop,
500-
}:{
501-
clientHeight:number;
502-
scrollHeight:number;
503-
scrollTop:number;
504-
})=>{
505-
if(hasMore&&!loading&&scrollHeight-scrollTop<=clientHeight+10){
506-
constnextPage=page+1;
507-
setPage(nextPage);
508-
fetchResults(searchText,nextPage);
509-
}
510-
}}
511-
/>
515+
{memoizedIconListElement}
512516
</IconListWrapper>
513517
)}
518+
{loading&&(
519+
<Flexalign="center"justify="center"style={{flex:1}}>
520+
<Spinindicator={<LoadingOutlinedstyle={{fontSize:25}}spin/>}/>
521+
</Flex>
522+
)}
514523
</Spin>
515524
</PopupContainer>
516525
</Draggable>
@@ -557,11 +566,12 @@ export function IconscoutControl(
557566
){
558567
returnclassIconscoutControlextendsSimpleComp<IconScoutAsset>{
559568
readonlyIGNORABLE_DEFAULT_VALUE=false;
569+
560570
protectedgetDefaultValue():IconScoutAsset{
561571
return{
562-
uuid:'',
563-
value:'',
564-
preview:'',
572+
uuid:"",
573+
value:"",
574+
preview:"",
565575
};
566576
}
567577

@@ -586,5 +596,5 @@ export function IconscoutControl(
586596
</ControlPropertyViewWrapper>
587597
);
588598
}
589-
}
599+
};
590600
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp