diff --git a/src/lib/components/organizationUsageLimits.svelte b/src/lib/components/organizationUsageLimits.svelte index 39ae9a1ea..8373b17b3 100644 --- a/src/lib/components/organizationUsageLimits.svelte +++ b/src/lib/components/organizationUsageLimits.svelte @@ -90,10 +90,14 @@ } if (selectedProjectsToDelete?.length) { - const projectsDeletionPromises = selectedProjectsToDelete.map((projectId) => ({ - projectId, - promise: sdk.forConsole.projects.delete({ projectId }) - })); + const projectsDeletionPromises = selectedProjectsToDelete.map((projectId) => { + const projectToDelete = projects.find((project) => project.$id === projectId); + + return { + projectId, + promise: sdk.forProject(projectToDelete.region, projectId).project.delete() + }; + }); try { const results = await Promise.allSettled( diff --git a/src/lib/constants.ts b/src/lib/constants.ts index be661eefb..d917925ae 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -112,8 +112,8 @@ export const defaultScopes: string[] = [ 'projects.write', 'locale.read', 'avatars.read', - 'execution.read', - 'execution.write', + 'executions.read', + 'executions.write', 'targets.read', 'targets.write', 'subscribers.write', @@ -339,17 +339,31 @@ export const scopes: ScopeDefinition[] = [ icon: 'lightning-bolt' }, { - scope: 'execution.read', + scope: 'executions.read', description: "Access to read your project's execution logs", category: 'Functions', icon: 'lightning-bolt' }, { - scope: 'execution.write', + scope: 'executions.write', description: "Access to execute your project's functions", category: 'Functions', icon: 'lightning-bolt' }, + { + scope: 'execution.read', + description: "Access to read your project's execution logs", + category: 'Functions', + icon: 'lightning-bolt', + deprecated: true + }, + { + scope: 'execution.write', + description: "Access to execute your project's functions", + category: 'Functions', + icon: 'lightning-bolt', + deprecated: true + }, { scope: 'targets.read', description: "Access to read your project's messaging targets", diff --git a/src/lib/stores/oauth-providers.ts b/src/lib/stores/oauth-providers.ts index 11191dbaf..1a2143a17 100644 --- a/src/lib/stores/oauth-providers.ts +++ b/src/lib/stores/oauth-providers.ts @@ -1,13 +1,5 @@ import type { Component } from 'svelte'; -import Apple from '$routes/(console)/project-[region]-[project]/auth/(providers)/appleOAuth.svelte'; -import Auth0 from '$routes/(console)/project-[region]-[project]/auth/(providers)/auth0OAuth.svelte'; -import Authentik from '$routes/(console)/project-[region]-[project]/auth/(providers)/authentikOAuth.svelte'; -import GitLab from '$routes/(console)/project-[region]-[project]/auth/(providers)/gitlabOAuth.svelte'; -import Google from '$routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte'; import Main from '$routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte'; -import Microsoft from '$routes/(console)/project-[region]-[project]/auth/(providers)/microsoftOAuth.svelte'; -import Oidc from '$routes/(console)/project-[region]-[project]/auth/(providers)/oidcOAuth.svelte'; -import Okta from '$routes/(console)/project-[region]-[project]/auth/(providers)/oktaOAuth.svelte'; export type Provider = { name: string; @@ -28,19 +20,19 @@ export const oAuthProviders: Record = { name: 'Apple', icon: 'apple', docs: 'https://developer.apple.com/sign-in-with-apple/', - component: Apple + component: Main }, auth0: { name: 'Auth0', icon: 'auth0', docs: 'https://auth0.com/developers', - component: Auth0 + component: Main }, authentik: { name: 'Authentik', icon: 'authentik', docs: 'https://goauthentik.io/integrations/sources/oauth/', - component: Authentik + component: Main }, autodesk: { name: 'Autodesk', @@ -108,6 +100,12 @@ export const oAuthProviders: Record = { docs: 'https://www.figma.com/developers/api#access-tokens', component: Main }, + fusionauth: { + name: 'FusionAuth', + icon: 'fusionauth', + docs: 'https://fusionauth.io/docs/apis/identity-providers/oauth2', + component: Main + }, github: { name: 'GitHub', icon: 'github', @@ -125,21 +123,33 @@ export const oAuthProviders: Record = { name: 'GitLab', icon: 'gitlab', docs: 'https://docs.gitlab.com/ee/api/', - component: GitLab + component: Main }, google: { name: 'Google', icon: 'google', docs: 'https://support.google.com/googleapi/answer/6158849', - component: Google + component: Main }, googleImagine: { name: 'Google', icon: 'google', docs: 'https://support.google.com/googleapi/answer/6158849', - component: Google, + component: Main, internal: true }, + keycloak: { + name: 'Keycloak', + icon: 'keycloak', + docs: 'https://www.keycloak.org/securing-apps/oidc-layers', + component: Main + }, + kick: { + name: 'Kick', + icon: 'kick', + docs: 'https://docs.kick.com/getting-started/using-the-api', + component: Main + }, linkedin: { name: 'LinkedIn', icon: 'linkedin', @@ -150,7 +160,7 @@ export const oAuthProviders: Record = { name: 'Microsoft', icon: 'microsoft', docs: 'https://developer.microsoft.com/en-us/', - component: Microsoft + component: Main }, notion: { name: 'Notion', @@ -162,13 +172,13 @@ export const oAuthProviders: Record = { name: 'OIDC', icon: 'oidc', docs: 'https://openid.net/connect/faq/', - component: Oidc + component: Main }, okta: { name: 'Okta', icon: 'okta', docs: 'https://developer.okta.com', - component: Okta + component: Main }, paypal: { name: 'Paypal', @@ -176,7 +186,7 @@ export const oAuthProviders: Record = { docs: 'https://developer.paypal.com/docs/api/overview/', component: Main }, - paypalsandbox: { + paypalSandbox: { name: 'Paypal Sandbox', icon: 'paypal', docs: 'https://developer.paypal.com/docs/api/overview/', @@ -248,12 +258,6 @@ export const oAuthProviders: Record = { docs: 'https://developer.yahoo.com/oauth2/guide/flows_authcode/', component: Main }, - yammer: { - name: 'Yammer', - icon: 'yammer', - docs: 'https://developer.yammer.com/docs/oauth-2', - component: Main - }, yandex: { name: 'Yandex', icon: 'yandex', diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index 987d1bca6..d8e9d5be8 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -148,6 +148,52 @@ ]; } + function createBandwidthProgressData( + totalBytes: number, + realtimeBytes: number, + maxGB: number + ): Array<{ size: number; color: string; tooltip?: { title: string; label: string } }> { + if (maxGB <= 0) return []; + + const maxBytes = maxGB * 1000 * 1000 * 1000; + const percentage = Math.min((totalBytes / maxBytes) * 100, 100); + const showRealtimeSegment = realtimeBytes > 0 && realtimeBytes <= totalBytes; + const realtimePortion = showRealtimeSegment ? realtimeBytes : 0; + const regularPortion = Math.max(0, totalBytes - realtimePortion); + const regularSize = humanFileSize(regularPortion); + const realtimeSize = humanFileSize(realtimePortion); + + const segments: Array<{ + size: number; + color: string; + tooltip?: { title: string; label: string }; + }> = []; + + if (regularPortion > 0) { + segments.push({ + size: regularPortion, + color: 'var(--bgcolor-neutral-invert)', + tooltip: { + title: `${percentage.toFixed(0)}% used`, + label: `Bandwidth: ${regularSize.value} ${regularSize.unit}` + } + }); + } + + if (realtimePortion > 0) { + segments.push({ + size: realtimePortion, + color: 'var(--bgcolor-neutral-invert-weak)', + tooltip: { + title: 'Realtime bandwidth', + label: `${realtimeSize.value} ${realtimeSize.unit}` + } + }); + } + + return segments; + } + function getResource(resources: Array | undefined, resourceId: string) { return resources?.find((resource) => resource.resourceId === resourceId); } @@ -278,9 +324,13 @@ const projects = (currentAggregation?.breakdown || []).map((projectData) => { const resources = projectData.resources || []; const bandwidth = getResource(resources, 'bandwidth'); + const realtimeBandwidth = getResource(resources, 'realtimeBandwidth'); const storage = getResource(resources, 'storage'); const authPhone = getResource(resources, 'authPhone'); + const bandwidthValue = bandwidth?.value || 0; + const realtimeBandwidthValue = realtimeBandwidth?.value || 0; + return { id: `project-${projectData.$id}`, expandable: true, @@ -305,10 +355,31 @@ ), priceFormatter: ({ amount }) => formatCurrency(amount), progressFactory: ({ value, planLimit, hasLimit }) => - hasLimit ? createStorageProgressData(value, planLimit || 0) : [], + hasLimit + ? createBandwidthProgressData( + value, + realtimeBandwidthValue, + planLimit || 0 + ) + : [], maxFactory: ({ planLimit, hasLimit }) => hasLimit ? (planLimit || 0) * 1000 * 1000 * 1000 : null }), + ...(realtimeBandwidthValue > bandwidthValue + ? [ + createRow({ + id: 'realtime-bandwidth', + label: 'Realtime bandwidth', + resource: realtimeBandwidth, + usageFormatter: ({ value }) => { + const size = humanFileSize(value); + return `${size.value} ${size.unit}`; + }, + priceFormatter: ({ amount }) => formatCurrency(amount), + includeProgress: false + }) + ] + : []), // standard resources (numeric) createResourceRow( 'users', @@ -379,15 +450,6 @@ getResource(resources, 'realtimeMessages'), currentPlan?.realtimeMessages ), - createRow({ - id: 'realtime-bandwidth', - label: 'Realtime bandwidth', - resource: getResource(resources, 'realtimeBandwidth'), - usageFormatter: ({ value }) => - humanFileSize(value).value + humanFileSize(value).unit, - priceFormatter: ({ amount }) => formatCurrency(amount), - includeProgress: false - }), createRow({ id: 'sms', label: 'Phone OTP', diff --git a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte index 4a743e4e7..874cc23ec 100644 --- a/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/usage/[[invoice]]/+page.svelte @@ -584,7 +584,7 @@ color: '#68A3FE', tooltip: { title: 'Backups storage', - label: `${Math.round(bytesToSize(data.organizationUsage.backupsStorageTotal, 'GB') * 100) / 100}MB` + label: `${Math.round(bytesToSize(data.organizationUsage.backupsStorageTotal, 'GB') * 100) / 100}GB` } }, { diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/appleOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/appleOAuth.svelte deleted file mode 100644 index 0554e9598..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/appleOAuth.svelte +++ /dev/null @@ -1,86 +0,0 @@ - - - -

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

- - - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/auth0OAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/auth0OAuth.svelte deleted file mode 100644 index 9b114e740..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/auth0OAuth.svelte +++ /dev/null @@ -1,91 +0,0 @@ - - - - - To use {provider.name} authentication in your application, first fill in this form. For more info - you can - visit the docs. - - - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - - diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/authentikOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/authentikOAuth.svelte deleted file mode 100644 index 19a3b40c6..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/authentikOAuth.svelte +++ /dev/null @@ -1,95 +0,0 @@ - - - -

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

- - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/gitlabOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/gitlabOAuth.svelte deleted file mode 100644 index fc46679bd..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/gitlabOAuth.svelte +++ /dev/null @@ -1,84 +0,0 @@ - - - -

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

- - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte deleted file mode 100644 index d5457b28b..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte +++ /dev/null @@ -1,84 +0,0 @@ - - - - {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. - - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte index 365782e6b..acc3a90c5 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte @@ -1,35 +1,204 @@ @@ -49,21 +220,157 @@ target="_blank" rel="noopener noreferrer">visit the docs.

+ - - + + {#if appIdParam} + + {/if} + + {#each basicDetailParams as param} + + {/each} + + {#if advancedDetailParams.length > 0} + + + {#each advancedDetailParams as param} + + {/each} + + + {/if} + + {#if secretParams.length > 0} + {#if !showSecretInput} +
+ (showSecretInput = true)}> + Update {secretCardTitle} + +
+ {:else} + + + + + {secretCardTitle} + + + + {#if secretParams.length === 1} + This field is write-only. Enter a new value to update it. + {:else} + These fields are write-only. Enter new values to update them. + {/if} + + + + + + + {#each secretParams as param} + {#if isP8Param(param.$id)} +
+
+ {primaryName(param.name)} +
+ +
+
+ {#if p8PasteMode[param.$id]} + + {:else} + + + handleP8FileUpload(param.$id, event)} /> + {/if} +
+ {:else} + + {/if} + {/each} +
+
+
+ {/if} + {/if} + To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. @@ -72,12 +379,52 @@ value={`${getApiEndpoint(page.params.region)}/account/sessions/oauth2/callback/${provider.key}/${projectId}`} /> - +
+ + diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/microsoftOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/microsoftOAuth.svelte deleted file mode 100644 index e6679ab2e..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/microsoftOAuth.svelte +++ /dev/null @@ -1,90 +0,0 @@ - - - -

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

- - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcOAuth.svelte deleted file mode 100644 index 1360c4b72..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcOAuth.svelte +++ /dev/null @@ -1,133 +0,0 @@ - - - -

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

- - - - - - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/oktaOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/oktaOAuth.svelte deleted file mode 100644 index 57f5c9e2c..000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/oktaOAuth.svelte +++ /dev/null @@ -1,109 +0,0 @@ - - - -

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

- - - - - - - - To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. - - - - - - -
diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte index c086f5b55..3596e8d7e 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte @@ -30,6 +30,8 @@ let { data }: PageProps = $props(); /** Must stay derived from `data` so OAuth/auth toggles reflect `invalidate(Dependencies.PROJECT)` without a full reload. */ const project = $derived(data.project); + const resolvedOAuthProviders = $derived(data.oauthProviders); + const consoleParamsMap = $derived(data.consoleParamsMap); let showProvider = $state(false); let selectedProvider: Models.AuthProvider | null = $state(null); @@ -152,7 +154,11 @@ Enable the authentication methods you wish to use. - + - - + +
{#each $authMethods.list as box} - +
{/if} - +
{/each} - +
@@ -200,8 +206,8 @@ OAuth2 Providers
    - {#each project.oAuthProviders - .filter((p) => p.name !== 'Mock') + {#each resolvedOAuthProviders + .filter((p) => p.key !== 'mock' && p.name !== 'Mock') .sort( (a, b) => (a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1) ) as provider} {@const oAuthProvider = oAuthProviders[provider.key]} {#if oAuthProvider && !oAuthProvider.internal} @@ -248,6 +254,7 @@ { selectedProvider = null; showProvider = false; @@ -271,3 +278,22 @@ + + diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts new file mode 100644 index 000000000..0aa058f7e --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts @@ -0,0 +1,52 @@ +import { Dependencies } from '$lib/constants'; +import { oAuthProviders } from '$lib/stores/oauth-providers'; +import { sdk } from '$lib/stores/sdk'; +import type { Models, Models as ConsoleModels } from '@appwrite.io/console'; +import type { PageLoad } from './$types'; + +/** Extract the appId equivalent from a typed OAuth2 provider model. */ +function extractAppId(p: Record): string { + return (p['clientId'] ?? + p['appId'] ?? + p['oauthClientId'] ?? + p['oauth2ClientId'] ?? + p['applicationId'] ?? + p['serviceId'] ?? + p['apiKey'] ?? + p['publicKey'] ?? + p['appKey'] ?? + p['keyString'] ?? + p['customerKey'] ?? + p['key'] ?? + '') as string; +} + +export const load: PageLoad = async ({ depends, params }) => { + depends(Dependencies.PROJECT); + + const [providerList, consoleProviderList] = await Promise.all([ + sdk.forProject(params.region, params.project).project.listOAuth2Providers(), + sdk.forConsole.console.listOAuth2Providers() + ]); + + const consoleParamsMap = new Map(); + for (const cp of consoleProviderList.oAuth2Providers) { + consoleParamsMap.set(cp.$id, cp.parameters ?? []); + } + + const oauthProviders: Models.AuthProvider[] = providerList.providers + .filter((p) => p.$id !== 'mock') + .map((p) => { + const raw = p as unknown as Record; + return { + ...raw, + key: p.$id, + name: oAuthProviders[p.$id]?.name ?? p.$id, + appId: extractAppId(raw), + secret: '', + enabled: p.enabled + }; + }); + + return { oauthProviders, consoleParamsMap }; +}; diff --git a/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts b/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts index 6249ef31e..0c2195502 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts +++ b/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts @@ -7,10 +7,12 @@ import { sdk } from '$lib/stores/sdk'; import { OAuthProvider, type Models } from '@appwrite.io/console'; type Args = { + region: string; projectId: string; provider: Models.AuthProvider; - appId: string; + appId: string | null; secret: string; + details: Record; enabled: boolean; }; @@ -19,11 +21,323 @@ type Return = { message?: string; }; -export async function updateOAuth({ +function parseSecret(secret: string) { + if (!secret) return {}; + + try { + return JSON.parse(secret); + } catch { + return {}; + } +} + +async function updateProjectOAuth({ + region, projectId, provider, appId, secret, + details, + enabled +}: Args) { + const projectSdk = sdk.forProject(region, projectId).project; + const parsedSecret = parseSecret(secret); + + const getAppId = (): string => appId ?? ''; + const getDetail = (key: string): string => details[key] ?? ''; + const getSecret = (key?: string): string | undefined => { + if (key) { + const value = parsedSecret[key]; + return typeof value === 'string' && value !== '' ? value : undefined; + } + + const firstValue = Object.values(parsedSecret).find( + (value): value is string => typeof value === 'string' && value !== '' + ); + + return firstValue; + }; + + switch (provider.key) { + case OAuthProvider.Amazon: + return projectSdk.updateOAuth2Amazon({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Apple: + return projectSdk.updateOAuth2Apple({ + serviceId: getAppId(), + keyId: getDetail('keyId'), + teamId: getDetail('teamId'), + p8File: getSecret('p8File'), + enabled + }); + case OAuthProvider.Auth0: + return projectSdk.updateOAuth2Auth0({ + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + endpoint: getDetail('endpoint'), + enabled + }); + case OAuthProvider.Authentik: + return projectSdk.updateOAuth2Authentik({ + endpoint: getDetail('endpoint'), + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + enabled + }); + case OAuthProvider.Autodesk: + return projectSdk.updateOAuth2Autodesk({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Bitbucket: + return projectSdk.updateOAuth2Bitbucket({ + key: getAppId(), + secret: getSecret(), + enabled + }); + case OAuthProvider.Bitly: + return projectSdk.updateOAuth2Bitly({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Box: + return projectSdk.updateOAuth2Box({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Dailymotion: + return projectSdk.updateOAuth2Dailymotion({ + apiKey: getAppId(), + apiSecret: getSecret(), + enabled + }); + case OAuthProvider.Discord: + return projectSdk.updateOAuth2Discord({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Disqus: + return projectSdk.updateOAuth2Disqus({ + publicKey: getAppId(), + secretKey: getSecret(), + enabled + }); + case OAuthProvider.Dropbox: + return projectSdk.updateOAuth2Dropbox({ + appKey: getAppId(), + appSecret: getSecret(), + enabled + }); + case OAuthProvider.Etsy: + return projectSdk.updateOAuth2Etsy({ + keyString: getAppId(), + sharedSecret: getSecret(), + enabled + }); + case OAuthProvider.Facebook: + return projectSdk.updateOAuth2Facebook({ + appId: getAppId(), + appSecret: getSecret(), + enabled + }); + case OAuthProvider.Figma: + return projectSdk.updateOAuth2Figma({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Fusionauth: + return projectSdk.updateOAuth2FusionAuth({ + endpoint: getDetail('endpoint'), + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + enabled + }); + case OAuthProvider.Github: + return projectSdk.updateOAuth2GitHub({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Gitlab: + return projectSdk.updateOAuth2Gitlab({ + applicationId: getAppId(), + secret: getSecret('secret'), + endpoint: getDetail('endpoint'), + enabled + }); + case OAuthProvider.Google: + return projectSdk.updateOAuth2Google({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Keycloak: + return projectSdk.updateOAuth2Keycloak({ + endpoint: getDetail('endpoint'), + realmName: getDetail('realmName'), + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + enabled + }); + case OAuthProvider.Kick: + return projectSdk.updateOAuth2Kick({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Linkedin: + return projectSdk.updateOAuth2Linkedin({ + clientId: getAppId(), + primaryClientSecret: getSecret(), + enabled + }); + case OAuthProvider.Microsoft: + return projectSdk.updateOAuth2Microsoft({ + tenant: getDetail('tenant'), + applicationId: getAppId(), + applicationSecret: getSecret('applicationSecret'), + enabled + }); + case OAuthProvider.Notion: + return projectSdk.updateOAuth2Notion({ + oauthClientId: getAppId(), + oauthClientSecret: getSecret(), + enabled + }); + case OAuthProvider.Oidc: + return projectSdk.updateOAuth2Oidc({ + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + wellKnownURL: getDetail('wellKnownURL'), + authorizationURL: getDetail('authorizationURL'), + tokenUrl: getDetail('tokenUrl'), + userInfoUrl: getDetail('userInfoUrl'), + enabled + }); + case OAuthProvider.Okta: + return projectSdk.updateOAuth2Okta({ + clientId: getAppId(), + clientSecret: getSecret('clientSecret'), + domain: getDetail('domain'), + authorizationServerId: getDetail('authorizationServerId'), + enabled + }); + case OAuthProvider.Paypal: + return projectSdk.updateOAuth2Paypal({ + clientId: getAppId(), + secretKey: getSecret(), + enabled + }); + case OAuthProvider.PaypalSandbox: + return projectSdk.updateOAuth2PaypalSandbox({ + clientId: getAppId(), + secretKey: getSecret(), + enabled + }); + case OAuthProvider.Podio: + return projectSdk.updateOAuth2Podio({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Salesforce: + return projectSdk.updateOAuth2Salesforce({ + customerKey: getAppId(), + customerSecret: getSecret(), + enabled + }); + case OAuthProvider.Slack: + return projectSdk.updateOAuth2Slack({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Spotify: + return projectSdk.updateOAuth2Spotify({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Stripe: + return projectSdk.updateOAuth2Stripe({ + clientId: getAppId(), + apiSecretKey: getSecret(), + enabled + }); + case OAuthProvider.Tradeshift: + return projectSdk.updateOAuth2Tradeshift({ + oauth2ClientId: getAppId(), + oauth2ClientSecret: getSecret(), + enabled + }); + case OAuthProvider.TradeshiftBox: + return projectSdk.updateOAuth2TradeshiftSandbox({ + oauth2ClientId: getAppId(), + oauth2ClientSecret: getSecret(), + enabled + }); + case OAuthProvider.Twitch: + return projectSdk.updateOAuth2Twitch({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Wordpress: + return projectSdk.updateOAuth2WordPress({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.X: + return projectSdk.updateOAuth2X({ + customerKey: getAppId(), + secretKey: getSecret(), + enabled + }); + case OAuthProvider.Yahoo: + return projectSdk.updateOAuth2Yahoo({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Yandex: + return projectSdk.updateOAuth2Yandex({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Zoho: + return projectSdk.updateOAuth2Zoho({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + case OAuthProvider.Zoom: + return projectSdk.updateOAuth2Zoom({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); + default: + throw new Error(`Unsupported OAuth2 provider: ${provider.key}`); + } +} + +export async function updateOAuth({ + region, + projectId, + provider, + appId, + secret, + details, enabled }: Args): Promise { try { @@ -31,13 +345,7 @@ export async function updateOAuth({ throw new Error(`Invalid OAuth2 provider: ${provider.key}`); } - await sdk.forConsole.projects.updateOAuth2({ - projectId, - provider: provider.key, - appId: appId || undefined, - secret: secret || undefined, - enabled - }); + await updateProjectOAuth({ region, projectId, provider, appId, secret, details, enabled }); await invalidate(Dependencies.PROJECT); addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/error.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/errorSonner.svelte similarity index 100% rename from src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/error.svelte rename to src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/errorSonner.svelte diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/index.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/index.ts index cc1daf60a..f5afd0bc5 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/index.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/sonners/index.ts @@ -1,3 +1,3 @@ export { default as Save } from './save.svelte'; -export { default as Error } from './error.svelte'; +export { default as Error } from './errorSonner.svelte'; export { default as Suggestions } from './suggestions.svelte'; diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createGit.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createGit.svelte index 1ea7fffbd..e9ee60e75 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createGit.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/(modals)/createGit.svelte @@ -90,7 +90,10 @@ scopes: ($func.scopes as Scopes[]) || undefined, installationId: $installation.$id || undefined, providerRepositoryId: selectedRepository || undefined, - providerBranch: branch || undefined + providerBranch: branch || undefined, + providerSilentMode: $func.providerSilentMode ?? undefined, + providerRootDirectory: $func.providerRootDirectory ?? undefined, + buildSpecification: $func.buildSpecification || undefined }); } if (commit) { diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/disconnectRepo.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/disconnectRepo.svelte index 9ba31a85a..fc27ddfe9 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/disconnectRepo.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/disconnectRepo.svelte @@ -40,7 +40,8 @@ providerRepositoryId: '', providerBranch: '', providerSilentMode: true, - providerRootDirectory: '' + providerRootDirectory: '', + buildSpecification: $func.buildSpecification || undefined }); await invalidate(Dependencies.FUNCTION); dispatch('success'); diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/updateRepository.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/updateRepository.svelte index 1a2412dfe..c091ffe53 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/updateRepository.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/settings/updateRepository.svelte @@ -91,7 +91,8 @@ providerRepositoryId: func.providerRepositoryId || undefined, providerBranch: selectedBranch, providerSilentMode: silentMode, - providerRootDirectory: selectedDir + providerRootDirectory: selectedDir, + buildSpecification: func.buildSpecification || undefined }); await invalidate(Dependencies.FUNCTION); addNotification({ @@ -129,7 +130,21 @@ selectedDir !== func?.providerRootDirectory; async function connect(selectedInstallationId: string, selectedRepository: string) { + let nextBranch = func?.providerBranch ?? 'main'; try { + const branchList = await sdk + .forProject(page.params.region, page.params.project) + .vcs.listRepositoryBranches({ + installationId: selectedInstallationId, + providerRepositoryId: selectedRepository + }); + const sorted = sortBranches(branchList.branches); + nextBranch = + sorted.find((branch) => branch.name === func?.providerBranch)?.name ?? + sorted.find((branch) => branch.name === 'main' || branch.name === 'master')?.name ?? + sorted[0]?.name ?? + nextBranch; + if (!isValueOfStringEnum(Runtime, func.runtime)) { throw new Error(`Invalid runtime: ${func.runtime}`); } @@ -148,7 +163,10 @@ scopes: (func.scopes as Scopes[]) || undefined, installationId: selectedInstallationId, providerRepositoryId: selectedRepository, - providerBranch: 'main' + providerBranch: nextBranch, + providerSilentMode: func.providerSilentMode ?? undefined, + providerRootDirectory: func.providerRootDirectory ?? undefined, + buildSpecification: func.buildSpecification || undefined }); await invalidate(Dependencies.FUNCTION); } catch { @@ -275,7 +293,7 @@ {#if showSelectRoot} {/if} diff --git a/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte b/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte index 70608e2f0..7309623b5 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte @@ -1,8 +1,9 @@ - + {#if loadError} + {loadError} + {/if} @@ -158,7 +224,7 @@ {@const checked = categoryState(category, scopes)} {@const isLastItem = index === categories.length - 1} {@const scopesLength = filteredScopes.filter( - (n) => n.category === category && scopes.includes(n.scope as Scopes) + (n) => n.category === category && effectiveScopes.includes(n.scope) ).length} { try { // send the project to correct region pool for deletion! - await sdk.forConsoleIn($project.region).projects.delete({ - projectId: $project.$id - }); + await sdk.forProject($project.region, $project.$id).project.delete(); await finishAndRedirect(); } catch (e) { error = e.message; diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte index 7bed364e6..fc54b8ba6 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte @@ -105,7 +105,7 @@ Scopes.FilesRead, Scopes.BucketsRead, Scopes.FunctionsRead, - Scopes.ExecutionRead, + Scopes.ExecutionsRead, Scopes.LocaleRead, Scopes.AvatarsRead, Scopes.HealthRead diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte index d2e717718..e70702127 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte @@ -107,7 +107,7 @@ Scopes.FilesRead, Scopes.BucketsRead, Scopes.FunctionsRead, - Scopes.ExecutionRead, + Scopes.ExecutionsRead, Scopes.SitesRead, Scopes.ProvidersRead, Scopes.TopicsRead, diff --git a/static/icons/dark/color/fusionauth.svg b/static/icons/dark/color/fusionauth.svg new file mode 100644 index 000000000..00303a443 --- /dev/null +++ b/static/icons/dark/color/fusionauth.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/dark/color/keycloak.svg b/static/icons/dark/color/keycloak.svg new file mode 100644 index 000000000..62219d304 --- /dev/null +++ b/static/icons/dark/color/keycloak.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/dark/color/kick.svg b/static/icons/dark/color/kick.svg new file mode 100644 index 000000000..7bd713230 --- /dev/null +++ b/static/icons/dark/color/kick.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/dark/color/oidc.svg b/static/icons/dark/color/oidc.svg index 3e45a505d..69ba83b7c 100644 --- a/static/icons/dark/color/oidc.svg +++ b/static/icons/dark/color/oidc.svg @@ -1,3 +1,5 @@ - - + + + + diff --git a/static/icons/dark/color/yammer.svg b/static/icons/dark/color/yammer.svg deleted file mode 100644 index 2d1083bd9..000000000 --- a/static/icons/dark/color/yammer.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/icons/dark/grayscale/yammer.svg b/static/icons/dark/grayscale/yammer.svg deleted file mode 100644 index cbb07a3c2..000000000 --- a/static/icons/dark/grayscale/yammer.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/static/icons/light/color/fusionauth.svg b/static/icons/light/color/fusionauth.svg new file mode 100644 index 000000000..00303a443 --- /dev/null +++ b/static/icons/light/color/fusionauth.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/light/color/keycloak.svg b/static/icons/light/color/keycloak.svg new file mode 100644 index 000000000..264768ec4 --- /dev/null +++ b/static/icons/light/color/keycloak.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/light/color/kick.svg b/static/icons/light/color/kick.svg new file mode 100644 index 000000000..7bd713230 --- /dev/null +++ b/static/icons/light/color/kick.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/icons/light/color/oidc.svg b/static/icons/light/color/oidc.svg index 3e45a505d..69ba83b7c 100644 --- a/static/icons/light/color/oidc.svg +++ b/static/icons/light/color/oidc.svg @@ -1,3 +1,5 @@ - - + + + + diff --git a/static/icons/light/color/yammer.svg b/static/icons/light/color/yammer.svg deleted file mode 100644 index e6d34f1e9..000000000 --- a/static/icons/light/color/yammer.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/icons/light/grayscale/yammer.svg b/static/icons/light/grayscale/yammer.svg deleted file mode 100644 index 66e6ba653..000000000 --- a/static/icons/light/grayscale/yammer.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - -