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',