diff --git a/package.json b/package.json index cef36f39c..f12341aef 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "^2.0.0-RC.1", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@40bae6b", + "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", "@stripe/stripe-js": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1e469431..a3664a807 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@40bae6b - version: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b(svelte@5.25.3) + specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778 + version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778(svelte@5.25.3) '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 @@ -260,8 +260,9 @@ packages: '@appwrite.io/console@1.9.0': resolution: {integrity: sha512-g8+zfdBF8mz7tRUER4CGVe5FHWQVLp8TlY/UOGCZ2TgUF1qnpNu/DhiQgph8uF+QZ9jDKCLAAZlP5//9t7ckWA==} - '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': - resolution: {integrity: sha512-iLFlV55hj8mGuAbmxJGenxN5RaZMmVT4GJb9dv/MP1xBAtYibFq7JvBcxm18qV2KU8c31Rntf+Ub4GL7HwqTYg==} + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@ee1b7788cd3f877c9aa1b6487976bd63a6196870': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@ee1b7788cd3f877c9aa1b6487976bd63a6196870} + version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -280,8 +281,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/%40appwrite.io%2Fpink-svelte@40bae6b': - resolution: {tarball: https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b} + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778': + resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -3636,7 +3637,7 @@ snapshots: '@appwrite.io/console@1.9.0': {} - '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@ee1b7788cd3f877c9aa1b6487976bd63a6196870(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3653,9 +3654,9 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/%40appwrite.io%2Fpink-svelte@40bae6b(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@ee1b778(svelte@5.25.3)': dependencies: - '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) + '@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@ee1b7788cd3f877c9aa1b6487976bd63a6196870(svelte@5.25.3) '@floating-ui/dom': 1.6.13 '@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.25.3))(svelte@5.25.3) '@melt-ui/svelte': 0.86.6(svelte@5.25.3) diff --git a/src/lib/components/billing/gradientBanner.svelte b/src/lib/components/billing/gradientBanner.svelte index 27c58ce62..92923bae5 100644 --- a/src/lib/components/billing/gradientBanner.svelte +++ b/src/lib/components/billing/gradientBanner.svelte @@ -1,10 +1,13 @@ @@ -72,4 +74,25 @@ {formatCurrency(scalePlan?.price ?? 0)} per month + usage + {#if $currentPlan && !isBasePlan} + + + {#if $organization?.billingPlan === $currentPlan.$id && !isNewOrg} + + {/if} + + + {$currentPlan.desc} + + + {@const isZeroPrice = ($currentPlan?.price ?? 0) <= 0} + {@const price = formatCurrency($currentPlan?.price ?? 0)} + {isZeroPrice ? price : `${price} per month + usage`} + + + {/if} diff --git a/src/lib/components/breadcrumbs.svelte b/src/lib/components/breadcrumbs.svelte index 0951839d8..01f8c72a2 100644 --- a/src/lib/components/breadcrumbs.svelte +++ b/src/lib/components/breadcrumbs.svelte @@ -12,7 +12,7 @@ import { isCloud } from '$lib/system'; import { goto } from '$app/navigation'; import { base } from '$app/paths'; - import { newOrgModal } from '$lib/stores/organization'; + import { currentPlan, newOrgModal } from '$lib/stores/organization'; import { Click, trackEvent } from '$lib/actions/analytics'; import { page } from '$app/stores'; @@ -182,6 +182,14 @@ projectsBottomSheetOpen = false; } } + + $: correctPlanName = + // the plan names are hardcoded in some cases and are not available locally, + // so we rely on the plan's source of truth - `$currentPlan` + $currentPlan && + $currentPlan?.name.toLocaleLowerCase() !== selectedOrg?.tierName.toLocaleLowerCase() + ? $currentPlan.name + : selectedOrg?.tierName; // fallback @@ -195,9 +203,9 @@ aria-label="Open organizations tab"> {selectedOrg?.name ?? 'Organization'} {#if selectedOrg?.tierName}{#if correctPlanName}{/if} + content={correctPlanName} />{/if} {:else} @@ -211,7 +219,7 @@ {selectedOrg?.name ?? 'Organization'} + > {/if} diff --git a/src/lib/components/columnSelector.svelte b/src/lib/components/columnSelector.svelte index 37c1640ad..c113d5e9c 100644 --- a/src/lib/components/columnSelector.svelte +++ b/src/lib/components/columnSelector.svelte @@ -18,6 +18,19 @@ children: Snippet<[toggle: () => void, selectedColumnsNumber: number]>; } = $props(); + let maxHeight = $state('none'); + let containerRef; + + const calcMaxHeight = () => { + if (containerRef) { + // get parent row element for correct top position + const parent = containerRef.parentElement.parentElement; + const { top } = parent.getBoundingClientRect(); + + maxHeight = `${window.innerHeight - top - 48}px`; + } + }; + onMount(async () => { if (isCustomCollection) { const prefs = preferences.getCustomCollectionColumns(page.params.collection); @@ -50,6 +63,8 @@ preferences.setColumns(columns); } }); + + calcMaxHeight(); }); let selectedColumnsNumber = $derived( @@ -61,29 +76,32 @@ ); + {#if $columns?.length} {@render children(toggle, selectedColumnsNumber)} - - {#each $columns as column} - {#if !column?.exclude} - (column.hide = !column.hide)} - disabled={allowNoColumns - ? false - : selectedColumnsNumber <= 1 && column.hide !== true}> - - (column.hide = !column.hide)} /> - {column.title} - - - {/if} - {/each} - +
+ + {#each $columns as column} + {#if !column?.exclude} + (column.hide = !column.hide)} + disabled={allowNoColumns + ? false + : selectedColumnsNumber <= 1 && column.hide !== true}> + + (column.hide = !column.hide)} /> + {column.title} + + + {/if} + {/each} + +
{/if} diff --git a/src/lib/components/navbar.svelte b/src/lib/components/navbar.svelte index 435037fd6..ee1b70df4 100644 --- a/src/lib/components/navbar.svelte +++ b/src/lib/components/navbar.svelte @@ -229,7 +229,7 @@ style:padding-inline-end="8px" style:padding-block="4px"> - {$user.email} + {$user?.email} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/layout/responsiveContainerHeader.svelte b/src/lib/layout/responsiveContainerHeader.svelte index 247564f86..e84caf048 100644 --- a/src/lib/layout/responsiveContainerHeader.svelte +++ b/src/lib/layout/responsiveContainerHeader.svelte @@ -17,7 +17,7 @@ let { columns, - view = View.Table, + view = $bindable(View.Table), hideView = false, hideColumns = false, hasSearch = false, diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index e9388c8c9..c68f336c1 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -11,7 +11,7 @@ import PaymentAuthRequired from '$lib/components/billing/alerts/paymentAuthRequi import PaymentMandate from '$lib/components/billing/alerts/paymentMandate.svelte'; import { BillingPlan, NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants'; import { cachedStore } from '$lib/helpers/cache'; -import { sizeToBytes, type Size } from '$lib/helpers/sizeConvertion'; +import { type Size, sizeToBytes } from '$lib/helpers/sizeConvertion'; import type { AddressesList, Aggregation, @@ -28,12 +28,18 @@ import { Query } from '@appwrite.io/console'; import { derived, get, writable } from 'svelte/store'; import { headerAlert } from './headerAlert'; import { addNotification, notifications } from './notifications'; -import { organization, type Organization, type OrganizationError } from './organization'; +import { + currentPlan, + organization, + type Organization, + type OrganizationError +} from './organization'; import { canSeeBilling } from './roles'; import { sdk } from './sdk'; import { user } from './user'; import BudgetLimitAlert from '$routes/(console)/organization-[organization]/budgetLimitAlert.svelte'; import TeamReadonlyAlert from '$routes/(console)/organization-[organization]/teamReadonlyAlert.svelte'; +import EnterpriseTrial from '$routes/(console)/organization-[organization]/enterpriseTrial.svelte'; export type Tier = 'tier-0' | 'tier-1' | 'tier-2' | 'auto-1' | 'cont-1' | 'ent-1'; @@ -268,6 +274,32 @@ export function isServiceLimited(serviceId: PlanServices, plan: Tier, total: num return isLimited && total >= limit && !hasUsageFees; } +export function checkForEnterpriseTrial(org: Organization) { + if (!org || !org.billingNextInvoiceDate) return; + if (calculateEnterpriseTrial(org) > 0) { + headerAlert.add({ + id: 'teamEnterpriseTrial', + component: EnterpriseTrial, + show: true, + importance: 11 + }); + } +} + +export function calculateEnterpriseTrial(org: Organization) { + const endDate = new Date(org.billingNextInvoiceDate); + const startDate = new Date(org.billingCurrentInvoiceDate); + const today = new Date(); + + let diffCycle = endDate.getTime() - startDate.getTime(); + diffCycle = Math.ceil(diffCycle / (1000 * 60 * 60 * 24)); + if (diffCycle === 14) { + const remaining = endDate.getTime() - today.getTime(); + return Math.ceil(remaining / (1000 * 60 * 60 * 24)); + } + return 0; +} + export function calculateTrialDay(org: Organization) { if (org?.billingPlan === BillingPlan.FREE) return false; const endDate = new Date(org?.billingStartDate); @@ -323,7 +355,7 @@ export async function checkForUsageLimit(org: Organization) { ]; const members = org.total; - const plan = get(plansInfo)?.get(org.billingPlan); + const plan = get(currentPlan); const membersOverflow = members > plan.addons.seats.limit ? members - (plan.addons.seats.limit || members) : 0; diff --git a/src/lib/stores/user.ts b/src/lib/stores/user.ts index 808dd3877..496da7952 100644 --- a/src/lib/stores/user.ts +++ b/src/lib/stores/user.ts @@ -13,6 +13,10 @@ export type Account = Models.User< >; export const user = derived(page, ($page) => { - if (browser) sessionStorage.setItem('account', JSON.stringify($page.data.account)); - return $page.data.account as Account; + if ($page.data?.account) { + if (browser) { + sessionStorage.setItem('account', JSON.stringify($page.data.account)); + } + return $page.data.account as Account; + } else return null; }); diff --git a/src/routes/(console)/(migration-wizard)/resource-form.svelte b/src/routes/(console)/(migration-wizard)/resource-form.svelte index 103d084b2..e8b5dadc4 100644 --- a/src/routes/(console)/(migration-wizard)/resource-form.svelte +++ b/src/routes/(console)/(migration-wizard)/resource-form.svelte @@ -167,7 +167,10 @@ {error} {formGroup} groupKey={getAsType(groupKey)} - reportValue={report?.[getReportKey(groupKey)]} /> + reportValue={report?.[getReportKey(groupKey)]} + on:updateFormGroup={(e) => { + $formData[groupKey] = e.detail; + }} /> {/if} {/each} {/if} diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte index 9d7a72d6d..dcdbf2011 100644 --- a/src/routes/(console)/+layout.svelte +++ b/src/routes/(console)/+layout.svelte @@ -13,6 +13,7 @@ import Create from './createOrganization.svelte'; import { calculateTrialDay, + checkForEnterpriseTrial, checkForMandate, checkForMarkedForDeletion, checkForMissingPaymentMethod, @@ -304,6 +305,7 @@ if (currentOrganizationId === org.$id) return; if (isCloud) { currentOrganizationId = org.$id; + checkForEnterpriseTrial(org); await checkForUsageLimit(org); checkForMarkedForDeletion(org); await checkForNewDevUpgradePro(org); diff --git a/src/routes/(console)/organization-[organization]/enterpriseTrial.svelte b/src/routes/(console)/organization-[organization]/enterpriseTrial.svelte new file mode 100644 index 000000000..6fe97f821 --- /dev/null +++ b/src/routes/(console)/organization-[organization]/enterpriseTrial.svelte @@ -0,0 +1,69 @@ + + +{#if $organization?.$id && remainingDays > 0 && !hideBillingHeaderRoutes.includes(page.url.pathname) && show} + + + +{/if} + + diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte index b7e886be5..989916cf9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte @@ -1,37 +1,31 @@ - - - - - - - {#if $canWriteCollections} - - {/if} - - + + {#if $canWriteCollections} + + {/if} + {#if data.collections.total} {#if data.view === 'grid'} diff --git a/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte b/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte index 0ed4c8b4c..12821a0bf 100644 --- a/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/messaging/+page.svelte @@ -1,19 +1,11 @@ - - - - - - - - {#if $canWriteMessages} - - {/if} - - + + {#if $canWriteMessages} + + {/if} + {#if data.messages.total} import { page } from '$app/state'; import { Button } from '$lib/elements/forms'; - import { - Empty, - EmptySearch, - SearchQuery, - PaginationWithLimit, - EmptyFilter, - ViewSelector - } from '$lib/components'; + import { Empty, EmptySearch, PaginationWithLimit, EmptyFilter } from '$lib/components'; import Create from './create.svelte'; import { goto } from '$app/navigation'; - import { Container } from '$lib/layout'; + import { Container, ResponsiveContainerHeader } from '$lib/layout'; import { base } from '$app/paths'; import type { Models } from '@appwrite.io/console'; import type { PageData } from './$types'; import { showCreate } from './store'; - import { Filters, hasPageQueries } from '$lib/components/filters'; + import { hasPageQueries } from '$lib/components/filters'; import Table from './table.svelte'; import type { Column } from '$lib/helpers/types'; import { writable } from 'svelte/store'; import { canWriteTopics } from '$lib/stores/roles'; - import { Icon, Layout } from '@appwrite.io/pink-svelte'; + import { Icon } from '@appwrite.io/pink-svelte'; import { View } from '$lib/helpers/load'; import { IconPlus } from '@appwrite.io/pink-icons-svelte'; import { Click, trackEvent } from '$lib/actions/analytics'; @@ -72,26 +65,26 @@ - - - - - - - - {#if $canWriteTopics} - - {/if} - - + + {#if $canWriteTopics} + + {/if} + {#if data.topics.total} diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte index 59460df7e..8d0aa74df 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte @@ -115,9 +115,11 @@ static const String APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.reg projectId, platform, $createPlatform.name, - $createPlatform.key || undefined, + platform === PlatformType.Flutterweb ? undefined : $createPlatform.key || undefined, undefined, - undefined + platform === PlatformType.Flutterweb + ? $createPlatform.hostname || undefined + : undefined ); isPlatformCreated = true; @@ -189,19 +191,35 @@ static const String APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.reg bind:value={$createPlatform.name} /> - - - - - {placeholder[platform].tooltip} - - - + {#if platform === PlatformType.Flutterweb} + + + + + {placeholder[platform].tooltip} + + + + {:else} + + + + + {placeholder[platform].tooltip} + + + + {/if}