diff --git a/app/templates/admin/imports.html b/app/templates/admin/imports.html index 3fd0ee2b..691f20d6 100644 --- a/app/templates/admin/imports.html +++ b/app/templates/admin/imports.html @@ -1,5 +1,6 @@ {# app/templates/admin/imports.html #} {% extends "admin/base.html" %} +{% from 'shared/macros/pagination.html' import pagination %} {% block title %}Import Jobs - Platform Monitoring{% endblock %} @@ -289,33 +290,7 @@ - {# noqa: FE-001 - Custom pagination with page/limit/totalJobs variables #} - -
-
-
- Showing to - of - jobs -
-
- - -
-
-
+ {{ pagination(show_condition="!loading && pagination.total > 0") }} diff --git a/app/templates/admin/logs.html b/app/templates/admin/logs.html index 9ba8fa9c..43d1208c 100644 --- a/app/templates/admin/logs.html +++ b/app/templates/admin/logs.html @@ -1,5 +1,6 @@ {# app/templates/admin/logs.html #} {% extends "admin/base.html" %} +{% from 'shared/macros/pagination.html' import pagination %} {% block title %}Application Logs{% endblock %} @@ -236,31 +237,7 @@ - {# noqa: FE-001 - Custom pagination with filters.skip/limit/totalLogs variables #} - -
-
-
- Showing to of -
-
- - -
-
-
+ {{ pagination(show_condition="!loading && logs.length > 0") }} diff --git a/app/templates/admin/marketplace.html b/app/templates/admin/marketplace.html index f3514fb2..e41d1043 100644 --- a/app/templates/admin/marketplace.html +++ b/app/templates/admin/marketplace.html @@ -1,5 +1,6 @@ {# app/templates/admin/marketplace.html #} {% extends "admin/base.html" %} +{% from 'shared/macros/pagination.html' import pagination %} {% block title %}Marketplace Import{% endblock %} @@ -370,33 +371,7 @@ - {# noqa: FE-001 - Custom pagination with page/limit/totalJobs variables #} - -
-
-
- Showing to - of - jobs -
-
- - -
-
-
+ {{ pagination(show_condition="!loading && pagination.total > 0") }} diff --git a/static/admin/js/imports.js b/static/admin/js/imports.js index a7ead3a8..500e0d6e 100644 --- a/static/admin/js/imports.js +++ b/static/admin/js/imports.js @@ -43,9 +43,12 @@ function adminImports() { // Import jobs jobs: [], - totalJobs: 0, - page: 1, - limit: 20, + pagination: { + page: 1, + per_page: 20, + total: 0, + pages: 0 + }, // Modal state showJobModal: false, @@ -54,6 +57,51 @@ function adminImports() { // Auto-refresh for active jobs autoRefreshInterval: null, + // Computed: Total pages + get totalPages() { + return this.pagination.pages; + }, + + // Computed: Start index for pagination display + get startIndex() { + if (this.pagination.total === 0) return 0; + return (this.pagination.page - 1) * this.pagination.per_page + 1; + }, + + // Computed: End index for pagination display + get endIndex() { + const end = this.pagination.page * this.pagination.per_page; + return end > this.pagination.total ? this.pagination.total : end; + }, + + // Computed: Page numbers for pagination + get pageNumbers() { + const pages = []; + const totalPages = this.totalPages; + const current = this.pagination.page; + + if (totalPages <= 7) { + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + pages.push(1); + if (current > 3) { + pages.push('...'); + } + const start = Math.max(2, current - 1); + const end = Math.min(totalPages - 1, current + 1); + for (let i = start; i <= end; i++) { + pages.push(i); + } + if (current < totalPages - 2) { + pages.push('...'); + } + pages.push(totalPages); + } + return pages; + }, + async init() { // Guard against multiple initialization if (window._adminImportsInitialized) { @@ -117,8 +165,8 @@ function adminImports() { try { // Build query params const params = new URLSearchParams({ - page: this.page, - limit: this.limit + skip: (this.pagination.page - 1) * this.pagination.per_page, + limit: this.pagination.per_page }); // Add filters @@ -140,7 +188,8 @@ function adminImports() { ); this.jobs = response.items || []; - this.totalJobs = response.total || 0; + this.pagination.total = response.total || 0; + this.pagination.pages = Math.ceil(this.pagination.total / this.pagination.per_page); adminImportsLog.debug('Loaded all jobs:', this.jobs.length); } catch (error) { @@ -155,7 +204,7 @@ function adminImports() { * Apply filters and reload */ async applyFilters() { - this.page = 1; // Reset to first page when filtering + this.pagination.page = 1; // Reset to first page when filtering await this.loadJobs(); await this.loadStats(); // Update stats based on filters }, @@ -168,7 +217,7 @@ function adminImports() { this.filters.status = ''; this.filters.marketplace = ''; this.filters.created_by = ''; - this.page = 1; + this.pagination.page = 1; await this.loadJobs(); await this.loadStats(); }, @@ -239,20 +288,30 @@ function adminImports() { /** * Pagination: Previous page */ - async previousPage() { - if (this.page > 1) { - this.page--; - await this.loadJobs(); + previousPage() { + if (this.pagination.page > 1) { + this.pagination.page--; + this.loadJobs(); } }, /** * Pagination: Next page */ - async nextPage() { - if (this.page * this.limit < this.totalJobs) { - this.page++; - await this.loadJobs(); + nextPage() { + if (this.pagination.page < this.totalPages) { + this.pagination.page++; + this.loadJobs(); + } + }, + + /** + * Pagination: Go to specific page + */ + goToPage(pageNum) { + if (pageNum !== '...' && pageNum >= 1 && pageNum <= this.totalPages) { + this.pagination.page = pageNum; + this.loadJobs(); } }, diff --git a/static/admin/js/logs.js b/static/admin/js/logs.js index ac142e01..4f811105 100644 --- a/static/admin/js/logs.js +++ b/static/admin/js/logs.js @@ -17,7 +17,6 @@ function adminLogs() { successMessage: null, logSource: 'database', logs: [], - totalLogs: 0, stats: { total_count: 0, warning_count: 0, @@ -28,14 +27,63 @@ function adminLogs() { filters: { level: '', module: '', - search: '', - skip: 0, - limit: 50 + search: '' + }, + pagination: { + page: 1, + per_page: 50, + total: 0, + pages: 0 }, logFiles: [], selectedFile: '', fileContent: null, + // Computed: Total pages + get totalPages() { + return this.pagination.pages; + }, + + // Computed: Start index for pagination display + get startIndex() { + if (this.pagination.total === 0) return 0; + return (this.pagination.page - 1) * this.pagination.per_page + 1; + }, + + // Computed: End index for pagination display + get endIndex() { + const end = this.pagination.page * this.pagination.per_page; + return end > this.pagination.total ? this.pagination.total : end; + }, + + // Computed: Page numbers for pagination + get pageNumbers() { + const pages = []; + const totalPages = this.totalPages; + const current = this.pagination.page; + + if (totalPages <= 7) { + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + pages.push(1); + if (current > 3) { + pages.push('...'); + } + const start = Math.max(2, current - 1); + const end = Math.min(totalPages - 1, current + 1); + for (let i = start; i <= end; i++) { + pages.push(i); + } + if (current < totalPages - 2) { + pages.push('...'); + } + pages.push(totalPages); + } + return pages; + }, + async init() { logsLog.info('=== LOGS PAGE INITIALIZING ==='); await this.loadStats(); @@ -72,13 +120,14 @@ function adminLogs() { if (this.filters.level) params.append('level', this.filters.level); if (this.filters.module) params.append('module', this.filters.module); if (this.filters.search) params.append('search', this.filters.search); - params.append('skip', this.filters.skip); - params.append('limit', this.filters.limit); + params.append('skip', (this.pagination.page - 1) * this.pagination.per_page); + params.append('limit', this.pagination.per_page); const data = await apiClient.get(`/admin/logs/database?${params}`); this.logs = data.logs; - this.totalLogs = data.total; - logsLog.info(`Loaded ${this.logs.length} logs (total: ${this.totalLogs})`); + this.pagination.total = data.total; + this.pagination.pages = Math.ceil(this.pagination.total / this.pagination.per_page); + logsLog.info(`Loaded ${this.logs.length} logs (total: ${this.pagination.total})`); } catch (error) { logsLog.error('Failed to load logs:', error); this.error = error.response?.data?.detail || 'Failed to load logs'; @@ -143,21 +192,31 @@ function adminLogs() { this.filters = { level: '', module: '', - search: '', - skip: 0, - limit: 50 + search: '' }; - this.loadLogs(); - }, - - nextPage() { - this.filters.skip += this.filters.limit; + this.pagination.page = 1; this.loadLogs(); }, previousPage() { - this.filters.skip = Math.max(0, this.filters.skip - this.filters.limit); - this.loadLogs(); + if (this.pagination.page > 1) { + this.pagination.page--; + this.loadLogs(); + } + }, + + nextPage() { + if (this.pagination.page < this.totalPages) { + this.pagination.page++; + this.loadLogs(); + } + }, + + goToPage(pageNum) { + if (pageNum !== '...' && pageNum >= 1 && pageNum <= this.totalPages) { + this.pagination.page = pageNum; + this.loadLogs(); + } }, showLogDetail(log) { diff --git a/static/admin/js/marketplace.js b/static/admin/js/marketplace.js index 4758d12f..8c14fe06 100644 --- a/static/admin/js/marketplace.js +++ b/static/admin/js/marketplace.js @@ -46,9 +46,12 @@ function adminMarketplace() { // Import jobs jobs: [], - totalJobs: 0, - page: 1, - limit: 10, + pagination: { + page: 1, + per_page: 10, + total: 0, + pages: 0 + }, // Modal state showJobModal: false, @@ -57,6 +60,51 @@ function adminMarketplace() { // Auto-refresh for active jobs autoRefreshInterval: null, + // Computed: Total pages + get totalPages() { + return this.pagination.pages; + }, + + // Computed: Start index for pagination display + get startIndex() { + if (this.pagination.total === 0) return 0; + return (this.pagination.page - 1) * this.pagination.per_page + 1; + }, + + // Computed: End index for pagination display + get endIndex() { + const end = this.pagination.page * this.pagination.per_page; + return end > this.pagination.total ? this.pagination.total : end; + }, + + // Computed: Page numbers for pagination + get pageNumbers() { + const pages = []; + const totalPages = this.totalPages; + const current = this.pagination.page; + + if (totalPages <= 7) { + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + pages.push(1); + if (current > 3) { + pages.push('...'); + } + const start = Math.max(2, current - 1); + const end = Math.min(totalPages - 1, current + 1); + for (let i = start; i <= end; i++) { + pages.push(i); + } + if (current < totalPages - 2) { + pages.push('...'); + } + pages.push(totalPages); + } + return pages; + }, + async init() { adminMarketplaceLog.info('Marketplace init() called'); @@ -156,8 +204,8 @@ function adminMarketplace() { try { // Build query params const params = new URLSearchParams({ - page: this.page, - limit: this.limit, + skip: (this.pagination.page - 1) * this.pagination.per_page, + limit: this.pagination.per_page, created_by_me: 'true' // ✅ Only show jobs I triggered }); @@ -177,7 +225,8 @@ function adminMarketplace() { ); this.jobs = response.items || []; - this.totalJobs = response.total || 0; + this.pagination.total = response.total || 0; + this.pagination.pages = Math.ceil(this.pagination.total / this.pagination.per_page); adminMarketplaceLog.info('Loaded my jobs:', this.jobs.length); } catch (error) { @@ -267,7 +316,7 @@ function adminMarketplace() { this.filters.vendor_id = ''; this.filters.status = ''; this.filters.marketplace = ''; - this.page = 1; + this.pagination.page = 1; this.loadJobs(); }, @@ -336,20 +385,30 @@ function adminMarketplace() { /** * Pagination: Previous page */ - async previousPage() { - if (this.page > 1) { - this.page--; - await this.loadJobs(); + previousPage() { + if (this.pagination.page > 1) { + this.pagination.page--; + this.loadJobs(); } }, /** * Pagination: Next page */ - async nextPage() { - if (this.page * this.limit < this.totalJobs) { - this.page++; - await this.loadJobs(); + nextPage() { + if (this.pagination.page < this.totalPages) { + this.pagination.page++; + this.loadJobs(); + } + }, + + /** + * Pagination: Go to specific page + */ + goToPage(pageNum) { + if (pageNum !== '...' && pageNum >= 1 && pageNum <= this.totalPages) { + this.pagination.page = pageNum; + this.loadJobs(); } },