diff --git a/src/lib/commandCenter/panels/ai.svelte b/src/lib/commandCenter/panels/ai.svelte index f2887239b..1c589e138 100644 --- a/src/lib/commandCenter/panels/ai.svelte +++ b/src/lib/commandCenter/panels/ai.svelte @@ -15,9 +15,10 @@ const { input, handleSubmit, completion, isLoading, complete, error } = useCompletion({ api: endpoint + '/console/assistant', headers: { - 'x-appwrite-mode': 'admin', - 'content-type': 'application/json' - } + 'content-type': 'application/json', + 'x-appwrite-project': 'console' + }, + credentials: 'include' }); let question = $input; diff --git a/src/lib/components/limit.svelte b/src/lib/components/limit.svelte index bf5ed752c..934354860 100644 --- a/src/lib/components/limit.svelte +++ b/src/lib/components/limit.svelte @@ -41,5 +41,5 @@ {options} bind:value={limit} on:change={limitChange} /> -

{name} per page. Total results: {sum}

+

{name} per page. Total results: {sum >= 5000 ? `${sum}+` : sum}

diff --git a/src/lib/layout/shell.svelte b/src/lib/layout/shell.svelte index f5435516d..318ef0000 100644 --- a/src/lib/layout/shell.svelte +++ b/src/lib/layout/shell.svelte @@ -30,8 +30,7 @@ * Cancel navigation when wizard is open and triggered by popstate */ beforeNavigate((n) => { - const external = n?.to?.url?.hostname !== globalThis?.location?.hostname; - if (external) return; + if (n.willUnload) return; if (!($wizard.show || $wizard.cover)) return; if (n.type === 'popstate') { n.cancel(); diff --git a/src/lib/layout/wizard.svelte b/src/lib/layout/wizard.svelte index 8d75f2c82..7ca87bfdd 100644 --- a/src/lib/layout/wizard.svelte +++ b/src/lib/layout/wizard.svelte @@ -75,8 +75,13 @@ wizard.setInterceptor(null); if (isLastStep) { + $wizard.nextDisabled = true; trackEvent('wizard_finish'); dispatch('finish'); + //Reactivate button in case there are errors + setTimeout(() => { + $wizard.nextDisabled = false; + }, 2000); } else { if (steps.get($wizard.step + 1)?.disabled) { $wizard.step++; diff --git a/src/lib/stores/marketplace.ts b/src/lib/stores/marketplace.ts index 9433a3f82..5c95eb771 100644 --- a/src/lib/stores/marketplace.ts +++ b/src/lib/stores/marketplace.ts @@ -132,7 +132,7 @@ export const marketplace: MarketplaceTemplate[] = [ { name: 'node-18.0', commands: 'npm install && npm run setup', - entrypoint: 'src/main.js && npm run setup', + entrypoint: 'src/main.js', providerRootDirectory: 'node/discord-command-bot' }, { @@ -150,9 +150,25 @@ export const marketplace: MarketplaceTemplate[] = [ variables: [ { name: 'DISCORD_PUBLIC_KEY', - description: `Discord Public Key to verify request signature. Learn more.`, + description: `Public Key of your application in Discord Developer Portal. Learn more.`, value: '', - placeholder: 'd1efb...aec35', + placeholder: 'db9...980', + required: true, + type: 'password' + }, + { + name: 'DISCORD_APPLICATION_ID', + description: `ID of your application in Discord Developer Portal. Learn more.`, + value: '', + placeholder: '427...169', + required: true, + type: 'password' + }, + { + name: 'DISCORD_TOKEN', + description: `Bot token of your application in Discord Developer Portal. Learn more.`, + value: '', + placeholder: 'NDI...LUfg', required: true, type: 'password' } @@ -698,7 +714,7 @@ export const marketplace: MarketplaceTemplate[] = [ value: '', placeholder: 'smtp.mailgun.org', required: true, - type: 'url' + type: 'text' }, { name: 'SMTP_PORT', @@ -737,6 +753,134 @@ export const marketplace: MarketplaceTemplate[] = [ type: 'text' } ] + }, + { + icon: 'icon-stripe', + id: 'subscriptions-with-stripe', + name: 'Subscriptions with Stripe', + tagline: 'Receive recurring card payments and grant subscribers extra permissions.', + permissions: ['any'], + events: [], + cron: '', + timeout: 15, + usecases: ['Utilities'], + runtimes: [ + { + name: 'node-18.0', + commands: 'npm install', + entrypoint: 'src/main.js', + providerRootDirectory: 'node/subscriptions-with-stripe' + } + ], + instructions: `For documentation and instructions check out file.`, + vcsProvider: 'github', + providerRepositoryId: 'templates', + providerOwner: 'appwrite', + providerBranch: 'main', + variables: [ + { + name: 'APPWRITE_API_KEY', + description: `The API Key to talk to Appwrite backend APIs. Learn more.`, + value: '', + placeholder: 'd1efb...aec35', + required: true, + type: 'password' + }, + { + name: 'APPWRITE_ENDPOINT', + description: `The URL endpoint of the Appwrite server. Learn more.`, + value: 'https://cloud.appwrite.io/v1', + placeholder: 'https://cloud.appwrite.io/v1', + required: false, + type: 'url' + }, + { + name: 'STRIPE_SECRET_KEY', + description: `Secret for sending requests to the Stripe API. Learn more.`, + placeholder: 'sk_test_51J...', + required: true, + type: 'password' + }, + { + name: 'STRIPE_WEBHOOK_SECRET', + description: `Secret used to validate the Stripe Webhook signature. Learn more.`, + placeholder: 'whsec_...', + required: true, + type: 'password' + } + ] + }, + { + icon: 'icon-stripe', + id: 'payments-with-stripe', + name: 'Payments with Stripe', + tagline: 'Receive card payments and store paid orders.', + permissions: ['any'], + events: [], + cron: '', + timeout: 15, + usecases: ['Utilities'], + runtimes: [ + { + name: 'node-18.0', + commands: 'npm install && npm run setup', + entrypoint: 'src/main.js', + providerRootDirectory: 'node/payments-with-stripe' + } + ], + instructions: `For documentation and instructions check out file.`, + vcsProvider: 'github', + providerRepositoryId: 'templates', + providerOwner: 'appwrite', + providerBranch: 'main', + variables: [ + { + name: 'APPWRITE_API_KEY', + description: `The API Key to talk to Appwrite backend APIs. Learn more.`, + value: '', + placeholder: 'd1efb...aec35', + required: true, + type: 'password' + }, + { + name: 'APPWRITE_ENDPOINT', + description: `The URL endpoint of the Appwrite server. Learn more.`, + value: 'https://cloud.appwrite.io/v1', + placeholder: 'https://cloud.appwrite.io/v1', + required: false, + type: 'url' + }, + { + name: 'STRIPE_SECRET_KEY', + description: `Secret for sending requests to the Stripe API. Learn more.`, + placeholder: 'sk_test_51J...', + required: true, + type: 'password' + }, + { + name: 'STRIPE_WEBHOOK_SECRET', + description: `Secret used to validate the Stripe Webhook signature. Learn more.`, + placeholder: 'whsec_...', + required: true, + type: 'password' + }, + { + name: 'APPWRITE_DATABASE_ID', + description: `The ID of the database to store paid orders. Learn more.`, + value: 'orders', + placeholder: 'orders', + required: false, + type: 'text' + }, + { + name: 'APPWRITE_COLLECTION_ID', + description: `The ID of the collection to store paid orders. Learn more.`, + value: 'orders', + placeholder: 'orders', + required: false, + type: 'text' + } + ] } ]; diff --git a/src/lib/wizards/functions/cover.svelte b/src/lib/wizards/functions/cover.svelte index 069005605..189ed47d2 100644 --- a/src/lib/wizards/functions/cover.svelte +++ b/src/lib/wizards/functions/cover.svelte @@ -106,21 +106,22 @@ {/each} {:then response} - {@const runtimes = response.runtimes} - {#each quickStart.runtimes.filter((_template, index) => index < 6) as runtime} - {@const runtimeDetail = runtimes.find( - (r) => r.$id === runtime.name - )} + {@const runtimes = new Map(response.runtimes.map((r) => [r.$id, r]))} + {@const templates = quickStart.runtimes.filter((_template) => + runtimes.has(_template.name) + )} + {#each templates.slice(0, 6) as template} + {@const runtimeDetail = runtimes.get(template.name)}
  • {/each} - {#if quickStart.runtimes.length < 6} + {#if templates.length < 6}
  • - import { Box } from '$lib/components'; + import { Box, SvgIcon } from '$lib/components'; import { FormList, InputChoice, InputText } from '$lib/elements/forms'; import InputSelectSearch from '$lib/elements/forms/inputSelectSearch.svelte'; import { WizardStep } from '$lib/layout'; @@ -8,14 +8,6 @@ import { choices, installation, repository } from '../store'; $choices.rootDir ??= ''; - function getProviderIcon(provider: string) { - switch (provider) { - case 'github': - return 'icon-github'; - default: - return ''; - } - } async function loadBranches() { const { branches } = await sdk.forProject.vcs.listRepositoryBranches( @@ -40,13 +32,9 @@ -
    -
    - -
    -
    -
    {$installation.organization}/{$repository.name}
    -
    +
    + +
    {$installation.organization}/{$repository.name}
    {#await loadBranches()}
    diff --git a/src/routes/console/project-[project]/functions/function-[function]/+layout.ts b/src/routes/console/project-[project]/functions/function-[function]/+layout.ts index e7362d9d8..dd5c79081 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+layout.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/+layout.ts @@ -14,8 +14,8 @@ export const load: LayoutLoad = async ({ params, depends }) => { return { header: Header, breadcrumbs: Breadcrumbs, - function: sdk.forProject.functions.get(params.function), - proxyRuleList: sdk.forProject.proxy.listRules([ + function: await sdk.forProject.functions.get(params.function), + proxyRuleList: await sdk.forProject.proxy.listRules([ Query.equal('resourceType', 'function'), Query.equal('resourceId', params.function), Query.limit(1) diff --git a/src/routes/console/project-[project]/functions/function-[function]/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/+page.svelte index 6e686948f..18f42e9d7 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/+page.svelte @@ -29,10 +29,9 @@ import { Container } from '$lib/layout'; import { app } from '$lib/stores/app'; import { calculateSize, humanFileSize } from '$lib/helpers/sizeConvertion'; - import { Query, type Models } from '@appwrite.io/console'; + import type { Models } from '@appwrite.io/console'; import Delete from './delete.svelte'; import Create from './create.svelte'; - import { sdk } from '$lib/stores/sdk'; import Activate from './activate.svelte'; import { calculateTime } from '$lib/helpers/timeConversion'; import { Pill } from '$lib/elements'; @@ -50,34 +49,10 @@ let showAlert = true; let selectedDeployment: Models.Deployment = null; - let activeDeployment: Models.Deployment = null; - - async function getActiveDeployment() { - if (!$func?.deployment) return null; - const list = await sdk.forProject.functions.listDeployments($page.params.function, [ - Query.equal('$id', $func.deployment) - ]); - return list?.deployments?.[0]; - } function handleActivate() { invalidate(Dependencies.DEPLOYMENTS); } - - deploymentList.subscribe((list: Models.DeploymentList | null) => { - if (list?.deployments) { - let activeDep = list.deployments.find( - (deployment) => deployment.$id === $func.deployment - ); - if (!activeDep) { - getActiveDeployment().then((deployment) => { - activeDeployment = deployment; - }); - } else { - activeDeployment = activeDep; - } - } - }); @@ -86,6 +61,7 @@
    {#if $deploymentList?.total} + {@const activeDeployment = data.activeDeployment}
    Active
    @@ -113,8 +89,8 @@

    Deployment ID

    - - {$func.deployment} + + {activeDeployment.$id}
    @@ -197,7 +173,6 @@ {/if} -
    All
    diff --git a/src/routes/console/project-[project]/functions/function-[function]/+page.ts b/src/routes/console/project-[project]/functions/function-[function]/+page.ts index d09a6161f..1d85970ce 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+page.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/+page.ts @@ -5,7 +5,7 @@ import { Dependencies, PAGE_LIMIT } from '$lib/constants'; import type { PageLoad } from './$types'; export const load: PageLoad = async ({ params, depends, url, route, parent }) => { - await parent(); + const data = await parent(); depends(Dependencies.DEPLOYMENTS); const page = getPage(url); const limit = getLimit(url, route, PAGE_LIMIT); @@ -14,6 +14,12 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => return { offset, limit, + activeDeployment: data.function.deployment + ? await sdk.forProject.functions.getDeployment( + params.function, + data.function.deployment + ) + : null, deploymentList: await sdk.forProject.functions.listDeployments(params.function, [ Query.limit(limit), Query.offset(offset), diff --git a/src/routes/console/project-[project]/functions/function-[function]/createCli.svelte b/src/routes/console/project-[project]/functions/function-[function]/createCli.svelte index 852456497..7dc455b19 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/createCli.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/createCli.svelte @@ -83,7 +83,7 @@ } - +

    Deploy your function using the Appwrite CLI by running the following command inside your function's folder. diff --git a/src/routes/console/project-[project]/functions/function-[function]/createGit.svelte b/src/routes/console/project-[project]/functions/function-[function]/createGit.svelte index be6d88241..4360458c1 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/createGit.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/createGit.svelte @@ -8,7 +8,7 @@ export let show = false; - + {#if $func.installationId && $func.providerRepositoryId}

    Deploy your function from the Git provider of your choice by following the steps below. @@ -19,52 +19,50 @@ class="link">documentation.

    - - - - Checkout your production branch. -
    - -
    -
    - - Add your changes -
    - -
    -
    - - Create a new commit -
    - -
    -
    - - Push your new commit -
    - -
    -
    - - A new deployment will be triggered automatically. - -
    -
    + + + Checkout your production branch. +
    + +
    +
    + + Add your changes +
    + +
    +
    + + Create a new commit +
    + +
    +
    + + Push your new commit +
    + +
    +
    + + A new deployment will be triggered automatically. + +
    {:else}
    diff --git a/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte b/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte index be24aece1..024ec8f6e 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte @@ -1,12 +1,5 @@ - +

    Manually deploy a function by uploading a zip file containing the source code and a relative path to the entry point. @@ -66,7 +65,7 @@ class="link">Learn more about function deployments.

    - + Build settings (optional) - - +

    + Overwrite your function configuration for a single deployment or save + commands for future use. +

    +
    -
    +

    Build {$func.name}

    {#if $deployment.status === 'building'} Building... {:else} - {$deployment.status} + {$deployment.status} {/if}
    diff --git a/src/routes/console/project-[project]/functions/function-[function]/execute.svelte b/src/routes/console/project-[project]/functions/function-[function]/execute.svelte index 26824e5f7..6302f5d97 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/execute.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/execute.svelte @@ -147,66 +147,68 @@ tooltip="Headers should contain alphanumeric characters (a-z, A-Z, and 0-9) and hyphens only (- and _)."> Headers +
    + + {#if headers} + {#each headers as [name, value], index} + + + + + + + + {/each} + {/if} + + +
    -
    - - {#if headers} - {#each headers as [name, value], index} - - - - - - - - {/each} - {/if} - - -
    +

    - Are you sure you want to disconnect {$func.name}? This will affect future deployments to - this function. + Are you sure you want to disconnect {$func.name}? This will affect future deployments + to this function.

    diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte index df75532d1..e29904e78 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte @@ -102,15 +102,6 @@ azure = 'Azure' } - function getProviderIcon(provider: string) { - switch (provider) { - case 'github': - return 'icon-github'; - default: - return ''; - } - } - function getRepositoryLink(repository: Models.ProviderRepository) { switch (repository.provider) { case 'github': @@ -218,21 +209,21 @@ {#if repository} -
    -
    - -
    -
    +
    + +
    {repository.name} {#if repository.private}
    -

    Last updated: {toLocaleDateTime(repository.pushedAt)}

    +

    + Last updated: {toLocaleDateTime(repository.pushedAt)} +

    diff --git a/src/routes/console/project-[project]/promoteVariableModal.svelte b/src/routes/console/project-[project]/promoteVariableModal.svelte index 785ef5f74..8216fed3a 100644 --- a/src/routes/console/project-[project]/promoteVariableModal.svelte +++ b/src/routes/console/project-[project]/promoteVariableModal.svelte @@ -16,8 +16,6 @@ onSubmit={() => { dispatch('promoted'); }} - icon="exclamation" - state="warning" headerDivider={false}> {isConflicting ? 'Overwrite global variable' : 'Promote variable'} diff --git a/src/routes/console/project-[project]/settings/GitDisconnectModal.svelte b/src/routes/console/project-[project]/settings/GitDisconnectModal.svelte index 34296e308..0e4f978a1 100644 --- a/src/routes/console/project-[project]/settings/GitDisconnectModal.svelte +++ b/src/routes/console/project-[project]/settings/GitDisconnectModal.svelte @@ -4,12 +4,10 @@ import Modal from '$lib/components/modal.svelte'; import { Dependencies } from '$lib/constants'; import Button from '$lib/elements/forms/button.svelte'; - import { base } from '$app/paths'; - import { app } from '$lib/stores/app'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { Query, type Models } from '@appwrite.io/console'; - import { Avatar } from '$lib/components'; + import { SvgIcon } from '$lib/components'; import { toLocaleDateTime } from '$lib/helpers/date'; export let showGitDisconnect: boolean; @@ -68,21 +66,17 @@ {#if functions.total}
    {#each functions.functions as func} -
    -
    - - +
    +
    + +
    +
    {func.name}
    +

    + Last deployed: {toLocaleDateTime(func.$updatedAt)} +

    - -

    - Last deployed: {toLocaleDateTime(func.$updatedAt)} -

    {/each}
    diff --git a/src/routes/console/project-[project]/updateVariables.svelte b/src/routes/console/project-[project]/updateVariables.svelte index f9232bf84..8a17fa61d 100644 --- a/src/routes/console/project-[project]/updateVariables.svelte +++ b/src/routes/console/project-[project]/updateVariables.svelte @@ -174,8 +174,9 @@ - {isGlobal ? 'Global Variables' : 'Environment Variables'} + + {isGlobal ? 'Global variables' : 'Environment variables'} + {#if isGlobal}

    Set the environment variables or secret keys that will be passed to all functions within @@ -216,7 +217,7 @@

    {@const sum = variableList.total} {#if sum} -
    +
    {#if conflictVariables.length > 0}

    @@ -227,7 +228,7 @@ {/if} a naming conflict with a global variable. View global variables in project settings - Key + Key Value - + {#each variableList.variables.slice(offset, offset + limit) as variable, i} @@ -251,16 +252,16 @@ globalVariable.key === variable.key ) !== undefined : false} - {#if isConflicting} -

    + class={isConflicting && hasConflictOnPage + ? 'u-flex u-gap-4 u-cross-center' + : ''}> + {#if isConflicting && hasConflictOnPage} +