diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte index de40932f52..3f6fe9bd57 100644 --- a/src/lib/components/billing/planSelection.svelte +++ b/src/lib/components/billing/planSelection.svelte @@ -2,12 +2,13 @@ import { BillingPlan } from '$lib/constants'; import { formatCurrency } from '$lib/helpers/numbers'; import { currentPlan, organization } from '$lib/stores/organization'; - import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte'; + import { Badge, Layout, Tooltip, Typography } from '@appwrite.io/pink-svelte'; import { LabelCard } from '..'; import type { Plan } from '$lib/sdk/billing'; import { page } from '$app/state'; import { ProfileMode, resolvedProfile } from '$lib/profiles/index.svelte'; import { InputSelect } from '$lib/elements/forms'; + import { isFreePlan, isPaidPlan } from '$lib/helpers/billing'; export let disabled = false; export let isNewOrg = false; @@ -113,52 +114,63 @@ function handleTierChange(group: PlanGroup) { billingPlan = selectedTiers[group.key] as BillingPlan; } + + function shouldShowTooltip(plan: Plan) { + if (isPaidPlan(plan.$id)) return true; + else return !anyOrgFree; + } {#each groupedPlans as group (group.key)} {@const basePlan = group.plans[0]} - - - {#if group.plans.some((plan) => $organization?.billingPlan === plan.$id) && !isNewOrg} - - {/if} - - - - - - {basePlan.desc} - - - {#if !group.isGrouped} - - {@const isZeroPrice = (basePlan.price ?? 0) <= 0} - {@const price = formatCurrency(basePlan.price ?? 0)} - {#if resolvedProfile.id === ProfileMode.STUDIO} - {getPlanLabel(basePlan)} - {:else} - {isZeroPrice ? price : getPlanLabel(basePlan)} - {/if} - + + + + {#if group.plans.some((plan) => $organization?.billingPlan === plan.$id) && !isNewOrg} + + {/if} + + + + + + {basePlan.desc} + + + {#if !group.isGrouped} + + {@const isZeroPrice = (basePlan.price ?? 0) <= 0} + {@const price = formatCurrency(basePlan.price ?? 0)} + {#if resolvedProfile.id === ProfileMode.STUDIO} + {getPlanLabel(basePlan)} + {:else} + {isZeroPrice ? price : getPlanLabel(basePlan)} + {/if} + + {/if} + + + {#if group.isGrouped} + handleTierChange(group)} + options={group.tierOptions} /> {/if} + - {#if group.isGrouped} - handleTierChange(group)} - options={group.tierOptions} /> - {/if} - - + + Only 1 free organization is allowed per account. + + {/each} {#if $currentPlan && !currentPlanInList} diff --git a/src/lib/components/filePicker.svelte b/src/lib/components/filePicker.svelte index 06866380b4..28b64406b1 100644 --- a/src/lib/components/filePicker.svelte +++ b/src/lib/components/filePicker.svelte @@ -33,6 +33,7 @@ import { IconInfo, IconPlus, IconViewGrid, IconViewList } from '@appwrite.io/pink-icons-svelte'; import { showCreateBucket } from '$routes/(console)/project-[region]-[project]/storage/+page.svelte'; import { preferences } from '$lib/stores/preferences'; + import { addNotification } from '$lib/stores/notifications'; export let show: boolean; export let mimeTypeQuery: string = 'image/'; @@ -110,7 +111,10 @@ } selectFile(file); } catch (e) { - console.error(e); + addNotification({ + type: 'error', + message: e.message + }); } finally { uploading = false; } @@ -351,7 +355,9 @@ {localFileBucketTitle} - + {allowedExtension} files are allowed + >{allowedExtension === '*' + ? `${mimeTypeQuery} files are allowed` + : `${allowedExtension} files are allowed`} t.tag === newTag.tag && t.value === newTag.value)) { return; } else { @@ -66,7 +70,7 @@ { id: selectedColumn, operator: operatorKey, - value: value, + value: preparedValue, arrayValues: arrayValues } ]; diff --git a/src/lib/components/git/repositories.svelte b/src/lib/components/git/repositories.svelte index 260576f324..d0dbaf8003 100644 --- a/src/lib/components/git/repositories.svelte +++ b/src/lib/components/git/repositories.svelte @@ -1,5 +1,5 @@ - {#each Array(4) as _} + {#each Array(count) as _} diff --git a/src/lib/components/permissions/row.svelte b/src/lib/components/permissions/row.svelte index c70fd5f66f..aa44cb73ad 100644 --- a/src/lib/components/permissions/row.svelte +++ b/src/lib/components/permissions/row.svelte @@ -221,20 +221,26 @@ - {data.customName} + {formatName( + data.customName ?? '', + $isSmallViewport ? 20 : 28 + )} {#if data.roleName} {:else} {/if} diff --git a/src/lib/elements/forms/inputFilePicker.svelte b/src/lib/elements/forms/inputFilePicker.svelte index c029b459ab..4000d8118c 100644 --- a/src/lib/elements/forms/inputFilePicker.svelte +++ b/src/lib/elements/forms/inputFilePicker.svelte @@ -12,6 +12,8 @@ export let optionalText: string = null; export let tooltip: string = null; export let isPopoverDefined = true; + export let mimeTypeQuery: string = 'image/'; + export let allowedExtension: string = '*'; let show = false; @@ -93,5 +95,12 @@ {#if show} - + {/if} diff --git a/src/lib/stores/organization.ts b/src/lib/stores/organization.ts index d0b49e50f0..7393c6ed65 100644 --- a/src/lib/stores/organization.ts +++ b/src/lib/stores/organization.ts @@ -1,8 +1,8 @@ import { page } from '$app/stores'; -import { derived, writable } from 'svelte/store'; -import type { Models, Platform } from '@appwrite.io/console'; import type { Tier } from './billing'; import type { Plan } from '$lib/sdk/billing'; +import { derived, writable } from 'svelte/store'; +import { type Models, Platform } from '@appwrite.io/console'; export type OrganizationError = { status: number; diff --git a/src/routes/(console)/(migration-wizard)/wizard.svelte b/src/routes/(console)/(migration-wizard)/wizard.svelte index d31fa2cb9a..f2dbac3059 100644 --- a/src/routes/(console)/(migration-wizard)/wizard.svelte +++ b/src/routes/(console)/(migration-wizard)/wizard.svelte @@ -58,6 +58,7 @@ let newProjName = ''; let projectType: 'existing' | 'new' = 'existing'; + let newlyCreatedProject: Models.Project | null = null; async function getProjects(orgId: string | null) { if (!orgId) { @@ -128,8 +129,9 @@ }); onExit(); await invalidate(Dependencies.PROJECTS); + const targetProject = newlyCreatedProject ?? currentSelectedProject; await goto( - `${base}/project-${currentSelectedProject.region}-${currentSelectedProject.$id}/settings/migrations` + `${base}/project-${targetProject.region ?? 'default'}-${targetProject.$id}/settings/migrations` ); } catch (error) { addNotification({ @@ -260,6 +262,7 @@ } else { const project = await createNewProject(); if (project !== null) { + newlyCreatedProject = project; projectSdkInstance = sdk.forProject( project.region, project.$id diff --git a/src/routes/(console)/create-organization/+page.svelte b/src/routes/(console)/create-organization/+page.svelte index 3006d9721f..e43117700a 100644 --- a/src/routes/(console)/create-organization/+page.svelte +++ b/src/routes/(console)/create-organization/+page.svelte @@ -1,6 +1,6 @@ @@ -218,7 +221,8 @@ + bind:billingPlan={selectedPlan} + anyOrgFree={data.hasFreeOrganizations} /> diff --git a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte index 7e39f10ee6..22797e6df3 100644 --- a/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte +++ b/src/routes/(console)/organization-[organization]/billing/retryPaymentModal.svelte @@ -55,7 +55,7 @@ async function handleSubmit() { isButtonDisabled = true; try { - if (paymentMethodId === null) { + if (paymentMethodId === null || paymentMethodId === '$new') { try { if (showState && !state) { throw Error('Please select a state'); @@ -65,13 +65,17 @@ method = await setPaymentMethod(paymentMethod.id, name, state); } else { const card = await submitStripeCard(name, $organization.$id); - if (card && Object.hasOwn(card, 'id')) { + // When Stripe returns an expanded PaymentMethod for US cards, we need state. + if (Object.hasOwn(card, 'id') && (card as PaymentMethod)?.card) { if ((card as PaymentMethod).card?.country === 'US') { paymentMethod = card as PaymentMethod; showState = true; return; } - } else if (card && Object.hasOwn(card, '$id')) { + } + + // Otherwise, we expect an Appwrite PaymentMethodData with `$id`. + if (Object.hasOwn(card, '$id')) { method = card as PaymentMethodData; } } diff --git a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte index 48ee2b2a9d..a3c25857fa 100644 --- a/src/routes/(console)/organization-[organization]/change-plan/+page.svelte +++ b/src/routes/(console)/organization-[organization]/change-plan/+page.svelte @@ -344,6 +344,7 @@ diff --git a/src/routes/(console)/organization-[organization]/header.svelte b/src/routes/(console)/organization-[organization]/header.svelte index e2cc3a1135..3f7e6b6218 100644 --- a/src/routes/(console)/organization-[organization]/header.svelte +++ b/src/routes/(console)/organization-[organization]/header.svelte @@ -1,4 +1,5 @@ {#if loading} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte index ff67ac2279..d826c2f862 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte @@ -901,9 +901,9 @@ hoverEffect showSelectOnHover valueWithoutHover={row.$sequence}> - {#each $tableColumns as { id: columnId, isEditable } (columnId)} + {#each $tableColumns as { id: columnId, isEditable, hide } (columnId)} {@const rowColumn = $columns.find((col) => col.key === columnId)} - {#if columnId === '$id'} + {#if columnId === '$id' && !hide}