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 1ea7fffbd7..e9ee60e75b 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 9ba31a85a1..fc27ddfe93 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 1a2412dfeb..c091ffe530 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 35b0ddf23b..7309623b52 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 @@ -31,7 +31,11 @@ import { isCloud } from '$lib/system'; import { Button } from '$lib/elements/forms'; import { symmetricDifference } from '$lib/helpers/array'; - import { cloudOnlyBackupScopes, type ScopeDefinition } from '$lib/constants'; + import { + cloudOnlyBackupScopes, + scopes as localScopes, + type ScopeDefinition + } from '$lib/constants'; import { sdk } from '$lib/stores/sdk'; import { Accordion, Alert, Badge, Divider, Layout, Selector } from '@appwrite.io/pink-svelte'; import type { Scopes } from '@appwrite.io/console'; @@ -41,39 +45,68 @@ let allScopesList: ScopeDefinition[] = $state([]); let mounted = $state(false); let loadError: string | null = $state(null); + const effectiveScopes = $derived(getEffectiveScopes(scopes)); + + const categoryAliasMap: Record = { + Database: 'Databases' + }; enum Category { + Project = 'Project', Auth = 'Auth', - Database = 'Database', + Databases = 'Databases', Functions = 'Functions', Messaging = 'Messaging', Sites = 'Sites', Storage = 'Storage', + Domains = 'Domains', Other = 'Other' } - const categories = [ + const categoryOrder = [ + Category.Project, Category.Auth, - Category.Database, + Category.Databases, Category.Functions, Category.Storage, Category.Messaging, Category.Sites, + Category.Domains, Category.Other ]; + function normalizeCategory(category: string): string { + return categoryAliasMap[category] ?? category; + } + const filteredScopes = $derived.by(() => { const databasesWriteIndex = allScopesList.findIndex((s) => s.scope === 'databases.write'); if (isCloud && databasesWriteIndex !== -1) { return [ ...allScopesList.slice(0, databasesWriteIndex + 1), - ...cloudOnlyBackupScopes, + ...cloudOnlyBackupScopes.map((scope) => ({ + ...scope, + category: normalizeCategory(scope.category) + })), ...allScopesList.slice(databasesWriteIndex + 1) ]; } return allScopesList; }); + const categories = $derived.by(() => { + const availableCategories = new Set( + filteredScopes.map((scope) => normalizeCategory(scope.category)) + ); + + return [ + ...categoryOrder.filter((category) => availableCategories.has(category)), + ...Array.from(availableCategories).filter( + (category) => !categoryOrder.includes(category as Category) + ) + ]; + }); + const scopeCatalog = $derived( new Set([ ...filteredScopes.map((s) => s.scope), @@ -95,16 +128,29 @@ onMount(async () => { try { const result = await sdk.forConsole.console.listProjectScopes(); - allScopesList = result.scopes.map((s) => ({ - scope: s.$id, - description: s.description, - category: s.category, - deprecated: s.deprecated, - icon: '' - })); + const scopesById = new Map(); + + for (const scope of localScopes) { + scopesById.set(scope.scope, { + ...scope, + category: normalizeCategory(scope.category) + }); + } + + for (const scope of result.scopes) { + scopesById.set(scope.$id, { + scope: scope.$id, + description: scope.description, + category: normalizeCategory(scope.category), + deprecated: scope.deprecated, + icon: '' + }); + } + + allScopesList = Array.from(scopesById.values()); for (const s of filteredScopes) { - activeScopes[s.scope] = scopes.includes(s.scope as Scopes); + activeScopes[s.scope] = effectiveScopes.includes(s.scope); } mounted = true; } catch (e) { @@ -129,8 +175,9 @@ function categoryState(category: string, s: string[]): boolean | 'indeterminate' { const scopesByCategory = filteredScopes.filter((n) => n.category === category); + const scopeSet = new Set(getEffectiveScopes(s)); const activeInCategory = scopesByCategory.filter((scopeItem) => - s.includes(scopeItem.scope as Scopes) + scopeSet.has(scopeItem.scope) ); if (activeInCategory.length === 0) { @@ -142,7 +189,7 @@ return 'indeterminate'; } - function onCategoryChange(event: CustomEvent, category: Category) { + function onCategoryChange(event: CustomEvent, category: string) { const { detail } = event; if (detail === 'indeterminate') return; filteredScopes.forEach((s) => { @@ -177,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}