From 29c12d6a3cf65ae13df53ee50568ef776d392389 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Wed, 10 Sep 2025 19:07:40 +0530 Subject: [PATCH 1/3] feat: pagination on billing ui table --- package.json | 2 +- pnpm-lock.yaml | 10 +- src/lib/sdk/billing.ts | 11 +- .../billing/+page.svelte | 5 +- .../billing/+page.ts | 20 +- .../billing/planSummary.svelte | 460 ++++++++++-------- 6 files changed, 300 insertions(+), 208 deletions(-) diff --git a/package.json b/package.json index 216b1e0bf0..6a69a6d591 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134", + "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9922899f4f..a89c546309 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.25.3)(zod@3.24.3) '@appwrite.io/console': - specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134 - version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134 + specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515 + version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 @@ -260,8 +260,8 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134': - resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515': + resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515} version: 1.10.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': @@ -3700,7 +3700,7 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515': {} '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': dependencies: diff --git a/src/lib/sdk/billing.ts b/src/lib/sdk/billing.ts index 0361f59101..5a5fcd51b5 100644 --- a/src/lib/sdk/billing.ts +++ b/src/lib/sdk/billing.ts @@ -934,12 +934,19 @@ export class Billing { ); } - async getAggregation(organizationId: string, aggregationId: string): Promise { + async getAggregation( + organizationId: string, + aggregationId: string, + limit?: number, + offset?: number + ): Promise { const path = `/organizations/${organizationId}/aggregations/${aggregationId}`; - const params = { + const params: Record = { organizationId, aggregationId }; + if (typeof limit === 'number') params['limit'] = limit; + if (typeof offset === 'number') params['offset'] = offset; const uri = new URL(this.client.config.endpoint + path); return await this.client.call( 'get', diff --git a/src/routes/(console)/organization-[organization]/billing/+page.svelte b/src/routes/(console)/organization-[organization]/billing/+page.svelte index e749892505..421f48efc7 100644 --- a/src/routes/(console)/organization-[organization]/billing/+page.svelte +++ b/src/routes/(console)/organization-[organization]/billing/+page.svelte @@ -133,7 +133,10 @@ availableCredit={data?.availableCredit} currentPlan={data?.currentPlan} nextPlan={data?.nextPlan} - currentAggregation={data?.billingAggregation} /> + currentAggregation={data?.billingAggregation} + limit={data?.limit} + offset={data?.offset} + aggregationKey={data?.aggregationKey} /> {:else} { +import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; + +export const load: PageLoad = async ({ parent, depends, url, route }) => { const { organization, scopes, currentPlan, countryList, locale } = await parent(); if (!scopes.includes('billing.read')) { @@ -18,6 +20,8 @@ export const load: PageLoad = async ({ parent, depends }) => { depends(Dependencies.CREDIT); depends(Dependencies.INVOICES); depends(Dependencies.ADDRESS); + //aggregation reloads on page param changes + depends('billing:aggregation'); const billingAddressId = (organization as Organization)?.billingAddressId; const billingAddressPromise: Promise
= billingAddressId @@ -33,9 +37,14 @@ export const load: PageLoad = async ({ parent, depends }) => { */ let billingAggregation = null; try { + const currentPage = getPage(url) || 1; + const limit = getLimit(url, route, 5); + const offset = pageToOffset(currentPage, limit); billingAggregation = await sdk.forConsole.billing.getAggregation( organization.$id, - (organization as Organization)?.billingAggregationId + (organization as Organization)?.billingAggregationId, + limit, + offset ); } catch (e) { // ignore error @@ -83,6 +92,11 @@ export const load: PageLoad = async ({ parent, depends }) => { areCreditsSupported, countryList, locale, - nextPlan: billingPlanDowngrade + nextPlan: billingPlanDowngrade, + // expose pagination for components + limit: getLimit(url, route, 5), + offset: pageToOffset(getPage(url) || 1, getLimit(url, route, 5)), + // unique key to force component refresh on page change + aggregationKey: `agg:${getPage(url) || 1}:${getLimit(url, route, 5)}` }; }; diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index 2dac1238a3..d6f19f6374 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -1,6 +1,6 @@ {#if $organization} - - {currentPlan.name} plan - - {#if totalAmount > 0} - - Next payment of {formatCurrency(totalAmount)} - will occur on - {toLocaleDate($organization?.billingNextInvoiceDate)}. - - {/if} - -
- - Current billing cycle ({new Date( - $organization?.billingCurrentInvoiceDate - ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}-{new Date( - $organization?.billingNextInvoiceDate - ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}) - - - Estimate, subject to change based on usage. - -
- -
- - {#each billingData as row} - - {#each columns as col} - - {#if col.id === 'item'} -
+ {#key aggregationKey} + + {currentPlan.name} plan + + {#if totalAmount > 0} + + Next payment of {formatCurrency(totalAmount)} + will occur on + {toLocaleDate($organization?.billingNextInvoiceDate)}. + + {/if} + +
+ + Current billing cycle ({new Date( + $organization?.billingCurrentInvoiceDate + ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}-{new Date( + $organization?.billingNextInvoiceDate + ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}) + + + Estimate, subject to change based on usage. + +
+ +
+ + {#each billingData as row} + + {#each columns as col} + + {#if col.id === 'item'} +
+ {#if row.badge} + + + {row.cells?.[col.id] ?? ''} + + + + {:else} + + {row.cells?.[col.id] ?? ''} + + {/if} +
+ {:else} {row.cells?.[col.id] ?? ''} -
- {:else} - - {row.cells?.[col.id] ?? ''} - + {/if} + + {/each} + + + {#if row.children} + {#each row.children as child (child.id)} + + {/each} +
+ {/each} {/if} + +
+ {/each} + {#if totalProjects > projectsLimit} + + +
+ +
- {/each} - - - {#if row.children} - {#each row.children as child (child.id)} -
- {/each} -
- {/each} - {/if} - - - {/each} - {#if availableCredit > 0} + + + + {/if} + {#if availableCredit > 0} + + + + + + Credits + + + + + + + + + -{formatCurrency(creditsApplied)} + + + + {/if} + - - - - Credits - + + Total + @@ -470,79 +546,64 @@ - -{formatCurrency(creditsApplied)} + {formatCurrency(totalAmount)} - {/if} - - - - - Total - - - - - - - - - {formatCurrency(totalAmount)} - - - - - - - -
- {#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION} -
- {#if !currentPlan?.usagePerProject} - - {/if} - -
- {:else} -
- {#if $organization?.billingPlanDowngrade !== null} - - {:else} + +
+ + +
+ {#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION} +
+ {#if !currentPlan?.usagePerProject} + + {/if} - {/if} - {#if !currentPlan?.usagePerProject} - - {/if} -
- {/if} -
- +
+ {:else} +
+ {#if $organization?.billingPlanDowngrade !== null} + + {:else} + + {/if} + {#if !currentPlan?.usagePerProject} + + {/if} +
+ {/if} + +
+ {/key} {/if} @@ -733,4 +794,11 @@ background: unset !important; } } + + /* reducingh size of paginator */ + .pagination-left { + display: inline-block; + transform: scale(0.95); + transform-origin: left center; + } From c0e3043876c1acb059b918307aaaa16e323bffdb Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Mon, 15 Sep 2025 17:54:41 +0530 Subject: [PATCH 2/3] replaced expandable table with accordian --- package.json | 4 +- pnpm-lock.yaml | 20 +- .../billing/planSummary.svelte | 241 ++++++++---------- 3 files changed, 115 insertions(+), 150 deletions(-) diff --git a/package.json b/package.json index 6a69a6d591..bce7be27a5 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2515", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092", "@faker-js/faker": "^9.9.0", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a89c546309..71383645b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ importers: specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -269,8 +269,8 @@ packages: peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -284,8 +284,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -3706,7 +3706,7 @@ snapshots: dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@2cf27e0(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@ba96092(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3719,7 +3719,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@fb8b1ed(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@ba96092(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index d6f19f6374..486915d0e7 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -11,7 +11,7 @@ import { Click, trackEvent } from '$lib/actions/analytics'; import { Typography, - Expandable as ExpandableTable, + AccordionTable, Icon, Layout, Divider, @@ -35,11 +35,11 @@ let showCancel: boolean = false; - // define columns for the expandable table + // define columns for the accordion table const columns = [ - { id: 'item', align: 'left' as const, width: '10fr' }, - { id: 'usage', align: 'left' as const, width: '20fr' }, - { id: 'price', align: 'right' as const, width: '0fr' } + { id: 'item', align: 'left' as const, width: { min: 200 } }, + { id: 'usage', align: 'left' as const, width: { min: 500 } }, + { id: 'price', align: 'right' as const, width: { min: 100 } } ]; function formatHumanSize(bytes: number): string { @@ -376,17 +376,11 @@ @@ -729,38 +726,6 @@ flex-shrink: 0; } - /* mobile table wrapper for horizontal scroll */ - .table-wrapper.is-mobile { - overflow-x: auto; - -webkit-overflow-scrolling: touch; - margin: 0 -1rem; - padding: 0 1rem; - } - - /* reset mobile overrides - use desktop layout in scrollable container */ - .table-wrapper.is-mobile :global(.child-row) { - grid-template-columns: var(--original-grid-template) !important; - min-width: 600px; /* ensure minimum width for proper layout */ - } - - .table-wrapper.is-mobile :global(.usage-cell-content) { - flex-direction: row !important; - align-items: center !important; - gap: 0.75rem !important; - padding-left: 1rem !important; - min-height: 2rem !important; - } - - .table-wrapper.is-mobile :global(.usage-progress-section) { - width: 200px !important; - flex-shrink: 0 !important; - } - - .table-wrapper.is-mobile :global(.usage-progress-section .progressbar__container) { - width: 200px !important; - max-width: 200px !important; - } - @media (max-width: 768px) { .actions-mobile { justify-content: flex-start !important; From 9de7eceab754a37da91bd99ca556347f53c98c44 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:31:44 +0530 Subject: [PATCH 3/3] removed unnecessary table warppper class --- .../organization-[organization]/billing/planSummary.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index 486915d0e7..21bd174cd2 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -375,7 +375,7 @@ -
+
{#each billingData as row}