diff --git a/src/lib/components/navbar.svelte b/src/lib/components/navbar.svelte index 37813d9172..1178cd1bfd 100644 --- a/src/lib/components/navbar.svelte +++ b/src/lib/components/navbar.svelte @@ -34,6 +34,7 @@ IconCreditCard, IconCurrencyDollar, IconGlobeAlt, + IconKey, IconLogoutRight, IconMenuAlt4, IconMode, @@ -340,6 +341,21 @@ )} on:click={() => toggle()}> Domains + + {#if currentProject} + toggle()}> + API keys + {/if} {/if} @@ -402,6 +418,21 @@ leadingIcon: IconUser, href: resolve('/(console)/account') }, + ...(resolvedProfile.showExtendedAccountsMenu && currentProject + ? [ + { + name: 'API keys', + leadingIcon: IconKey, + href: resolve( + '/(console)/project-[region]-[project]/settings/api-keys', + { + region: currentProject.region, + project: currentProject.$id + } + ) + } + ] + : []), { name: 'Sign out', leadingIcon: IconLogoutRight, diff --git a/src/routes/(console)/project-[region]-[project]/overview/(components)/create.svelte b/src/routes/(console)/project-[region]-[project]/overview/(components)/create.svelte index 4c9bb81508..ebff384cf4 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/(components)/create.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/(components)/create.svelte @@ -17,6 +17,8 @@ import { page } from '$app/state'; import { copy } from '$lib/helpers/copy'; + export let basePath: string = `${base}/project-${page.params.region}-${page.params.project}/overview`; + const projectId = page.params.project; let showExitModal = false; @@ -41,9 +43,7 @@ } trackEvent(Submit.KeyCreate); - await goto( - `${base}/project-${page.params.region}-${page.params.project}/overview/api-keys/${$id}` - ); + await goto(`${basePath}/api-keys/${$id}`); addNotification({ message: `API key has been created`, type: 'success', @@ -74,7 +74,7 @@ + import { base } from '$app/paths'; import { invalidate } from '$app/navigation'; import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { Box, CardGrid } from '$lib/components'; @@ -23,6 +24,7 @@ export let key: Models.DevKey | Models.Key; export let keyType: 'api' | 'dev' = 'api'; + export let basePath: string = `${base}/project-${page.params.region}-${page.params.project}/overview`; let name: string = null; let scopes: string[] = null; @@ -190,7 +192,7 @@ {/if} - + Delete {label} key @@ -212,4 +214,4 @@ - + diff --git a/src/routes/(console)/project-[region]-[project]/overview/(components)/table.svelte b/src/routes/(console)/project-[region]-[project]/overview/(components)/table.svelte index 9cfb56a832..3963d746f3 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/(components)/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/(components)/table.svelte @@ -15,10 +15,12 @@ let { keyType = 'api', - keys + keys, + basePath = `${base}/project-${page.params.region}-${page.params.project}/overview` }: { keyType?: 'api' | 'dev'; keys: Models.KeyList | Models.DevKeyList; + basePath?: string; } = $props(); let selectedKeys = $state([]); @@ -126,13 +128,11 @@ description={getDescription()} on:click={async () => { if (isApiKey) { - await goto( - `${base}/project-${page.params.region}-${page.params.project}/overview/${slug}/create` - ); + await goto(`${basePath}/${slug}/create`); } else { $showDevKeysCreateModal = true; } }} /> {/if} - + diff --git a/src/routes/(console)/project-[region]-[project]/overview/(components)/updateExpirationDate.svelte b/src/routes/(console)/project-[region]-[project]/overview/(components)/updateExpirationDate.svelte index 19f49adaed..4c03ea2338 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/(components)/updateExpirationDate.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/(components)/updateExpirationDate.svelte @@ -14,6 +14,7 @@ export let keyType: 'api' | 'dev' = 'api'; export let key: Models.DevKey | Models.Key; + export let basePath: string = undefined; const projectId = page.params.project; diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/+layout.svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+layout.svelte new file mode 100644 index 0000000000..2bb0a3bd9c --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+layout.svelte @@ -0,0 +1,11 @@ + + + + {getPageTitle(page.data?.project?.name, 'API Keys', resolvedProfile.platform)} + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.svelte new file mode 100644 index 0000000000..ca50bac97e --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.svelte @@ -0,0 +1,27 @@ + + + + + {#if $canWriteKeys} + + {/if} + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.ts b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.ts new file mode 100644 index 0000000000..36fa8bbf52 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/+page.ts @@ -0,0 +1,12 @@ +import { Dependencies } from '$lib/constants'; +import { sdk } from '$lib/stores/sdk'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params, depends }) => { + depends(Dependencies.KEYS); + return { + keys: await sdk.forConsole.projects.listKeys({ + projectId: params.project + }) + }; +}; diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page.ts b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page.ts new file mode 100644 index 0000000000..84421d00e6 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page.ts @@ -0,0 +1,25 @@ +import Header from './header.svelte'; +import Breadcrumbs from './breadcrumbs.svelte'; +import { sdk } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params, depends }) => { + depends(Dependencies.KEY); + + const key = await sdk.forConsole.projects.getKey({ + projectId: params.project, + keyId: params.key + }); + if (key.expire) { + key.expire = new Date(key.expire).toISOString().slice(0, 23); + } else { + key.expire = undefined; + } + + return { + header: Header, + breadcrumbs: Breadcrumbs, + key + }; +}; diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page@project-[region]-[project].svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page@project-[region]-[project].svelte new file mode 100644 index 0000000000..60c780e334 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/+page@project-[region]-[project].svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/breadcrumbs.svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/breadcrumbs.svelte new file mode 100644 index 0000000000..7b81ac46d5 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/breadcrumbs.svelte @@ -0,0 +1,29 @@ + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/header.svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/header.svelte new file mode 100644 index 0000000000..aa12667f7f --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/header.svelte @@ -0,0 +1,41 @@ + + + + + + {$key?.name} + + + {#if $key?.secret} + + + + API secret + + + {/if} + {#if $projectRegion} + + {/if} + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/store.ts b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/store.ts new file mode 100644 index 0000000000..5a1a9f936e --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/[key]/store.ts @@ -0,0 +1,5 @@ +import { page } from '$app/stores'; +import { derived } from 'svelte/store'; +import type { Models } from '@appwrite.io/console'; + +export const key = derived(page, ($page) => $page.data.key as Models.Key); diff --git a/src/routes/(console)/project-[region]-[project]/settings/api-keys/create/+page@project-[region]-[project].svelte b/src/routes/(console)/project-[region]-[project]/settings/api-keys/create/+page@project-[region]-[project].svelte new file mode 100644 index 0000000000..ba22cb1841 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/api-keys/create/+page@project-[region]-[project].svelte @@ -0,0 +1,9 @@ + + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/header.svelte b/src/routes/(console)/project-[region]-[project]/settings/header.svelte index d7a715c2c8..9cee8d76f8 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/header.svelte @@ -8,6 +8,7 @@ import { canWriteProjects } from '$lib/stores/roles'; import { isCloud } from '$lib/system'; import { Typography } from '@appwrite.io/pink-svelte'; + import { resolvedProfile } from '$lib/profiles/index.svelte'; const path = `${base}/project-${page.params.region}-${page.params.project}/settings`; const tabs: TabElement[] = [ @@ -16,6 +17,12 @@ title: 'Overview', event: 'overview' }, + { + href: `${path}/api-keys`, + title: 'API keys', + event: 'api-keys', + disabled: !resolvedProfile.showExtendedAccountsMenu + }, { href: `${path}/domains`, title: 'Custom domains',