-
Notifications
You must be signed in to change notification settings - Fork 243
feat: add Premium Geo DB addon to project settings #2981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lohanidamodar
wants to merge
27
commits into
main
Choose a base branch
from
feat/project-premium-geo-db-addon
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
470b047
feat: add Premium Geo DB addon to project settings
lohanidamodar 5954b75
feat(settings): show price in premium geo DB enable dialog
lohanidamodar 7e73d36
update sdk
lohanidamodar 0e53210
feat(billing): render project addons in breakdown + use server addon …
lohanidamodar 66e615e
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar afb13fc
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 13b0478
chore: bump @appwrite.io/console SDK to 95547fc
lohanidamodar 0cba797
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 6fc000f
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 304142c
chore: keep @appwrite.io/console@95547fc for premium geo DB SDK methods
lohanidamodar 67566db
Revert "chore: keep @appwrite.io/console@95547fc for premium geo DB S…
lohanidamodar e5a62c5
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar a54c530
chore: update console SDK to 352239b
lohanidamodar 4376702
merge main
lohanidamodar da68f75
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 0889ace
feat(settings): rewrite Premium Geo DB card description to focus on d…
lohanidamodar 6fbdd43
feat(settings): tighten Premium Geo DB card copy to outcome-focused v…
lohanidamodar 1ba8ebd
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar f8d2816
chore: update console SDK to 634f110
lohanidamodar afecbd2
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 60838e0
fix(settings): handle 3DS redirect + replace cancel/retry with refres…
lohanidamodar 279737d
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar 51ad756
fix: rename Models.Locale to Models.CloudLocale after SDK bump
lohanidamodar bd9d958
Merge main into feat/project-premium-geo-db-addon
lohanidamodar 5b1b4fd
Bump console SDK to @2642dc5 (current cloud HEAD)
lohanidamodar 0983d4c
Bump console SDK to @dd8e255
lohanidamodar bdf38af
Merge remote-tracking branch 'origin/main' into feat/project-premium-…
lohanidamodar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 12 additions & 3 deletions
15
src/routes/(console)/project-[region]-[project]/settings/+page.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,38 @@ | ||
| import { Dependencies, PAGE_LIMIT } from '$lib/constants'; | ||
| import { isCloud } from '$lib/system'; | ||
| import { sdk } from '$lib/stores/sdk'; | ||
| import { Query } from '@appwrite.io/console'; | ||
| import type { PageLoad } from './$types'; | ||
|
|
||
| export const load: PageLoad = async ({ depends, url, params }) => { | ||
| depends(Dependencies.PROJECT_VARIABLES); | ||
| depends(Dependencies.PROJECT_INSTALLATIONS); | ||
| depends(Dependencies.ADDONS); | ||
| const limit = PAGE_LIMIT; | ||
| const offset = Number(url.searchParams.get('offset') ?? 0); | ||
| const variablesOffset = Number(url.searchParams.get('variablesOffset') ?? 0); | ||
| const projectSdk = sdk.forProject(params.region, params.project); | ||
| const [variables, installations] = await Promise.all([ | ||
| const [variables, installations, addons] = await Promise.all([ | ||
| projectSdk.projectApi.listVariables({ | ||
| queries: [Query.limit(limit), Query.offset(variablesOffset)] | ||
| }), | ||
| projectSdk.vcs.listInstallations({ | ||
| queries: [Query.limit(limit), Query.offset(offset)] | ||
| }) | ||
| }), | ||
| isCloud | ||
| ? sdk | ||
| .forConsoleIn(params.region) | ||
| .projects.listAddons({ projectId: params.project }) | ||
| .catch(() => null) | ||
| : Promise.resolve(null) | ||
| ]); | ||
|
|
||
| return { | ||
| limit, | ||
| offset, | ||
| variablesOffset, | ||
| variables, | ||
| installations | ||
| installations, | ||
| addons | ||
| }; | ||
| }; |
176 changes: 176 additions & 0 deletions
176
src/routes/(console)/project-[region]-[project]/settings/premiumGeoDB.svelte
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| <script lang="ts"> | ||
| import { Box, CardGrid } from '$lib/components'; | ||
| import { Button } from '$lib/elements/forms'; | ||
| import { getChangePlanUrl, plansInfo } from '$lib/stores/billing'; | ||
| import { currentPlan, organization } from '$lib/stores/organization'; | ||
| import { page } from '$app/state'; | ||
| import { get } from 'svelte/store'; | ||
| import { invalidate } from '$app/navigation'; | ||
| import { Dependencies } from '$lib/constants'; | ||
| import { addNotification } from '$lib/stores/notifications'; | ||
| import { sdk } from '$lib/stores/sdk'; | ||
| import { Badge } from '@appwrite.io/pink-svelte'; | ||
| import type { Models } from '@appwrite.io/console'; | ||
| import PremiumGeoDBEnableModal from './premiumGeoDBEnableModal.svelte'; | ||
| import PremiumGeoDBDisableModal from './premiumGeoDBDisableModal.svelte'; | ||
|
|
||
| export let addons: Models.AddonList | null = null; | ||
|
|
||
| let showEnable = false; | ||
| let showDisable = false; | ||
| let reEnabling = false; | ||
| let cancelling = false; | ||
|
|
||
| $: planSupportsPremiumGeoDB = $currentPlan?.supportedAddons?.premiumGeoDB === true; | ||
| $: canUpgradeToPremiumGeoDB = | ||
| !planSupportsPremiumGeoDB && hasUpgradeablePlanWithPremiumGeoDB($currentPlan); | ||
| $: premiumGeoDBAddon = addons?.addons?.find( | ||
| (a) => a.key === 'premiumGeoDB' && (a.status === 'active' || a.status === 'pending') | ||
| ); | ||
| $: isPending = premiumGeoDBAddon?.status === 'pending'; | ||
| $: isActive = premiumGeoDBAddon?.status === 'active'; | ||
| $: isScheduledForRemoval = isActive && premiumGeoDBAddon?.nextValue === 0; | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
|
|
||
| function hasUpgradeablePlanWithPremiumGeoDB(plan: Models.BillingPlan): boolean { | ||
| if (!plan) return false; | ||
| const plans = get(plansInfo); | ||
| for (const [, p] of plans) { | ||
| if (p.order > plan.order && p.supportedAddons?.premiumGeoDB) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| async function handleCancelAndRetry() { | ||
| cancelling = true; | ||
| try { | ||
| await sdk.forConsoleIn(page.params.region).projects.deleteAddon({ | ||
| projectId: page.params.project, | ||
| addonId: premiumGeoDBAddon.$id | ||
| }); | ||
| await invalidate(Dependencies.ADDONS); | ||
| showEnable = true; | ||
| } catch (e) { | ||
| addNotification({ | ||
| message: e.message, | ||
| type: 'error' | ||
| }); | ||
| } finally { | ||
| cancelling = false; | ||
| } | ||
| } | ||
|
|
||
| async function handleReEnable() { | ||
| reEnabling = true; | ||
| try { | ||
| await sdk.forConsoleIn(page.params.region).projects.createPremiumGeoDBAddon({ | ||
| projectId: page.params.project | ||
| }); | ||
| await Promise.all([invalidate(Dependencies.ADDONS), invalidate(Dependencies.PROJECT)]); | ||
| addNotification({ | ||
| message: 'Premium Geo DB addon has been re-enabled', | ||
| type: 'success' | ||
| }); | ||
| } catch (e) { | ||
| addNotification({ | ||
| message: e.message, | ||
| type: 'error' | ||
| }); | ||
| } finally { | ||
| reEnabling = false; | ||
| } | ||
| } | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
| </script> | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
|
|
||
| <CardGrid> | ||
| <svelte:fragment slot="title">Premium Geo DB</svelte:fragment> | ||
| Enrich session and request data with premium geolocation details such as timezone, postal code, ISP, | ||
| connection type, and organization. Useful for fine-grained analytics, fraud detection, and personalized | ||
| user experiences. | ||
| <svelte:fragment slot="aside"> | ||
| <Box> | ||
| <h6> | ||
| <b>Premium Geo DB</b> | ||
| </h6> | ||
| {#if !planSupportsPremiumGeoDB && canUpgradeToPremiumGeoDB} | ||
| <p class="text u-margin-block-start-8"> | ||
| Premium Geo DB is not available on your current plan. Upgrade your plan to | ||
| enable it. | ||
| </p> | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| href={getChangePlanUrl($organization?.$id)}> | ||
| <span class="text">Upgrade plan</span> | ||
| </Button> | ||
| {:else if !planSupportsPremiumGeoDB} | ||
| <p class="text u-margin-block-start-8"> | ||
| Premium Geo DB is not available on your current plan. | ||
| </p> | ||
| {:else if isPending} | ||
| <div class="u-flex u-cross-center u-gap-8 u-margin-block-start-8"> | ||
| <Badge variant="secondary" type="warning" content="Payment pending" /> | ||
| </div> | ||
| <p class="text u-margin-block-start-8"> | ||
| A payment is awaiting confirmation. If the payment was interrupted, you can | ||
| cancel and retry. | ||
| </p> | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| disabled={cancelling} | ||
| on:click={handleCancelAndRetry}> | ||
| <span class="text">Cancel & retry</span> | ||
| </Button> | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
| {:else if isActive} | ||
| <div class="u-flex u-cross-center u-gap-8 u-margin-block-start-8"> | ||
| {#if isScheduledForRemoval} | ||
| <Badge variant="secondary" type="warning" content="Scheduled for removal" /> | ||
| {:else} | ||
| <Badge variant="secondary" type="success" content="Active" /> | ||
| {/if} | ||
| </div> | ||
| <p class="text u-margin-block-start-8"> | ||
| Premium Geo DB is enabled for this project. | ||
| </p> | ||
| {#if isScheduledForRemoval} | ||
| <p class="text u-margin-block-start-8"> | ||
| Premium Geo DB will be removed at the end of your current billing cycle. | ||
| </p> | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| disabled={reEnabling} | ||
| on:click={handleReEnable}> | ||
| <span class="text">Keep Premium Geo DB</span> | ||
| </Button> | ||
| {:else} | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| on:click={() => (showDisable = true)}> | ||
| <span class="text">Disable Premium Geo DB</span> | ||
| </Button> | ||
| {/if} | ||
| {:else} | ||
| <p class="text u-margin-block-start-8"> | ||
| Enable Premium Geo DB for this project to collect detailed geolocation data on | ||
| every request. Billed prorated for your current cycle. | ||
| </p> | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| on:click={() => (showEnable = true)}> | ||
| <span class="text">Enable Premium Geo DB</span> | ||
| </Button> | ||
| {/if} | ||
| </Box> | ||
| </svelte:fragment> | ||
| </CardGrid> | ||
|
|
||
| <PremiumGeoDBEnableModal bind:show={showEnable} /> | ||
|
|
||
| {#if premiumGeoDBAddon} | ||
| <PremiumGeoDBDisableModal bind:show={showDisable} addonId={premiumGeoDBAddon.$id} /> | ||
| {/if} | ||
54 changes: 54 additions & 0 deletions
54
src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBDisableModal.svelte
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <script lang="ts"> | ||
| import { page } from '$app/state'; | ||
| import { invalidate } from '$app/navigation'; | ||
| import { Modal } from '$lib/components'; | ||
| import { Button } from '$lib/elements/forms'; | ||
| import { Dependencies } from '$lib/constants'; | ||
| import { addNotification } from '$lib/stores/notifications'; | ||
| import { sdk } from '$lib/stores/sdk'; | ||
|
|
||
| let { | ||
| show = $bindable(false), | ||
| addonId | ||
| }: { | ||
| show: boolean; | ||
| addonId: string; | ||
| } = $props(); | ||
|
|
||
| let error = $state<string | null>(null); | ||
| let submitting = $state(false); | ||
|
|
||
| async function handleSubmit() { | ||
| submitting = true; | ||
| error = null; | ||
| try { | ||
| await sdk.forConsoleIn(page.params.region).projects.deleteAddon({ | ||
| projectId: page.params.project, | ||
| addonId | ||
| }); | ||
| await Promise.all([invalidate(Dependencies.ADDONS), invalidate(Dependencies.PROJECT)]); | ||
| addNotification({ | ||
| message: | ||
| 'Premium Geo DB addon will be removed at the end of your current billing cycle', | ||
| type: 'success' | ||
| }); | ||
| show = false; | ||
| } catch (e) { | ||
| error = e.message; | ||
| } finally { | ||
| submitting = false; | ||
| } | ||
| } | ||
| </script> | ||
|
|
||
| <Modal bind:error bind:show onSubmit={handleSubmit} title="Disable Premium Geo DB"> | ||
| <p class="text"> | ||
| Are you sure you want to disable the Premium Geo DB addon? The addon will remain active | ||
| until the end of your current billing cycle and will not be renewed. | ||
| </p> | ||
|
|
||
| <svelte:fragment slot="footer"> | ||
| <Button text on:click={() => (show = false)}>Cancel</Button> | ||
| <Button secondary submit disabled={submitting}>Disable Premium Geo DB</Button> | ||
| </svelte:fragment> | ||
| </Modal> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
BAA.sveltefilter uses the all-lowercase string'baa', consistent with Appwrite's API key convention. Here'premiumGeoDB'(camelCase) is used. If the API returns the addon with a lowercase key (following the same pattern as BAA), thisfindwill never match —premiumGeoDBAddonwould always beundefinedand the component would always render the Enable CTA even when the addon is already active or pending. The same camelCase string is also used in theonMountfallback lookup at line 65, so both detection paths would silently fail. Please confirm the exact key string the API returns for this addon. What string does the API'slistAddonsresponse return for thekeyfield of the Premium Geo DB addon —'premiumGeoDB','premiumgeodb', or something else? BAA uses'baa'(all lowercase), so camelCase here looks inconsistent with that established pattern.