Skip to content

Commit a602426

Browse files
committed
Implemented pagination in Your App.
1 parent efa56c3 commit a602426

File tree

6 files changed

+154
-53
lines changed

6 files changed

+154
-53
lines changed

client/packages/lowcoder-design/src/components/Search.tsx

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,35 @@ interface ISearch {
6262
placeholder: string;
6363
value: string;
6464
onChange: (value: React.ChangeEvent<HTMLInputElement>) => void;
65+
onEnterPress?: (value: string) => void; // Added for capturing Enter key press
6566
disabled?: boolean;
6667
}
6768

6869
export const Search = (props: ISearch & InputProps) => {
69-
const { value, onChange, style, disabled, placeholder, ...others } = props;
70+
const { value, onChange, style, disabled, placeholder, onEnterPress, ...others } = props;
71+
7072
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
7173
onChange && onChange(e);
7274
};
75+
76+
// Handling Enter key press
77+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
78+
if (e.key === 'Enter' && onEnterPress) {
79+
onEnterPress(value);
80+
}
81+
};
82+
7383
return (
74-
<SearchDiv style={style}>
75-
<SearchInput
76-
disabled={disabled}
77-
placeholder={placeholder}
78-
onChange={handleChange}
79-
value={value}
80-
prefix={<SearchIcon />}
81-
{...others}
82-
/>
83-
</SearchDiv>
84+
<SearchDiv style={style}>
85+
<SearchInput
86+
disabled={disabled}
87+
placeholder={placeholder}
88+
onChange={handleChange}
89+
onKeyDown={handleKeyDown} // Listening for key down events
90+
value={value}
91+
prefix={<SearchIcon />}
92+
{...others}
93+
/>
94+
</SearchDiv>
8495
);
85-
};
96+
};

client/packages/lowcoder/src/api/apiResponses.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ export interface GenericApiResponse<T> {
1212
data: T;
1313
}
1414

