diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1f4ef8396..aaac70173 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,11 +22,11 @@ jobs: # run: npm audit --audit-level low - name: Install dependencies run: npm ci - - name: Build Console - run: npm run build - name: Svelte Diagnostics run: npm run check - name: Linter run: npm run lint - name: Unit Tests run: npm test + - name: Build Console + run: npm run build diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 84c178cc4..b9724ff75 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/lib/components/empty.svelte b/src/lib/components/empty.svelte index 2c01f69fa..9dc0c6103 100644 --- a/src/lib/components/empty.svelte +++ b/src/lib/components/empty.svelte @@ -21,7 +21,8 @@ {#if single}
-
+
{/if} diff --git a/src/lib/elements/table/tableScroll.svelte b/src/lib/elements/table/tableScroll.svelte index 814fe00e5..6d30f8aff 100644 --- a/src/lib/elements/table/tableScroll.svelte +++ b/src/lib/elements/table/tableScroll.svelte @@ -2,11 +2,28 @@ import type { Action } from 'svelte/action'; export let isSticky = false; + let isOverflowing = false; - const hasOverflow: Action void> = (node, callback) => { + const hasOverflow: Action = (node) => { const observer = new ResizeObserver((entries) => { for (const entry of entries) { - callback(entry.contentRect.width < entry.target.scrollWidth); + let overflowing = false; + if (entry.contentRect.width < entry.target.scrollWidth) { + overflowing = true; + } + + const cols = entry.target.querySelectorAll('.table-thead-col'); + for (let i = 0; i < cols.length; i++) { + const col = cols[i]; + const cs = getComputedStyle(col); + const innerWidth = + col.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight); + if (innerWidth < 32) { + overflowing = true; + } + } + + isOverflowing = overflowing; } }); @@ -18,12 +35,10 @@ } }; }; - - let isOverflowing = false;
-
(isOverflowing = v)}> +
diff --git a/src/lib/helpers/style.ts b/src/lib/helpers/style.ts new file mode 100644 index 000000000..fef15c8cc --- /dev/null +++ b/src/lib/helpers/style.ts @@ -0,0 +1,16 @@ +type Direction = 'rtl' | 'ltr'; + +function isDirection(dir: string): dir is Direction { + return dir === 'rtl' || dir === 'ltr'; +} + +function parseDirection(dir: string): Direction { + return isDirection(dir) ? dir : 'ltr'; +} + +export function getElementDir(el: HTMLElement): Direction { + if (window.getComputedStyle) { + return parseDirection(window.getComputedStyle(el, null).getPropertyValue('direction')); + } + return parseDirection(el.style.direction); +} diff --git a/src/lib/helpers/waitUntil.ts b/src/lib/helpers/waitUntil.ts new file mode 100644 index 000000000..c3b3a85e4 --- /dev/null +++ b/src/lib/helpers/waitUntil.ts @@ -0,0 +1,14 @@ +export async function waitUntil(condition: () => boolean, timeout = 1000) { + return new Promise((resolve, reject) => { + const start = Date.now(); + const interval = setInterval(() => { + if (condition()) { + clearInterval(interval); + resolve(undefined); + } else if (Date.now() - start > timeout) { + clearInterval(interval); + reject(new Error('Timeout')); + } + }, 10); + }); +} diff --git a/src/lib/layout/logs.svelte b/src/lib/layout/logs.svelte index fcaabd80f..7b27b8b3d 100644 --- a/src/lib/layout/logs.svelte +++ b/src/lib/layout/logs.svelte @@ -17,7 +17,7 @@ function isDeployment(data: Models.Deployment | Models.Execution): data is Models.Deployment { if ('buildId' in data) { selectedTab = 'logs'; - rawData = `${sdk.forConsole.client.config.endpoint}/functions/${$log.func.$id}/deployment/${$log.data.$id}?mode=admin&project=${$page.params.project}`; + rawData = `${sdk.forConsole.client.config.endpoint}/functions/${$log.func.$id}/deployments/${$log.data.$id}?mode=admin&project=${$page.params.project}`; return true; } } @@ -25,7 +25,7 @@ function isExecution(data: Models.Deployment | Models.Execution): data is Models.Execution { if ('trigger' in data) { selectedTab = 'response'; - rawData = `${sdk.forConsole.client.config.endpoint}/functions/${$log.func.$id}/execution/${$log.data.$id}?mode=admin&project=${$page.params.project}`; + rawData = `${sdk.forConsole.client.config.endpoint}/functions/${$log.func.$id}/executions/${$log.data.$id}?mode=admin&project=${$page.params.project}`; return true; } } diff --git a/src/lib/stores/oauth-providers.ts b/src/lib/stores/oauth-providers.ts index 8047d6bdb..40bcff26a 100644 --- a/src/lib/stores/oauth-providers.ts +++ b/src/lib/stores/oauth-providers.ts @@ -7,6 +7,7 @@ import Okta from '../../routes/console/project-[project]/auth/oktaOAuth.svelte'; import Auth0 from '../../routes/console/project-[project]/auth/auth0OAuth.svelte'; import Authentik from '../../routes/console/project-[project]/auth/authentikOAuth.svelte'; import GitLab from '../../routes/console/project-[project]/auth/gitlabOAuth.svelte'; +import Google from '../../routes/console/project-[project]/auth/googleOAuth.svelte'; import Main from '../../routes/console/project-[project]/auth/mainOAuth.svelte'; export type Provider = Models.Provider & { @@ -81,6 +82,7 @@ const setProviders = (project: Models.Project): Provider[] => { break; case 'google': docs = 'https://support.google.com/googleapi/answer/6158849'; + component = Google; break; case 'linkedin': docs = 'https://developer.linkedin.com/'; 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/project-[project]/auth/gitlabOAuth.svelte b/src/routes/console/project-[project]/auth/gitlabOAuth.svelte index 2b5aea8a6..934d73801 100644 --- a/src/routes/console/project-[project]/auth/gitlabOAuth.svelte +++ b/src/routes/console/project-[project]/auth/gitlabOAuth.svelte @@ -81,7 +81,7 @@ disabled={(secret === provider.secret && enabled === provider.enabled && appId === provider.appId) || - !(appId && clientSecret && endpoint)} + !(appId && clientSecret)} submit>Update diff --git a/src/routes/console/project-[project]/auth/googleOAuth.svelte b/src/routes/console/project-[project]/auth/googleOAuth.svelte new file mode 100644 index 000000000..c8fd0390b --- /dev/null +++ b/src/routes/console/project-[project]/auth/googleOAuth.svelte @@ -0,0 +1,82 @@ + + + + {provider.name} OAuth2 Settings + +

+ To use {provider.name} authentication in your application, first fill in this form. For more + info you can + visit the docs. +

+ + + + + To complete the setup, create an OAuth2 client ID with "Web application" as the + application type, then add this redirect URI to your {provider.name} configuration. + +
+

URI

+ +
+
+ + + + +
diff --git a/src/routes/console/project-[project]/auth/settings/+page.svelte b/src/routes/console/project-[project]/auth/settings/+page.svelte index eba59cea4..42f640d07 100644 --- a/src/routes/console/project-[project]/auth/settings/+page.svelte +++ b/src/routes/console/project-[project]/auth/settings/+page.svelte @@ -1,17 +1,17 @@ - + {#each $columns as column} {#if column.show} @@ -54,4 +54,4 @@ {/each} -
+ diff --git a/src/routes/console/project-[project]/databases/table.svelte b/src/routes/console/project-[project]/databases/table.svelte index 401364401..ac63aa184 100644 --- a/src/routes/console/project-[project]/databases/table.svelte +++ b/src/routes/console/project-[project]/databases/table.svelte @@ -3,13 +3,13 @@ import { page } from '$app/stores'; import { Id } from '$lib/components'; import { - Table, TableBody, TableCell, TableCellHead, TableCellText, TableHeader, - TableRowLink + TableRowLink, + TableScroll } from '$lib/elements/table'; import { toLocaleDateTime } from '$lib/helpers/date'; import type { PageData } from './$types'; @@ -19,7 +19,7 @@ const projectId = $page.params.project; - + {#each $columns as column} {#if column.show} @@ -55,4 +55,4 @@ {/each} -
+ 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 4bf39c827..119a813a4 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/+page.svelte @@ -32,6 +32,7 @@ import type { PageData } from './$types'; import Delete from './delete.svelte'; import Create from './create.svelte'; + import Rebuild from './rebuild.svelte'; import Activate from './activate.svelte'; import { browser } from '$app/environment'; import { sdk } from '$lib/stores/sdk'; @@ -44,6 +45,7 @@ let showDropdown = []; let showDelete = false; let showActivate = false; + let showRebuild = false; let selectedDeployment: Models.Deployment = null; @@ -51,6 +53,10 @@ invalidate(Dependencies.DEPLOYMENTS); } + function handleRebuild() { + invalidate(Dependencies.DEPLOYMENTS); + } + $: activeDeployment = data.deployments.deployments.find((d) => d.$id === $func?.deployment); if (browser) { @@ -215,6 +221,17 @@ }}> Activate + {#if 'failed' === deployment.status} + { + selectedDeployment = deployment; + showRebuild = true; + showDropdown = []; + }}> + Retry Build + + {/if} { @@ -281,4 +298,5 @@ {#if selectedDeployment} + {/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/create.svelte b/src/routes/console/project-[project]/functions/function-[function]/create.svelte index 806ff23ca..4d65e044b 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/create.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/create.svelte @@ -62,10 +62,10 @@ function setCodeSnippets(lang: string) { return { Unix: { - code: `appwrite functions createDeployment \\ - --functionId=${functionId} \\ - --entrypoint='index.${lang}' \\ - --code="." \\ + code: `appwrite functions createDeployment \\ + --functionId=${functionId} \\ + --entrypoint='index.${lang}' \\ + --code="." \\ --activate=true`, language: 'bash' }, diff --git a/src/routes/console/project-[project]/functions/function-[function]/header.svelte b/src/routes/console/project-[project]/functions/function-[function]/header.svelte index c878a4b00..f48bc5324 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/header.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/header.svelte @@ -40,7 +40,9 @@ {$func?.name} - Function ID + {#if $func?.$id} + {$func.$id} + {/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/rebuild.svelte b/src/routes/console/project-[project]/functions/function-[function]/rebuild.svelte new file mode 100644 index 000000000..a3d1b4e1d --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/rebuild.svelte @@ -0,0 +1,46 @@ + + + + Retry build +

Are you sure you want to retry building this deployment?

+ + + + +
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte index 94aadbc6c..85f8265db 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte @@ -1,520 +1,25 @@ - -
-
- technology -
-
- {$func.name} - -

{$func.runtime}

-
-
- -
-
-

Function ID: {$func.$id}

-

Created at: {toLocaleDateTime($func.$createdAt)}

-

Updated at: {toLocaleDateTime($func.$updatedAt)}

-
-
-
- - - - -
- -
- - Name - - -
    - -
-
- - - - -
-
- -
- - Execute Access -

- Choose who can execute this function using the client API. For more information, - check out the - Permissions Guide - . -

- - - - - - - -
-
- + + + - -
- - Schedule -

- Set a Cron schedule to trigger your function. Leave blank for no schedule. - More details on Cron syntax here. -

- - - - - - - - - -
-
- - - Variables -

Set the variables (or secret keys) that will be passed to your function at runtime.

- -
- - -
- {@const limit = 10} - {@const sum = data.variables.total} - {#if sum} -
- - - Key - Value - - - - {#each data.variables.variables.slice(offset, offset + limit) as variable, i} - - - - {variable.key} - - - - - - - - - - - { - selectedVar = variable; - showVariablesDropdown[i] = false; - showVariablesModal = true; - }}> - Edit - - { - handleVariableDeleted(variable); - showVariablesDropdown[i] = false; - }}> - Delete - - - - - - {/each} - -
- -
-

Total variables: {sum}

- -
-
- {:else} - (showVariablesModal = !showVariablesModal)}> - Create a variable to get started - - {/if} -
-
- -
- - Timeout -

- Limit the execution time of your function. Maximum value is 900 seconds (15 - minutes). -

- - - - - - - - - -
-
- - - Delete Function -

- The function will be permanently deleted, including all deployments associated with it. - This action is irreversible. -

- - - -
{$func.name}
-
-

Last Updated: {toLocaleDateTime($func.$updatedAt)}

-
-
- - - - -
+ + + +
- - -{#if showVariablesModal} - -{/if} -{#if showVariablesUpload} - -{/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/dangerZone.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/dangerZone.svelte new file mode 100644 index 000000000..d5ec9fbf4 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/dangerZone.svelte @@ -0,0 +1,33 @@ + + + + Delete Function +

+ The function will be permanently deleted, including all deployments associated with it. This + action is irreversible. +

+ + + +
{$func.name}
+
+

Last Updated: {toLocaleDateTime($func.$updatedAt)}

+
+
+ + + + +
+ + diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/delete.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/deleteModal.svelte similarity index 100% rename from src/routes/console/project-[project]/functions/function-[function]/settings/delete.svelte rename to src/routes/console/project-[project]/functions/function-[function]/settings/deleteModal.svelte diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/executeFunction.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/executeFunction.svelte new file mode 100644 index 000000000..194b18bed --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/executeFunction.svelte @@ -0,0 +1,36 @@ + + + +
+
+ technology +
+
+ {$func.name} + +

{$func.runtime}

+
+
+ +
+
+

Function ID: {$func.$id}

+

Created at: {toLocaleDateTime($func.$createdAt)}

+

Updated at: {toLocaleDateTime($func.$updatedAt)}

+
+
+
+ + + + +
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte new file mode 100644 index 000000000..431d12e5f --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte @@ -0,0 +1,66 @@ + + +
+ + Name + + +
    + +
+
+ + + + +
+
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte new file mode 100644 index 000000000..369f936a9 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte @@ -0,0 +1,78 @@ + + +
+ + Execute Access +

+ Choose who can execute this function using the client API. For more information, check + out the + Permissions Guide + . +

+ + + + + + + +
+
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte new file mode 100644 index 000000000..699b727b1 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte @@ -0,0 +1,71 @@ + + +
+ + Schedule +

+ Set a Cron schedule to trigger your function. Leave blank for no schedule. + More details on Cron syntax here. +

+ + + + + + + + + +
+
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte new file mode 100644 index 000000000..94489f929 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte @@ -0,0 +1,66 @@ + + +
+ + Timeout +

Limit the execution time of your function. Maximum value is 900 seconds (15 minutes).

+ + + + + + + + + +
+
diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateVariables.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateVariables.svelte new file mode 100644 index 000000000..c3915babc --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateVariables.svelte @@ -0,0 +1,233 @@ + + + + Variables +

Set the variables (or secret keys) that will be passed to your function at runtime.

+ +
+ + +
+ {@const limit = 10} + {@const sum = variableList.total} + {#if sum} +
+ + + Key + Value + + + + {#each variableList.variables.slice(offset, offset + limit) as variable, i} + + + + {variable.key} + + + + + + + + + + + { + selectedVar = variable; + showVariablesDropdown[i] = false; + showVariablesModal = true; + }}> + Edit + + { + handleVariableDeleted(variable); + showVariablesDropdown[i] = false; + }}> + Delete + + + + + + {/each} + +
+ +
+

Total variables: {sum}

+ +
+
+ {:else} + (showVariablesModal = !showVariablesModal)}> + Create a variable to get started + + {/if} +
+
+ +{#if showVariablesModal} + +{/if} +{#if showVariablesUpload} + +{/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/uploadVariables.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/uploadVariablesModal.svelte similarity index 100% rename from src/routes/console/project-[project]/functions/function-[function]/settings/uploadVariables.svelte rename to src/routes/console/project-[project]/functions/function-[function]/settings/uploadVariablesModal.svelte diff --git a/src/routes/console/project-[project]/overview/platforms/wizard/flutter/step1.svelte b/src/routes/console/project-[project]/overview/platforms/wizard/flutter/step1.svelte index ca0c62f7e..f8e2936ff 100644 --- a/src/routes/console/project-[project]/overview/platforms/wizard/flutter/step1.svelte +++ b/src/routes/console/project-[project]/overview/platforms/wizard/flutter/step1.svelte @@ -65,7 +65,7 @@ }, [Platform.Web]: { name: 'My Web App', - hostname: 'com.company.appname', + hostname: 'localhost', tooltip: 'The hostname that your website will use to interact with the Appwrite APIs in production or development environments. No protocol or port number required.' }, diff --git a/src/routes/console/project-[project]/overview/platforms/wizard/web/step2.svelte b/src/routes/console/project-[project]/overview/platforms/wizard/web/step2.svelte index 9699669ff..bff1c05dc 100644 --- a/src/routes/console/project-[project]/overview/platforms/wizard/web/step2.svelte +++ b/src/routes/console/project-[project]/overview/platforms/wizard/web/step2.svelte @@ -35,8 +35,12 @@ {#if method === Method.NPM}

- Use NPM (node package manager) from your command line to add Appwrite SDK to your project. + Use NPM (node package manager) from your command line to add Appwrite SDK + to your project.

diff --git a/src/routes/console/project-[project]/settings/+page.svelte b/src/routes/console/project-[project]/settings/+page.svelte index a03e4e6e2..60cb06450 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'; @@ -16,9 +24,12 @@ 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; @@ -26,6 +37,7 @@ onMount(async () => { name ??= $project.name; + teamId ??= $project.teamId; }); async function updateName() { @@ -163,7 +175,10 @@ Services -

Choose services you wish to enable or disable.

+

+ Choose services you wish to enable or disable for the client API. When disabled, the + services are not accessible to client SDKs but remain accessible to server SDKs. +

  • @@ -192,7 +207,30 @@ + + Transfer project +

    Transfer your project to another organization that you own.

    + + + ({ + value: team.$id, + label: team.name + }))} /> + + + + + + +
    Delete Project @@ -220,3 +258,9 @@ toggleAllServices(false)} bind:show={showDisableAll} /> toggleAllServices(true)} bind:show={showEnableAll} /> +{#if teamId} + t.$id == teamId).name} + bind:show={showTransfer} /> +{/if} \ No newline at end of file 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. +

    + + + + + +
    diff --git a/src/routes/console/project-[project]/settings/webhooks/+page.svelte b/src/routes/console/project-[project]/settings/webhooks/+page.svelte index fde1c291e..1e22b243a 100644 --- a/src/routes/console/project-[project]/settings/webhooks/+page.svelte +++ b/src/routes/console/project-[project]/settings/webhooks/+page.svelte @@ -6,13 +6,13 @@ import { Button } from '$lib/elements/forms'; import { Pill } from '$lib/elements'; import { - Table, TableBody, TableRowLink, TableCellHead, TableCell, TableCellText, - TableHeader + TableHeader, + TableScroll } from '$lib/elements/table'; import { Container } from '$lib/layout'; import { wizard } from '$lib/stores/wizard'; @@ -46,10 +46,10 @@
    {#if data.webhooks.total} - + - Name - POST URL + Name + POST URL Events @@ -57,7 +57,7 @@ -
    +
    {webhook.name} {#if webhook.security === false} SLL/TLS disabled @@ -69,7 +69,7 @@ {/each} -
    + {:else} {$bucket?.name} - Bucket ID + {#if $bucket?.$id} + {$bucket.$id} + {/if} diff --git a/tests/unit/components/tab.test.ts b/tests/unit/components/tab.test.ts index a0d7b0dcb..9e75e25e8 100644 --- a/tests/unit/components/tab.test.ts +++ b/tests/unit/components/tab.test.ts @@ -6,12 +6,12 @@ import { Tab } from '../../../src/lib/components'; test('shows tab', () => { const { getByRole } = render(Tab); - expect(getByRole('button')).toBeInTheDocument(); + expect(getByRole('tab')).toBeInTheDocument(); }); test('shows tab - is selected', () => { const { getByRole } = render(Tab, { selected: true }); - expect(getByRole('button')).toHaveClass('is-selected'); + expect(getByRole('tab')).toHaveClass('is-selected'); }); test('shows tab - is link', () => { @@ -23,7 +23,7 @@ test('shows tab - is link', () => { test('shows tab - on:click', async () => { const { getByRole, component } = render(Tab); - const tab = getByRole('button'); + const tab = getByRole('tab'); const callback = vi.fn(); component.$on('click', callback);