diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 2b7a0d80b..06fd80505 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -131,6 +131,7 @@ export enum Submit { ProjectCreate = 'submit_project_create', ProjectDelete = 'submit_project_delete', ProjectUpdateName = 'submit_project_update_name', + ProjectUpdateTeam = 'submit_project_update_team', ProjectService = 'submit_project_service', MemberCreate = 'submit_member_create', MemberDelete = 'submit_member_delete', diff --git a/src/routes/auth/oauth2/failure/+page.svelte b/src/routes/auth/oauth2/failure/+page.svelte index 359c6ffdc..928ad82c4 100644 --- a/src/routes/auth/oauth2/failure/+page.svelte +++ b/src/routes/auth/oauth2/failure/+page.svelte @@ -2,20 +2,56 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; import { Heading } from '$lib/components'; - import { onMount } from 'svelte'; - onMount(async () => { - const project = $page.url.searchParams.get('project'); - if (project) { - await goto(`appwrite-callback-${project}://${$page.url.search}`); + const project = $page.url.searchParams.get('project'); + const link = `appwrite-callback-${project}://${$page.url.search}`; + + const redirect = new Promise((resolve, reject) => { + if (!project) { + reject('no-project'); } + // this timeout is needed because goto does not + // throw an exception if the redirect does not work + setTimeout(() => reject('timeout'), 500); + // goto will resolve on successful redirect + goto(link).then(resolve); }); -Missing Redirect URL -

- Your OAuth login flow is missing a proper redirect URL. Please check the - OAuth docs - and send request for new session with a valid callback URL. -

+{#await redirect then} +
+
+ Login failed +

You will be automatically redirected back to your app shortly.

+

+ If you are not redirected, please click on the following + link. +

+
+
+{:catch} +
+
+ Missing Redirect URL +

+ Your OAuth login flow is missing a proper redirect URL. Please check the + OAuth docs + and send request for new session with a valid callback URL. +

+
+
+{/await} + + diff --git a/src/routes/auth/oauth2/success/+page.svelte b/src/routes/auth/oauth2/success/+page.svelte index 359c6ffdc..b67ad0ce6 100644 --- a/src/routes/auth/oauth2/success/+page.svelte +++ b/src/routes/auth/oauth2/success/+page.svelte @@ -2,20 +2,56 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; import { Heading } from '$lib/components'; - import { onMount } from 'svelte'; - onMount(async () => { - const project = $page.url.searchParams.get('project'); - if (project) { - await goto(`appwrite-callback-${project}://${$page.url.search}`); + const project = $page.url.searchParams.get('project'); + const link = `appwrite-callback-${project}://${$page.url.search}`; + + const redirect = new Promise((resolve, reject) => { + if (!project) { + reject('no-project'); } + // this timeout is needed because goto does not + // throw an exception if the redirect does not work + setTimeout(() => reject('timeout'), 500); + // goto will resolve on successful redirect + goto(link).then(resolve); }); -Missing Redirect URL -

- Your OAuth login flow is missing a proper redirect URL. Please check the - OAuth docs - and send request for new session with a valid callback URL. -

+{#await redirect then} +
+
+ You're now logged in +

You will be automatically redirected back to your app shortly.

+

+ If you are not redirected, please click on the following + link. +

+
+
+{:catch} +
+
+ Missing Redirect URL +

+ Your OAuth login flow is missing a proper redirect URL. Please check the + OAuth docs + and send request for new session with a valid callback URL. +

+
+
+{/await} + + diff --git a/src/routes/console/organization-[organization]/+page.svelte b/src/routes/console/organization-[organization]/+page.svelte index 99d0e70eb..a5aaf20c9 100644 --- a/src/routes/console/organization-[organization]/+page.svelte +++ b/src/routes/console/organization-[organization]/+page.svelte @@ -11,6 +11,8 @@ import { wizard } from '$lib/stores/wizard'; import { isCloud } from '$lib/system'; import { page } from '$app/stores'; + import { services } from '$lib/stores/project-services'; + import type { Models } from '@appwrite.io/console'; export let data: PageData; @@ -41,6 +43,17 @@ return { name, icon }; }; + function allServiceDisabled(project: Models.Project): boolean { + let disabled = true; + services.load(project); + $services.list.forEach((service) => { + if (service.value) { + disabled = false; + } + }); + return disabled; + } + function filterPlatforms(platforms: { name: string; icon: string }[]) { return platforms.filter( (value, index, self) => index === self.findIndex((t) => t.name === value.name) @@ -75,6 +88,11 @@ {project.name} + {#if allServiceDisabled(project)} +

+

+ {/if} {@const platforms = filterPlatforms( project.platforms.map((platform) => getPlatformInfo(platform.type)) )} diff --git a/src/routes/console/project-[project]/settings/+page.svelte b/src/routes/console/project-[project]/settings/+page.svelte index cf8659329..699f12ddf 100644 --- a/src/routes/console/project-[project]/settings/+page.svelte +++ b/src/routes/console/project-[project]/settings/+page.svelte @@ -3,10 +3,18 @@ import { onMount } from 'svelte'; import { toLocaleDateTime } from '$lib/helpers/date'; import { addNotification } from '$lib/stores/notifications'; + import { organizationList } from '$lib/stores/organization'; import { project } from '../store'; import { services, type Service } from '$lib/stores/project-services'; import { CardGrid, CopyInput, Box, Heading } from '$lib/components'; - import { Button, Form, FormList, InputText, InputSwitch } from '$lib/elements/forms'; + import { + Button, + Form, + FormList, + InputText, + InputSwitch, + InputSelect + } from '$lib/elements/forms'; import { Container } from '$lib/layout'; import { invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -14,14 +22,22 @@ import { base } from '$app/paths'; import { page } from '$app/stores'; import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; + import EnableAllServices from './enableAllServices.svelte'; + import DisableAllServices from './disableAllServices.svelte'; + import Transfer from './transferProject.svelte'; let name: string = null; + let teamId: string = null; let showDelete = false; + let showTransfer = false; const endpoint = sdk.forConsole.client.config.endpoint; const projectId = $page.params.project; + let showDisableAll = false; + let showEnableAll = false; onMount(async () => { name ??= $project.name; + teamId ??= $project.teamId; }); async function updateName() { @@ -42,6 +58,50 @@ } } + async function toggleAllServices(status: boolean) { + if (status && !showEnableAll) { + showEnableAll = true; + return; + } + if (!status && !showDisableAll) { + showDisableAll = true; + return; + } + + try { + const path = '/projects/' + $project.$id + '/service/all'; + await sdk.forConsole.client.call( + 'PATCH', + new URL(sdk.forConsole.client.config.endpoint + path), + { + 'content-type': 'application/json' + }, + { + status: status + } + ); + invalidate(Dependencies.PROJECT); + addNotification({ + type: 'success', + message: + 'All services for ' + + $project.name + + ' has been ' + + (status ? 'enabled.' : 'disabled.') + }); + trackEvent(Submit.ProjectService); + } catch (error) { + addNotification({ + type: 'error', + message: error.message + }); + trackError(error, Submit.ProjectService); + } finally { + showDisableAll = false; + showEnableAll = false; + } + } + async function serviceUpdate(service: Service) { try { await sdk.forConsole.projects.updateServiceStatus( @@ -120,8 +180,18 @@ services are not accessible to client SDKs but remain accessible to server SDKs.

+ -
+
    {#each $services.list as service} + + Transfer project +

    Transfer your project to another organization that you own.

    + + + ({ + value: team.$id, + label: team.name + }))} /> + + + + + + +
    Delete Project @@ -163,3 +256,11 @@ + toggleAllServices(false)} bind:show={showDisableAll} /> + toggleAllServices(true)} bind:show={showEnableAll} /> +{#if teamId} + t.$id == teamId).name} + bind:show={showTransfer} /> +{/if} diff --git a/src/routes/console/project-[project]/settings/disableAllServices.svelte b/src/routes/console/project-[project]/settings/disableAllServices.svelte new file mode 100644 index 000000000..1cf11235e --- /dev/null +++ b/src/routes/console/project-[project]/settings/disableAllServices.svelte @@ -0,0 +1,19 @@ + + + + Disable all services +

    + Are you sure you want to disable all services? This will disable API requests to your + project. +

    + + + + +
    diff --git a/src/routes/console/project-[project]/settings/enableAllServices.svelte b/src/routes/console/project-[project]/settings/enableAllServices.svelte new file mode 100644 index 000000000..e3189a739 --- /dev/null +++ b/src/routes/console/project-[project]/settings/enableAllServices.svelte @@ -0,0 +1,16 @@ + + + + Enable all services +

    All project services will be enabled.

    + + + + +
    diff --git a/src/routes/console/project-[project]/settings/transferProject.svelte b/src/routes/console/project-[project]/settings/transferProject.svelte new file mode 100644 index 000000000..9e16d5611 --- /dev/null +++ b/src/routes/console/project-[project]/settings/transferProject.svelte @@ -0,0 +1,59 @@ + + + + Transfer project +

    Are you sure you want to transfer {$project.name} to {teamName}?

    +

    + Members who are not part of the destination organization must be invited to gain access to + this project. +

    + + + + + +