15+
export interface GenericApiPaginationResponse<T> {
16+
total: number;
17+
success: boolean;
18+
code: number;
19+
message: string;
20+
data: T;
21+
}
22+
1523
export interface FetchGroupApiResponse<T> extends GenericApiResponse<T> {
1624
totalAdmins: number,
1725
totalAdminsAndDevelopers: number,

client/packages/lowcoder/src/api/folderApi.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import Api from "./api";
22
import { AxiosPromise } from "axios";
3-
import { GenericApiResponse } from "./apiResponses";
3+
import {GenericApiPaginationResponse, GenericApiResponse} from "./apiResponses";
44
import {
55
CreateFolderPayload,
66
DeleteFolderPayload,
7+
FetchFolderElementsPaginationPayload,
78
FetchFolderElementsPayload,
89
MoveToFolderPayload,
910
UpdateFolderPayload,
@@ -40,4 +41,10 @@ export class FolderApi extends Api {
4041
): AxiosPromise<GenericApiResponse<(ApplicationMeta | FolderMeta)[]>> {
4142
return Api.get(FolderApi.url + `/elements`, { id: request.folderId });
4243
}
44+
45+
static fetchFolderElementsPagination(
46+
request: FetchFolderElementsPaginationPayload
47+
): AxiosPromise<GenericApiPaginationResponse<(ApplicationMeta | FolderMeta)[]>> {
48+
return Api.get(FolderApi.url + `/elements`, { ...request });
49+
}
4350
}

client/packages/lowcoder/src/pages/ApplicationV2/HomeLayout.tsx

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ const EmptyView = styled.div`
203203
const PaginationLayout = styled.div`
204204
display: flex;
205205
justify-content: center;
206-
margin-top: 40px;
206+
margin-top: -20px;
207207
margin-bottom: 20px;
208208
`
209209

@@ -308,13 +308,39 @@ export interface HomeLayoutProps {
308308
localMarketplaceApps?: Array<ApplicationMeta>;
309309
globalMarketplaceApps?: Array<ApplicationMeta>;
310310
mode: HomeLayoutMode;
311+
setCurrentPage?: any;
312+
setPageSize?: any;
313+
currentPage?: number;
314+
pageSize?: number;
315+
total?: number;
316+
setSearchValues?: any;
317+
typeFilter?: number;
318+
setTypeFilter?: any;
311319
}
312320

313321
export function HomeLayout(props: HomeLayoutProps) {
322+
const { breadcrumb = [],
323+
elements = [],
324+
localMarketplaceApps = [],
325+
globalMarketplaceApps = [],
326+
mode ,
327+
setCurrentPage,
328+
setPageSize,
329+
pageSize,
330+
currentPage,
331+
setSearchValues,
332+
total,
333+
typeFilter,
334+
setTypeFilter,
335+
} = props;
336+
console.log("elements", elements, total);
337+
const handlePageChange = (page: number) => {
338+
setCurrentPage(page);
339+
};
314340

315-
const { breadcrumb = [], elements = [], localMarketplaceApps = [], globalMarketplaceApps = [], mode } = props;
316-
317-
console.log("folder", elements);
341+
const handlePageSizeChange = (current: number, size: number) => {
342+
setPageSize(size);
343+
};
318344

319345
const categoryOptions = [
320346
{ label: <FilterMenuItem>{trans("home.allCategories")}</FilterMenuItem>, value: 'All' },
@@ -331,10 +357,9 @@ export function HomeLayout(props: HomeLayoutProps) {
331357
const user = useSelector(getUser);
332358
const isFetching = useSelector(isFetchingFolderElements);
333359
const isSelfHost = window.location.host !== 'app.lowcoder.cloud';
334-
const [typeFilter, setTypeFilter] = useState<HomeResKey>("All");
335360
const [categoryFilter, setCategoryFilter] = useState<ApplicationCategoriesEnum | "All">("All");
336361
const [searchValue, setSearchValue] = useState("");
337-
const [visibility, setVisibility] = useState(true);
362+
const [visibility, setVisibility] = useState(mode !== "marketplace");
338363
const [layout, setLayout] = useState<HomeLayoutType>(
339364
checkIsMobile(window.innerWidth) ? "card" : getHomeLayout()
340365
);
@@ -352,7 +377,15 @@ export function HomeLayout(props: HomeLayoutProps) {
352377
return null;
353378
}
354379

355-
var displayElements = elements;
380+
var displayElements = elements.sort((a, b) => {
381+
if (a.folder && !b.folder) {
382+
return -1; // a is a folder and should come first
383+
} else if (!a.folder && b.folder) {
384+
return 1; // b is a folder and should come first
385+
} else {
386+
return 0; // both are folders or both are not, keep original order
387+
}
388+
});
356389

357390
if (mode === "marketplace" && isSelfHost) {
358391
const markedLocalApps = localMarketplaceApps.map(app => ({ ...app, isLocalMarketplace: true }));
@@ -364,27 +397,7 @@ export function HomeLayout(props: HomeLayoutProps) {
364397
const markedLocalApps = localMarketplaceApps.map(app => ({ ...app, isLocalMarketplace: true }));
365398
displayElements = [...markedLocalApps];
366399
}
367-
368400
const resList: HomeRes[] = displayElements
369-
.filter((e) =>
370-
searchValue
371-
? e.name?.toLocaleLowerCase().includes(searchValue?.toLocaleLowerCase()) ||
372-
e.createBy?.toLocaleLowerCase().includes(searchValue?.toLocaleLowerCase())
373-
: true
374-
)
375-
.filter((e) => {
376-
if (HomeResTypeEnum[typeFilter].valueOf() === HomeResTypeEnum.All) {
377-
return true;
378-
}
379-
if (e.folder) {
380-
return HomeResTypeEnum[typeFilter] === HomeResTypeEnum.Folder;
381-
} else {
382-
if (typeFilter === "Navigation") {
383-
return NavigationTypes.map((t) => t.valueOf()).includes(e.applicationType);
384-
}
385-
return HomeResTypeEnum[typeFilter].valueOf() === e.applicationType;
386-
}
387-
})
388401
.filter((e) => {
389402
// If "All" is selected, do not filter out any elements based on category
390403
if (categoryFilter === 'All' || !categoryFilter) {
@@ -425,7 +438,6 @@ export function HomeLayout(props: HomeLayoutProps) {
425438
}
426439
);
427440

428-
console.log(resList);
429441

430442
const getFilterMenuItem = (type: HomeResTypeEnum) => {
431443
const Icon = HomeResInfo[type].icon;
@@ -474,7 +486,7 @@ export function HomeLayout(props: HomeLayoutProps) {
474486

475487
{showNewUserGuide(user) && <HomepageTourV2 />}
476488

477-
<HomeView>
489+
<HomeView>
478490
<StyleHomeCover>
479491
<h1 style={{color: "#ffffff", marginTop : "12px"}}>
480492
{mode === "marketplace" && trans("home.appMarketplace")}
@@ -491,8 +503,11 @@ export function HomeLayout(props: HomeLayoutProps) {
491503
{mode !== "folders" && mode !== "module" && (
492504
<FilterDropdown
493505
variant="borderless"
494-
value={typeFilter}
495-
onChange={(value: any) => setTypeFilter(value as HomeResKey)}
506+
value={HomeResTypeEnum[typeFilter || 0]}
507+
onChange={(value: any) => {
508+
console.log(HomeResTypeEnum[value])
509+
setTypeFilter(HomeResTypeEnum[value])}
510+
}
496511
options={[
497512
getFilterMenuItem(HomeResTypeEnum.All),
498513
getFilterMenuItem(HomeResTypeEnum.Application),
@@ -519,6 +534,7 @@ export function HomeLayout(props: HomeLayoutProps) {
519534
placeholder={trans("search")}
520535
value={searchValue}
521536
onChange={(e) => setSearchValue(e.target.value)}
537+
onEnterPress={(value) => setSearchValues(value)}
522538
style={{ width: "192px", height: "32px", margin: "0" }}
523539
/>
524540
{mode !== "trash" && mode !== "marketplace" && user.orgDev && (
@@ -615,15 +631,21 @@ export function HomeLayout(props: HomeLayoutProps) {
615631
</>
616632
)}
617633
</ContentWrapper>
618-
{visibility ? <div>
619-
<Divider />
634+
{visibility && resList.length ? <div>
620635
<PaginationLayout>
621-
<Pagination total={50} showSizeChanger />
636+
<Pagination
637+
current={currentPage}
638+
pageSize={pageSize}
639+
onChange={handlePageChange}
640+
onShowSizeChange={handlePageSizeChange}
641+
total={total}
642+
showSizeChanger
643+
/>
622644
</PaginationLayout>
623645
</div> : null}
624646
</Card>
625647

626-
</HomeView>
648+
</HomeView>
627649

628650
</Wrapper>
629651
);

client/packages/lowcoder/src/pages/ApplicationV2/HomeView.tsx

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,50 @@
11
import { useSelector } from "react-redux";
22
import { HomeLayout } from "./HomeLayout";
33
import { getUser } from "../../redux/selectors/usersSelectors";
4-
import { folderElementsSelector } from "../../redux/selectors/folderSelector";
54
import { Helmet } from "react-helmet";
65
import { trans } from "i18n";
6+
import {useState, useEffect } from "react";
7+
import {fetchFolderElements} from "@lowcoder-ee/util/pagination/axios";
8+
import {ApplicationMeta, FolderMeta} from "@lowcoder-ee/constants/applicationConstants";
9+
import {ApplicationPaginationType} from "@lowcoder-ee/util/pagination/type";
10+
11+
interface ElementsState {
12+
elements: (ApplicationMeta | FolderMeta)[];
13+
total: number;
14+
}
715

816
export function HomeView() {
9-
const elements = useSelector(folderElementsSelector)[""];
17+
const [elements, setElements] = useState<ElementsState>({ elements: [], total: 1 });
18+
const [currentPage, setCurrentPage] = useState(1);
19+
const [pageSize, setPageSize] = useState(10);
20+
const [searchValues, setSearchValues] = useState("");
21+
const [typeFilter, setTypeFilter] = useState<number>(0);
22+
useEffect( () => {
23+
try{
24+
25+
fetchFolderElements({
26+
pageNum:currentPage,
27+
pageSize:pageSize,
28+
applicationType: ApplicationPaginationType[typeFilter],
29+
name: searchValues,
30+
}).then(
31+
data => {
32+
console.log(data)
33+
if (data.success) {
34+
setElements({elements: data.data || [], total: data.total || 1})
35+
}
36+
else
37+
console.error("ERROR: fetchFolderElements", data.error)
38+
}
39+
);
40+
} catch (error) {
41+
console.error('Failed to fetch data:', error);
42+
}
43+
}, [currentPage, pageSize, searchValues, typeFilter]
44+
);
45+
46+
console.log(currentPage, pageSize);
47+
1048
const user = useSelector(getUser);
1149

1250
if (!user.currentOrgId) {
@@ -16,9 +54,17 @@ export function HomeView() {
1654
return (
1755
<>
1856
<Helmet>{<title>{trans("productName")} {trans("home.home")}</title>}</Helmet>
19-
<HomeLayout
20-
elements={elements}
21-
mode={"view"}
57+
<HomeLayout
58+
elements={elements.elements}
59+
mode={"view"}
60+
currentPage ={currentPage}
61+
setCurrentPage={setCurrentPage}
62+
pageSize={pageSize}
63+
setPageSize={setPageSize}
64+
total={elements.total}
65+
setSearchValues={setSearchValues}
66+
typeFilter={typeFilter}
67+
setTypeFilter={setTypeFilter}
2268
/>
2369
</>
2470
);

client/packages/lowcoder/src/redux/reduxActions/folderActions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ export interface FetchFolderElementsPayload {
7878
folderId?: string;
7979
}
8080

81+
export interface FetchFolderElementsPaginationPayload {
82+
pageNum?: number;
83+
pageSize?: number;
84+
name?: string;
85+
applicationType?: string;
86+
}
87+
8188
export const fetchFolderElements = (
8289
payload: FetchFolderElementsPayload
8390
): ReduxAction<FetchFolderElementsPayload> => {

0 commit comments

Comments
 (0)