From 2d418644bbf175c1a42022067cf72b852af27778 Mon Sep 17 00:00:00 2001 From: berkay Date: Mon, 28 Apr 2025 13:19:01 +0300 Subject: [PATCH] updated pagination commit to carry --- Controllers/Postgres/pagination.py | 14 ++ .../application/PaginationToolsComponent.tsx | 155 ++++++++++-------- .../src/components/Pages/application/hooks.ts | 30 +++- .../src/components/Pages/application/page.tsx | 54 +++--- docker-compose.yml | 154 ++++++++--------- 5 files changed, 228 insertions(+), 179 deletions(-) diff --git a/Controllers/Postgres/pagination.py b/Controllers/Postgres/pagination.py index b75d60c..c334c5a 100644 --- a/Controllers/Postgres/pagination.py +++ b/Controllers/Postgres/pagination.py @@ -144,6 +144,18 @@ class Pagination: self.orderField = "uu_id" self.orderType = "asc" + @property + def next_available(self) -> bool: + if self.page < self.total_pages: + return True + return False + + @property + def back_available(self) -> bool: + if self.page > 1: + return True + return False + @property def as_dict(self) -> Dict[str, Any]: """Convert pagination state to dictionary format.""" @@ -157,6 +169,8 @@ class Pagination: "pageCount": self.page_count, "orderField": self.orderField, "orderType": self.orderType, + "next": self.next_available, + "back": self.back_available, } diff --git a/WebServices/management-frontend/src/components/Pages/application/PaginationToolsComponent.tsx b/WebServices/management-frontend/src/components/Pages/application/PaginationToolsComponent.tsx index ec2458d..0edcc58 100644 --- a/WebServices/management-frontend/src/components/Pages/application/PaginationToolsComponent.tsx +++ b/WebServices/management-frontend/src/components/Pages/application/PaginationToolsComponent.tsx @@ -1,7 +1,13 @@ "use client"; import React from "react"; import { Button } from "@/components/ui/button"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { PagePagination } from "./hooks"; import { getTranslation, LanguageKey } from "./language"; @@ -12,14 +18,11 @@ interface PaginationToolsComponentProps { lang: string; } -export const PaginationToolsComponent: React.FC = ({ - pagination, - updatePagination, - loading, - lang, -}) => { +export const PaginationToolsComponent: React.FC< + PaginationToolsComponentProps +> = ({ pagination, updatePagination, loading, lang }) => { const t = getTranslation(lang as LanguageKey); - + const handlePageChange = (newPage: number) => { if (newPage >= 1 && newPage <= pagination.totalPages) { updatePagination({ page: newPage }); @@ -32,20 +35,23 @@ export const PaginationToolsComponent: React.FC =
{t.showing}{" "} {/* Show the range based on filtered count when available */} - {(pagination.totalCount || pagination.allCount || 0) > 0 - ? (pagination.page - 1) * pagination.size + 1 + {(pagination.totalCount || pagination.allCount || 0) > 0 + ? (pagination.page - 1) * pagination.size + 1 : 0}{" "} - - {Math.min( - pagination.page * pagination.size, - pagination.totalCount || pagination.allCount || 0 - )} {t.of} {pagination.totalCount || pagination.allCount || 0}{" "} - {t.items} + -{" "} + {Math.min( + pagination.page * pagination.size, + pagination.totalCount || pagination.allCount || 0 + )}{" "} + {t.of} {pagination.totalCount || pagination.allCount || 0} {t.items}
- {pagination.totalCount && pagination.totalCount !== (pagination.allCount || 0) && ( -
- {t.total}: {pagination.allCount || 0} {t.items} ({t.filtered}: {pagination.totalCount} {t.items}) -
- )} + {pagination.totalCount && + pagination.totalCount !== (pagination.allCount || 0) && ( +
+ {t.total}: {pagination.allCount || 0} {t.items} ({t.filtered}:{" "} + {pagination.totalCount} {t.items}) +
+ )} {/* Navigation buttons - center */} @@ -54,70 +60,87 @@ export const PaginationToolsComponent: React.FC = variant="outline" size="sm" onClick={() => handlePageChange(pagination.page - 1)} - disabled={pagination.page <= 1 || loading} + disabled={pagination.next} > {t.previous} {/* Page number buttons */}
- {Array.from({ length: Math.min(5, Math.max(1, Math.ceil( - (pagination.totalCount && pagination.totalCount !== pagination.allCount - ? pagination.totalCount - : (pagination.allCount || 0)) / pagination.size - ))) }, (_, i) => { - // Show pages around current page - let pageNum; - const calculatedTotalPages = Math.max(1, Math.ceil( - (pagination.totalCount && pagination.totalCount !== pagination.allCount - ? pagination.totalCount - : (pagination.allCount || 0)) / pagination.size - )); - if (calculatedTotalPages <= 5) { - pageNum = i + 1; - } else if (pagination.page <= 3) { - pageNum = i + 1; - } else if (pagination.page >= calculatedTotalPages - 2) { - pageNum = calculatedTotalPages - 4 + i; - } else { - pageNum = pagination.page - 2 + i; - } + {Array.from( + { + length: Math.min( + 5, + Math.max( + 1, + Math.ceil( + (pagination.totalCount && + pagination.totalCount !== pagination.allCount + ? pagination.totalCount + : pagination.allCount || 0) / pagination.size + ) + ) + ), + }, + (_, i) => { + // Show pages around current page + let pageNum; + const calculatedTotalPages = Math.max( + 1, + Math.ceil( + (pagination.totalCount && + pagination.totalCount !== pagination.allCount + ? pagination.totalCount + : pagination.allCount || 0) / pagination.size + ) + ); + if (calculatedTotalPages <= 5) { + pageNum = i + 1; + } else if (pagination.page <= 3) { + pageNum = i + 1; + } else if (pagination.page >= calculatedTotalPages - 2) { + pageNum = calculatedTotalPages - 4 + i; + } else { + pageNum = pagination.page - 2 + i; + } - return ( - - ); - })} + return ( + + ); + } + )}
{/* Page text display */} - {t.page} {pagination.page} {t.of} {Math.max(1, Math.ceil( - (pagination.totalCount && pagination.totalCount !== pagination.allCount - ? pagination.totalCount - : (pagination.allCount || 0)) / pagination.size - ))} + {t.page} {pagination.page} {t.of}{" "} + {Math.max( + 1, + Math.ceil( + (pagination.totalCount && + pagination.totalCount !== pagination.allCount + ? pagination.totalCount + : pagination.allCount || 0) / pagination.size + ) + )} @@ -129,7 +152,7 @@ export const PaginationToolsComponent: React.FC = onValueChange={(value) => { updatePagination({ size: Number(value), - page: 1 // Reset to first page when changing page size + page: 1, // Reset to first page when changing page size }); }} > diff --git a/WebServices/management-frontend/src/components/Pages/application/hooks.ts b/WebServices/management-frontend/src/components/Pages/application/hooks.ts index 03914a2..7c4f67e 100644 --- a/WebServices/management-frontend/src/components/Pages/application/hooks.ts +++ b/WebServices/management-frontend/src/components/Pages/application/hooks.ts @@ -16,6 +16,8 @@ export interface ResponseMetadata { totalPages: number; pageCount: number; allCount?: number; + next: boolean; + back: boolean; } export interface PagePagination extends RequestParams, ResponseMetadata {} @@ -39,6 +41,8 @@ export function useApplicationData() { totalItems: 0, totalPages: 0, pageCount: 0, + next: true, + back: false, }); const [loading, setLoading] = useState(false); @@ -66,6 +70,8 @@ export function useApplicationData() { totalPages: result.pagination.totalPages || 1, pageCount: result.pagination.pageCount || 0, allCount: result.pagination.allCount || 0, + next: result.pagination.next || true, + back: result.pagination.back || false, }); } } @@ -96,23 +102,27 @@ export function useApplicationData() { // Transform query parameters to use __ilike with %value% format if (updates.query) { const transformedQuery: Record = {}; - + Object.entries(updates.query).forEach(([key, value]) => { // Only transform string values that aren't already using a special operator - if (typeof value === 'string' && !key.includes('__') && value.trim() !== '') { + if ( + typeof value === "string" && + !key.includes("__") && + value.trim() !== "" + ) { transformedQuery[`${key}__ilike`] = `%${value}%`; } else { transformedQuery[key] = value; } }); - + updates.query = transformedQuery; - + // Always reset to page 1 when search query changes - if (!updates.hasOwnProperty('page')) { + if (!updates.hasOwnProperty("page")) { updates.page = 1; } - + // Reset response metadata when search changes to avoid stale pagination data setResponseMetadata({ totalCount: 0, @@ -120,9 +130,11 @@ export function useApplicationData() { totalPages: 0, pageCount: 0, allCount: 0, + next: true, + back: false, }); } - + setRequestParams((prev) => ({ ...prev, ...updates, @@ -132,9 +144,9 @@ export function useApplicationData() { // Create a combined refetch function const refetch = useCallback(() => { // Reset pagination to page 1 when manually refetching - setRequestParams(prev => ({ + setRequestParams((prev) => ({ ...prev, - page: 1 + page: 1, })); fetchApplicationsFromApi(); }, [fetchApplicationsFromApi]); diff --git a/WebServices/management-frontend/src/components/Pages/application/page.tsx b/WebServices/management-frontend/src/components/Pages/application/page.tsx index 0528956..0cf5521 100644 --- a/WebServices/management-frontend/src/components/Pages/application/page.tsx +++ b/WebServices/management-frontend/src/components/Pages/application/page.tsx @@ -21,11 +21,11 @@ const ApplicationPage: React.FC = ({ lang = "en" }) => { null ); - // State for sorting - const [sortField, setSortField] = useState(null); - const [sortDirection, setSortDirection] = useState<"asc" | "desc" | null>( - null - ); + // // State for sorting + // const [sortField, setSortField] = useState(null); + // const [sortDirection, setSortDirection] = useState<"asc" | "desc" | null>( + // null + // ); // Available options for dropdowns const urlOptions = [ @@ -55,29 +55,29 @@ const ApplicationPage: React.FC = ({ lang = "en" }) => { }); }; - // Handle sorting - const handleSort = (field: string) => { - let direction: "asc" | "desc" | null = "asc"; + // // Handle sorting + // const handleSort = (field: string) => { + // let direction: "asc" | "desc" | null = "asc"; - if (sortField === field) { - // Toggle direction if same field is clicked - if (sortDirection === "asc") { - direction = "desc"; - } else if (sortDirection === "desc") { - // Clear sorting if already desc - field = ""; - direction = null; - } - } + // if (sortField === field) { + // // Toggle direction if same field is clicked + // if (sortDirection === "asc") { + // direction = "desc"; + // } else if (sortDirection === "desc") { + // // Clear sorting if already desc + // field = ""; + // direction = null; + // } + // } - setSortField(field || null); - setSortDirection(direction); + // setSortField(field || null); + // setSortDirection(direction); - updatePagination({ - orderField: field ? [field] : [], - orderType: direction ? [direction] : [], - }); - }; + // updatePagination({ + // orderField: field ? [field] : [], + // orderType: direction ? [direction] : [], + // }); + // }; return (
@@ -99,14 +99,14 @@ const ApplicationPage: React.FC = ({ lang = "en" }) => { lang={lang} /> - {/* Sorting Component */} + {/* Sorting Component + /> */} {/* Data Display Component */}
diff --git a/docker-compose.yml b/docker-compose.yml index e6175af..48e9b09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,17 @@ services: - client_frontend: - container_name: client_frontend - build: - context: . - dockerfile: WebServices/client-frontend/Dockerfile - networks: - - wag-services - ports: - - "3000:3000" - environment: - - NODE_ENV=development - cpus: 1 - mem_limit: 2048m + # client_frontend: + # container_name: client_frontend + # build: + # context: . + # dockerfile: WebServices/client-frontend/Dockerfile + # networks: + # - wag-services + # ports: + # - "3000:3000" + # environment: + # - NODE_ENV=development + # cpus: 1 + # mem_limit: 2048m # volumes: # - client-frontend:/WebServices/client-frontend @@ -26,7 +26,7 @@ services: - "3001:3001" environment: - NODE_ENV=development - cpus: 1 + cpus: 2 mem_limit: 2048m auth_service: @@ -56,59 +56,59 @@ services: mem_limit: 512m cpus: 0.5 - identity_service: - container_name: identity_service - build: - context: . - dockerfile: ApiServices/IdentityService/Dockerfile - networks: - - wag-services - depends_on: - - initializer_service - env_file: - - api_env.env - environment: - - API_PATH=app:app - - API_HOST=0.0.0.0 - - API_PORT=8002 - - API_LOG_LEVEL=info - - API_RELOAD=1 - - API_APP_NAME=evyos-identity-api-gateway - - API_TITLE=WAG API Identity Api Gateway - - API_FORGOT_LINK=https://identity_service/forgot-password - - API_DESCRIPTION=This api is serves as web identity api gateway only to evyos web services. - - API_APP_URL=https://identity_service - ports: - - "8002:8002" - mem_limit: 512m - cpus: 0.5 + # identity_service: + # container_name: identity_service + # build: + # context: . + # dockerfile: ApiServices/IdentityService/Dockerfile + # networks: + # - wag-services + # depends_on: + # - initializer_service + # env_file: + # - api_env.env + # environment: + # - API_PATH=app:app + # - API_HOST=0.0.0.0 + # - API_PORT=8002 + # - API_LOG_LEVEL=info + # - API_RELOAD=1 + # - API_APP_NAME=evyos-identity-api-gateway + # - API_TITLE=WAG API Identity Api Gateway + # - API_FORGOT_LINK=https://identity_service/forgot-password + # - API_DESCRIPTION=This api is serves as web identity api gateway only to evyos web services. + # - API_APP_URL=https://identity_service + # ports: + # - "8002:8002" + # mem_limit: 512m + # cpus: 0.5 - building_service: - container_name: building_service - build: - context: . - dockerfile: ApiServices/BuildingService/Dockerfile - networks: - - wag-services - env_file: - - api_env.env - depends_on: - - initializer_service - environment: - - API_PATH=app:app - - API_HOST=0.0.0.0 - - API_PORT=8003 - - API_LOG_LEVEL=info - - API_RELOAD=1 - - API_APP_NAME=evyos-building-api-gateway - - API_TITLE=WAG API Building Api Gateway - - API_FORGOT_LINK=https://building_service/forgot-password - - API_DESCRIPTION=This api is serves as web building api gateway only to evyos web services. - - API_APP_URL=https://building_service - ports: - - "8003:8003" - mem_limit: 512m - cpus: 0.5 + # building_service: + # container_name: building_service + # build: + # context: . + # dockerfile: ApiServices/BuildingService/Dockerfile + # networks: + # - wag-services + # env_file: + # - api_env.env + # depends_on: + # - initializer_service + # environment: + # - API_PATH=app:app + # - API_HOST=0.0.0.0 + # - API_PORT=8003 + # - API_LOG_LEVEL=info + # - API_RELOAD=1 + # - API_APP_NAME=evyos-building-api-gateway + # - API_TITLE=WAG API Building Api Gateway + # - API_FORGOT_LINK=https://building_service/forgot-password + # - API_DESCRIPTION=This api is serves as web building api gateway only to evyos web services. + # - API_APP_URL=https://building_service + # ports: + # - "8003:8003" + # mem_limit: 512m + # cpus: 0.5 management_service: container_name: management_service @@ -151,17 +151,17 @@ services: mem_limit: 512m cpus: 0.5 - dealer_service: - container_name: dealer_service - build: - context: . - dockerfile: ApiServices/DealerService/Dockerfile - networks: - - wag-services - env_file: - - api_env.env - mem_limit: 512m - cpus: 0.5 + # dealer_service: + # container_name: dealer_service + # build: + # context: . + # dockerfile: ApiServices/DealerService/Dockerfile + # networks: + # - wag-services + # env_file: + # - api_env.env + # mem_limit: 512m + # cpus: 0.5 networks: wag-services: