|
19 | 19 | let platformsError = $state<string | null>(null);
|
20 | 20 | let mappedData = $state<any[]>([]);
|
21 | 21 |
|
| 22 | + // Pagination for eVaults |
| 23 | + let currentPage = $state(1); |
| 24 | + let itemsPerPage = $state(10); |
| 25 | + let totalPages = $state(1); |
| 26 | +
|
22 | 27 | // Track selected items
|
23 | 28 | let selectedEVaults = $state<number[]>([]);
|
24 | 29 | let selectedPlatforms = $state<number[]>([]);
|
25 | 30 |
|
26 |
| - const mappedPlatformsData = $derived( |
27 |
| - platforms.map((platform) => ({ |
| 31 | + // Filtered data for search |
| 32 | + let filteredEVaults = $derived(() => { |
| 33 | + if (!evaultsSearchValue.trim()) return evaults; |
| 34 | + return evaults.filter( |
| 35 | + (evault) => |
| 36 | + evault.name.toLowerCase().includes(evaultsSearchValue.toLowerCase()) || |
| 37 | + evault.evaultId.toLowerCase().includes(evaultsSearchValue.toLowerCase()) || |
| 38 | + evault.namespace.toLowerCase().includes(evaultsSearchValue.toLowerCase()) |
| 39 | + ); |
| 40 | + }); |
| 41 | +
|
| 42 | + let filteredPlatforms = $derived(() => { |
| 43 | + if (!platformsSearchQuery.trim()) return platforms; |
| 44 | + return platforms.filter( |
| 45 | + (platform) => |
| 46 | + platform.name.toLowerCase().includes(platformsSearchQuery.toLowerCase()) || |
| 47 | + platform.status.toLowerCase().includes(platformsSearchQuery.toLowerCase()) |
| 48 | + ); |
| 49 | + }); |
| 50 | +
|
| 51 | + // Paginated eVaults |
| 52 | + let paginatedEVaults = $derived(() => { |
| 53 | + const startIndex = (currentPage - 1) * itemsPerPage; |
| 54 | + const endIndex = startIndex + itemsPerPage; |
| 55 | + const filtered = filteredEVaults(); |
| 56 | + return filtered.slice(startIndex, endIndex); |
| 57 | + }); |
| 58 | +
|
| 59 | + // Update total pages when filtered data changes |
| 60 | + $effect(() => { |
| 61 | + const filtered = filteredEVaults(); |
| 62 | + totalPages = Math.ceil(filtered.length / itemsPerPage); |
| 63 | + if (currentPage > totalPages && totalPages > 0) { |
| 64 | + currentPage = totalPages; |
| 65 | + } |
| 66 | + }); |
| 67 | +
|
| 68 | + // Mapped data for eVaults table |
| 69 | + let mappedEVaultsData = $derived(() => { |
| 70 | + const paginated = paginatedEVaults(); |
| 71 | + return paginated.map((evault) => ({ |
| 72 | + eName: { |
| 73 | + type: 'text', |
| 74 | + value: evault.evaultId, |
| 75 | + className: 'cursor-pointer text-blue-600 hover:text-blue-800 hover:underline' |
| 76 | + }, |
| 77 | + Uptime: { |
| 78 | + type: 'text', |
| 79 | + value: evault.age |
| 80 | + }, |
| 81 | + IP: { |
| 82 | + type: 'text', |
| 83 | + value: evault.ip |
| 84 | + }, |
| 85 | + URI: { |
| 86 | + type: 'link', |
| 87 | + value: evault.serviceUrl || 'N/A', |
| 88 | + link: evault.serviceUrl || '#', |
| 89 | + external: true |
| 90 | + } |
| 91 | + })); |
| 92 | + }); |
| 93 | +
|
| 94 | + const mappedPlatformsData = $derived(() => { |
| 95 | + const filtered = filteredPlatforms(); |
| 96 | + return filtered.map((platform) => ({ |
28 | 97 | Name: {
|
29 | 98 | type: 'text',
|
30 | 99 | value: platform.name
|
|
43 | 112 | link: platform.url,
|
44 | 113 | external: true
|
45 | 114 | }
|
46 |
| - })) |
47 |
| - ); |
| 115 | + })); |
| 116 | + }); |
48 | 117 |
|
49 | 118 | const handlePreviousPage = async () => {
|
50 |
| - alert('Previous btn clicked. Make a call to your server to fetch data.'); |
| 119 | + if (currentPage > 1) { |
| 120 | + currentPage--; |
| 121 | + } |
51 | 122 | };
|
52 | 123 |
|
53 | 124 | const handleNextPage = async () => {
|
54 |
| - alert('Next btn clicked. Make a call to your server to fetch data.'); |
| 125 | + if (currentPage < totalPages) { |
| 126 | + currentPage++; |
| 127 | + } |
55 | 128 | };
|
56 | 129 |
|
57 | 130 | const tableHeadings = ['eName', 'Uptime', 'IP', 'URI'];
|
|
249 | 322 | });
|
250 | 323 | </script>
|
251 | 324 |
|
252 |
| -<section class="flex flex-col gap-7"> |
253 |
| - <TableCard> |
254 |
| - <TableCardHeader |
255 |
| - title="eVaults" |
256 |
| - placeholder="Search eVaults" |
257 |
| - bind:searchValue={evaultsSearchValue} |
258 |
| - rightTitle={selectedEVaults.length > 0 |
259 |
| - ? `${selectedEVaults.length} eVault${selectedEVaults.length === 1 ? '' : 's'} selected` |
260 |
| - : 'Monitoring all eVault pods across Kubernetes clusters'} |
261 |
| - showClearSelection={selectedEVaults.length > 0} |
262 |
| - onClearSelection={clearEVaultSelection} |
263 |
| - /> |
264 |
| - |
265 |
| - {#if isLoading} |
266 |
| - <div class="flex justify-center py-8"> |
267 |
| - <div class="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div> |
268 |
| - </div> |
269 |
| - {:else if error} |
270 |
| - <div class="py-8 text-center text-red-500"> |
271 |
| - {error} |
272 |
| - <button |
273 |
| - onclick={fetchEVaults} |
274 |
| - class="ml-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700" |
275 |
| - > |
276 |
| - Retry |
277 |
| - </button> |
278 |
| - </div> |
279 |
| - {:else if evaults.length === 0} |
280 |
| - <div class="py-8 text-center text-gray-500"> |
281 |
| - No eVault pods found. Make sure kubectl is configured and eVault pods are running. |
282 |
| - </div> |
283 |
| - {:else} |
284 |
| - <Table |
285 |
| - class="mb-7" |
286 |
| - tableData={mappedData} |
287 |
| - withSelection={true} |
288 |
| - {handlePreviousPage} |
289 |
| - {handleNextPage} |
290 |
| - handleSelectedRow={handleEVaultRowClick} |
291 |
| - onSelectionChange={handleEVaultSelectionChange} |
292 |
| - onSelectAllChange={handleSelectAllEVaults} |
293 |
| - selectedIndices={selectedEVaults} |
| 325 | +<section class="flex gap-7"> |
| 326 | + <!-- Left Column: eVaults --> |
| 327 | + <div class="flex-1"> |
| 328 | + <TableCard> |
| 329 | + <TableCardHeader |
| 330 | + title="eVaults" |
| 331 | + placeholder="Search eVaults" |
| 332 | + bind:searchValue={evaultsSearchValue} |
| 333 | + rightTitle={selectedEVaults.length > 0 |
| 334 | + ? `${selectedEVaults.length} eVault${selectedEVaults.length === 1 ? '' : 's'} selected` |
| 335 | + : 'Monitoring all eVault pods across Kubernetes clusters'} |
| 336 | + showClearSelection={selectedEVaults.length > 0} |
| 337 | + onClearSelection={clearEVaultSelection} |
294 | 338 | />
|
295 |
| - {/if} |
296 |
| - </TableCard> |
297 |
| - |
298 |
| - <TableCard> |
299 |
| - <TableCardHeader |
300 |
| - title="Platforms" |
301 |
| - placeholder="Search Platforms" |
302 |
| - bind:searchValue={platformsSearchQuery} |
303 |
| - rightTitle={selectedPlatforms.length > 0 |
304 |
| - ? `${selectedPlatforms.length} platform${selectedPlatforms.length === 1 ? '' : 's'} selected` |
305 |
| - : 'No platform selected. Select a platform to monitor logs'} |
306 |
| - showClearSelection={selectedPlatforms.length > 0} |
307 |
| - onClearSelection={clearPlatformSelection} |
308 |
| - /> |
309 |
| - {#if platformsLoading} |
310 |
| - <div class="flex justify-center py-8"> |
311 |
| - <div class="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div> |
312 |
| - </div> |
313 |
| - {:else if platformsError} |
314 |
| - <div class="py-8 text-center text-red-500"> |
315 |
| - {platformsError} |
316 |
| - <button |
317 |
| - onclick={fetchPlatforms} |
318 |
| - class="ml-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700" |
319 |
| - > |
320 |
| - Retry |
321 |
| - </button> |
322 |
| - </div> |
323 |
| - {:else if platforms.length === 0} |
324 |
| - <div class="py-8 text-center text-gray-500"> |
325 |
| - No platforms found. Make sure the registry service is running. |
326 |
| - </div> |
327 |
| - {:else} |
328 |
| - <Table |
329 |
| - class="mb-7" |
330 |
| - tableData={mappedPlatformsData} |
331 |
| - withSelection={true} |
332 |
| - {handlePreviousPage} |
333 |
| - {handleNextPage} |
334 |
| - onSelectionChange={handlePlatformSelectionChange} |
335 |
| - onSelectAllChange={handleSelectAllPlatforms} |
336 |
| - selectedIndices={selectedPlatforms} |
| 339 | + |
| 340 | + {#if isLoading} |
| 341 | + <div class="flex justify-center py-8"> |
| 342 | + <div class="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div> |
| 343 | + </div> |
| 344 | + {:else if error} |
| 345 | + <div class="py-8 text-center text-red-500"> |
| 346 | + {error} |
| 347 | + <button |
| 348 | + onclick={fetchEVaults} |
| 349 | + class="ml-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700" |
| 350 | + > |
| 351 | + Retry |
| 352 | + </button> |
| 353 | + </div> |
| 354 | + {:else if evaults.length === 0} |
| 355 | + <div class="py-8 text-center text-gray-500"> |
| 356 | + No eVault pods found. Make sure kubectl is configured and eVault pods are |
| 357 | + running. |
| 358 | + </div> |
| 359 | + {:else} |
| 360 | + <Table |
| 361 | + class="mb-4" |
| 362 | + tableData={mappedEVaultsData} |
| 363 | + withSelection={true} |
| 364 | + {handlePreviousPage} |
| 365 | + {handleNextPage} |
| 366 | + handleSelectedRow={handleEVaultRowClick} |
| 367 | + onSelectionChange={handleEVaultSelectionChange} |
| 368 | + onSelectAllChange={handleSelectAllEVaults} |
| 369 | + selectedIndices={selectedEVaults} |
| 370 | + /> |
| 371 | + |
| 372 | + <!-- Pagination Info --> |
| 373 | + <div class="mb-4 flex items-center justify-between text-sm text-gray-600"> |
| 374 | + <div> |
| 375 | + Showing {(currentPage - 1) * itemsPerPage + 1} - {Math.min( |
| 376 | + currentPage * itemsPerPage, |
| 377 | + filteredEVaults().length |
| 378 | + )} of {filteredEVaults().length} eVaults |
| 379 | + </div> |
| 380 | + <div class="flex gap-2"> |
| 381 | + <button |
| 382 | + onclick={handlePreviousPage} |
| 383 | + disabled={currentPage <= 1} |
| 384 | + class="rounded border px-3 py-1 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50" |
| 385 | + > |
| 386 | + Previous |
| 387 | + </button> |
| 388 | + <span class="px-3 py-1">Page {currentPage} of {totalPages}</span> |
| 389 | + <button |
| 390 | + onclick={handleNextPage} |
| 391 | + disabled={currentPage >= totalPages} |
| 392 | + class="rounded border px-3 py-1 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50" |
| 393 | + > |
| 394 | + Next |
| 395 | + </button> |
| 396 | + </div> |
| 397 | + </div> |
| 398 | + {/if} |
| 399 | + </TableCard> |
| 400 | + </div> |
| 401 | + |
| 402 | + <!-- Right Column: Platforms --> |
| 403 | + <div class="flex-1"> |
| 404 | + <TableCard> |
| 405 | + <TableCardHeader |
| 406 | + title="Platforms" |
| 407 | + placeholder="Search Platforms" |
| 408 | + bind:searchValue={platformsSearchQuery} |
| 409 | + rightTitle={selectedPlatforms.length > 0 |
| 410 | + ? `${selectedPlatforms.length} platform${selectedPlatforms.length === 1 ? '' : 's'} selected` |
| 411 | + : 'No platform selected. Select a platform to monitor logs'} |
| 412 | + showClearSelection={selectedPlatforms.length > 0} |
| 413 | + onClearSelection={clearPlatformSelection} |
337 | 414 | />
|
338 |
| - {/if} |
339 |
| - </TableCard> |
| 415 | + {#if platformsLoading} |
| 416 | + <div class="flex justify-center py-8"> |
| 417 | + <div class="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div> |
| 418 | + </div> |
| 419 | + {:else if platformsError} |
| 420 | + <div class="py-8 text-center text-red-500"> |
| 421 | + {platformsError} |
| 422 | + <button |
| 423 | + onclick={fetchPlatforms} |
| 424 | + class="ml-4 rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700" |
| 425 | + > |
| 426 | + Retry |
| 427 | + </button> |
| 428 | + </div> |
| 429 | + {:else if platforms.length === 0} |
| 430 | + <div class="py-8 text-center text-gray-500"> |
| 431 | + No platforms found. Make sure the registry service is running. |
| 432 | + </div> |
| 433 | + {:else} |
| 434 | + <Table |
| 435 | + class="mb-4" |
| 436 | + tableData={mappedPlatformsData} |
| 437 | + withSelection={true} |
| 438 | + onSelectionChange={handlePlatformSelectionChange} |
| 439 | + onSelectAllChange={handleSelectAllPlatforms} |
| 440 | + selectedIndices={selectedPlatforms} |
| 441 | + /> |
| 442 | + {/if} |
| 443 | + </TableCard> |
| 444 | + </div> |
340 | 445 | </section>
|
0 commit comments