diff --git a/src/lib/sdk/dedicatedDatabases.ts b/src/lib/sdk/dedicatedDatabases.ts index 20442e397..993077834 100644 --- a/src/lib/sdk/dedicatedDatabases.ts +++ b/src/lib/sdk/dedicatedDatabases.ts @@ -16,10 +16,12 @@ export type DedicatedDatabase = { storage: number; storageClass: string; hostname: string; - port: number; - status: 'provisioning' | 'ready' | 'failed' | 'deleting' | 'deleted'; - containerStatus: 'inactive' | 'starting' | 'running' | null; - projectId: string; + connectionPort: number; + connectionUser: string; + connectionPassword: string; + connectionString: string; + status: 'provisioning' | 'ready' | 'inactive' | 'paused' | 'failed' | 'deleted' | 'restoring' | 'scaling'; + containerStatus: 'inactive' | 'starting' | 'running' | 'active' | null; highAvailability: boolean; haReplicaCount: number; haSyncMode: string | null; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts index 058f14ed8..fac292c65 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/sdk.ts @@ -187,15 +187,16 @@ export function useDatabaseSdk( async createEntity(params) { switch (type ?? params.databaseType) { case 'legacy': /* databases api */ - case 'tablesdb': - case 'prisma': - case 'dedicated': { + case 'tablesdb': { const table = await baseSdk.tablesDB.createTable({ ...params, tableId: params.entityId }); return toSupportiveEntity(table); } + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support entity creation via Appwrite'); case 'documentsdb': { const table = await baseSdk.documentsDB.createCollection({ ...params, @@ -214,12 +215,15 @@ export function useDatabaseSdk( async listEntities(params) { switch (type ?? params.databaseType) { case 'legacy': /* databases api */ - case 'tablesdb': - case 'prisma': - case 'dedicated': { + case 'tablesdb': { const { total, tables } = await baseSdk.tablesDB.listTables(params); return { total, entities: tables.map(toSupportiveEntity) }; } + case 'prisma': + case 'dedicated': { + // External databases don't have entities managed by Appwrite + return { total: 0, entities: [] }; + } case 'documentsdb': { const { total, collections } = await baseSdk.documentsDB.listCollections(params); @@ -235,15 +239,16 @@ export function useDatabaseSdk( async getEntity(params) { switch (type ?? params.databaseType) { case 'legacy': /* databases api */ - case 'tablesdb': - case 'prisma': - case 'dedicated': { + case 'tablesdb': { const table = await baseSdk.tablesDB.getTable({ databaseId: params.databaseId, tableId: params.entityId }); return toSupportiveEntity(table); } + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support entity retrieval via Appwrite'); case 'documentsdb': { const table = await baseSdk.documentsDB.getCollection({ databaseId: params.databaseId, @@ -280,12 +285,13 @@ export function useDatabaseSdk( switch (type ?? params.databaseType) { case 'legacy': /* databases api */ case 'tablesdb': - case 'prisma': - case 'dedicated': return await baseSdk.tablesDB.deleteTable({ databaseId: params.databaseId, tableId: params.entityId }); + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support entity deletion via Appwrite'); case 'documentsdb': return await baseSdk.documentsDB.deleteCollection({ databaseId: params.databaseId, @@ -302,8 +308,6 @@ export function useDatabaseSdk( switch (type ?? params.databaseType) { case 'legacy': /* databases api */ case 'tablesdb': - case 'prisma': - case 'dedicated': return await baseSdk.tablesDB.createRow({ databaseId: params.databaseId, tableId: params.entityId, @@ -311,6 +315,9 @@ export function useDatabaseSdk( data: params.data, permissions: params.permissions }); + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support record creation via Appwrite'); case 'documentsdb': return await baseSdk.documentsDB.createDocument({ databaseId: params.databaseId, @@ -330,8 +337,6 @@ export function useDatabaseSdk( switch (type ?? params.databaseType) { case 'legacy': /* databases api */ case 'tablesdb': - case 'prisma': - case 'dedicated': return await baseSdk.tablesDB.updateRow({ databaseId: params.databaseId, tableId: params.entityId, @@ -339,6 +344,9 @@ export function useDatabaseSdk( data: params.data, permissions: params.permissions }); + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support record updates via Appwrite'); case 'documentsdb': return await baseSdk.documentsDB.upsertDocument({ databaseId: params.databaseId, @@ -358,14 +366,15 @@ export function useDatabaseSdk( switch (type ?? params.databaseType) { case 'legacy': /* databases api */ case 'tablesdb': - case 'prisma': - case 'dedicated': return await baseSdk.tablesDB.updateRow({ databaseId: params.databaseId, tableId: params.entityId, rowId: params.recordId, permissions: params.permissions }); + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support permission updates via Appwrite'); case 'documentsdb': return await baseSdk.documentsDB.upsertDocument({ databaseId: params.databaseId, @@ -383,9 +392,7 @@ export function useDatabaseSdk( async deleteRecord(params) { switch (type ?? params.databaseType) { case 'legacy': /* databases api */ - case 'tablesdb': - case 'prisma': - case 'dedicated': { + case 'tablesdb': { const row = await baseSdk.tablesDB.deleteRow({ databaseId: params.databaseId, tableId: params.entityId, @@ -393,6 +400,9 @@ export function useDatabaseSdk( }); return toSupportiveRecord(row); } + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support record deletion via Appwrite'); case 'documentsdb': { const document = await baseSdk.documentsDB.deleteDocument({ databaseId: params.databaseId, @@ -411,9 +421,7 @@ export function useDatabaseSdk( async deleteRecords(params) { switch (type ?? params.databaseType) { case 'legacy': /* databases api */ - case 'tablesdb': - case 'prisma': - case 'dedicated': { + case 'tablesdb': { const { total, rows } = await baseSdk.tablesDB.deleteRows({ databaseId: params.databaseId, tableId: params.entityId, @@ -421,6 +429,9 @@ export function useDatabaseSdk( }); return { total, records: rows.map(toSupportiveRecord) }; } + case 'prisma': + case 'dedicated': + throw new Error('External databases do not support bulk record deletion via Appwrite'); case 'documentsdb': { const { total, documents } = await baseSdk.documentsDB.deleteDocuments({ databaseId: params.databaseId, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts index 5674ef184..efee99629 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts @@ -4,7 +4,7 @@ import type { LayoutLoad } from './$types'; import { Dependencies } from '$lib/constants'; import Breadcrumbs from './breadcrumbs.svelte'; import SubNavigation from './subNavigation.svelte'; -import type { DedicatedDatabase, DedicatedDatabaseCredentials } from '$lib/sdk/dedicatedDatabases'; +import type { DedicatedDatabase } from '$lib/sdk/dedicatedDatabases'; import type { Models } from '@appwrite.io/console'; type DatabaseWithType = Models.Database & { @@ -23,7 +23,6 @@ export const load: LayoutLoad = async ({ params, depends }) => { // Try to get from tablesDB first (handles legacy, tablesdb, documentsdb) let database: DatabaseWithType | DedicatedDatabase; let dedicatedDatabase: DedicatedDatabase | null = null; - let credentials: DedicatedDatabaseCredentials | null = null; try { database = await projectSdk.tablesDB.get({ @@ -45,19 +44,9 @@ export const load: LayoutLoad = async ({ params, depends }) => { } } - // Fetch credentials for dedicated databases - if (dedicatedDatabase) { - try { - credentials = await projectSdk.dedicatedDatabases.getCredentials(params.database); - } catch { - // Credentials not available yet (e.g., still provisioning) - } - } - return { database, dedicatedDatabase, - credentials, header: Header, breadcrumbs: Breadcrumbs, subNavigation: SubNavigation diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte index 0f6870e1f..cce344d1d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte @@ -51,7 +51,7 @@ {#if data.isDedicatedType && data.dedicatedDatabase} - + {:else} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.ts index c98835bf7..e4c26b486 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.ts @@ -5,7 +5,7 @@ import { CARD_LIMIT, Dependencies } from '$lib/constants'; import { type DatabaseType, useDatabaseSdk } from '$database/(entity)'; export const load: PageLoad = async ({ params, url, route, depends, parent }) => { - const { database, dedicatedDatabase, credentials } = await parent(); + const { database, dedicatedDatabase } = await parent(); depends(Dependencies.TABLES); const databaseType = database.type as DatabaseType; @@ -21,8 +21,7 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) => view: View.Grid, entities: { total: 0, entities: [] }, isDedicatedType: true, - dedicatedDatabase, - credentials + dedicatedDatabase }; } @@ -46,7 +45,6 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) => view, entities, isDedicatedType: false, - dedicatedDatabase: null, - credentials: null + dedicatedDatabase: null }; }; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte index 013b56068..72894a0b6 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/connectModal.svelte @@ -5,20 +5,15 @@ import { IconDuplicate } from '@appwrite.io/pink-icons-svelte'; import { copy } from '$lib/helpers/copy'; import { addNotification } from '$lib/stores/notifications'; - import type { - DedicatedDatabase, - DedicatedDatabaseCredentials - } from '$lib/sdk/dedicatedDatabases'; + import type { DedicatedDatabase } from '$lib/sdk/dedicatedDatabases'; let { show = $bindable(false), database, - credentials, connectionCommand }: { show: boolean; database: DedicatedDatabase; - credentials: DedicatedDatabaseCredentials | null; connectionCommand: string; } = $props(); @@ -48,8 +43,8 @@ } async function copyConnectionString() { - if (!credentials) return; - const success = await copy(credentials.connectionString); + if (!database.connectionString) return; + const success = await copy(database.connectionString); if (success) { addNotification({ type: 'success', @@ -91,8 +86,8 @@ Use this URI to connect from your application or database client. - {#if credentials} - + {#if database.connectionString} + {/if} @@ -116,21 +111,19 @@
Host - {credentials?.host ?? '-'} + {database.hostname || '-'}
Port - {credentials?.port ?? '-'} + {database.connectionPort || '-'}
Database - {credentials?.database ?? '-'} + postgres
Username - {credentials?.username ?? '-'} + {database.connectionUser || '-'}
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/dedicatedOverview.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/dedicatedOverview.svelte index 80af11f4c..24ffde449 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/dedicatedOverview.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/dedicatedOverview.svelte @@ -1,7 +1,7 @@ - - + + Status - - - Database Status - - + + + {capitalizeFirst(database.status)} + - {#if database.containerStatus} - - Container - - + {#if database.containerStatus && !isPrisma} + + Container: {capitalizeFirst(database.containerStatus)} + {/if} + + + {database.region.toUpperCase()} + {#if database.error} @@ -194,14 +199,18 @@ {/if} -
-

Created: {toLocaleDateTime(database.$createdAt)}

-

Last updated: {toLocaleDateTime(database.$updatedAt)}

-
+ + + Created {toLocaleDateTime(database.$createdAt)} + + + Updated {toLocaleDateTime(database.$updatedAt)} + +
- {#if database.containerStatus === 'inactive'} + {#if database.containerStatus === 'inactive' && !isPrisma} @@ -213,43 +222,72 @@
- - {#if database.status === 'ready' && credentials} + + {#if database.status === 'ready' && hasConnectionDetails} - Connection Settings - Use these credentials to connect to your database directly. + Connection + Use these credentials to connect to your database. - - - - - - - -
- -
- - - -
+ +
+ + (connectionTab = 'direct')} + active={connectionTab === 'direct'}> + Direct Connection + + (connectionTab = 'string')} + active={connectionTab === 'string'}> + Connection String + + +
- + {#if connectionTab === 'direct'} + + + + +
+ +
+ + + +
+
+
+ + {:else} + + + + + Terminal Command + + + + + {/if}
- - - {:else if database.status === 'provisioning'} - Connection Settings + Connection - + Your database is being set up. Connection details will be available once provisioning is complete. @@ -264,53 +302,69 @@ {/if} - + Resources + Your database configuration and allocated resources. - - - - Engine - {getEngineDisplayName(database.engine)} - {database.version} - - - Tier - {database.tier.charAt(0).toUpperCase() + - database.tier.slice(1)} - - - CPU - {cpuDisplay} - - - Memory - {memoryDisplay} - - - Storage - {storageDisplay} - - - Storage Class - {database.storageClass} - - - + + + + Engine + + + {getEngineDisplayName(database.engine)} {database.version} + + + + + Tier + + + {capitalizeFirst(database.tier)} + + + + + Backend + + + {capitalizeFirst(database.backend)} + + + + + CPU + + {cpuDisplay} + + + + Memory + + {memoryDisplay} + + + + Storage + + {storageDisplay} + + - - - High Availability - - - + + {#if !isPrisma} + + High Availability + Configure replicas and failover settings for your database. + + - Status + + Status + {#if database.highAvailability} - Replica Count - {database.haReplicaCount} + + Replicas + + + {database.haReplicaCount} + {#if database.haSyncMode} - Sync Mode - {database.haSyncMode} + + Sync Mode + + + {capitalizeFirst(database.haSyncMode)} + {/if} {/if} - - - + + + {/if} - - - Network - - - - - Max Connections - {database.networkMaxConnections} - - - Idle Timeout - {database.networkIdleTimeoutSeconds}s - - {#if database.idleTimeoutMinutes} + + {#if !isPrisma} + + Network + Connection limits and network configuration. + + + - Sleep After Idle - {database.idleTimeoutMinutes} min + + Max Connections + + + {database.networkMaxConnections} + + + + + Idle Timeout + + + {database.networkIdleTimeoutSeconds}s + + + {#if database.idleTimeoutMinutes} + + + Sleep After Idle + + + {database.idleTimeoutMinutes} min + + + {/if} + + + {#if database.networkIPAllowlist?.length > 0} + + + IP Allowlist + + + {#each database.networkIPAllowlist as ip} + + {/each} + {/if} - + + + + {/if} - {#if database.networkIPAllowlist?.length > 0} - - IP Allowlist - - {#each database.networkIPAllowlist as ip} - {ip} - {/each} - - - {/if} - - - - - + Backups + Automatic backup and point-in-time recovery settings. - - + + + + Automatic Backups + + + + {#if database.backupEnabled} - Status + + Point-in-Time Recovery + + content={database.backupPitr ? 'Enabled' : 'Disabled'} /> - {#if database.backupEnabled} - - Point-in-Time Recovery - - - - Schedule - {database.backupCron} - - - Retention - {database.backupRetentionDays} days - - {/if} - - + + + Schedule + + {database.backupCron} + + + + Retention + + + {database.backupRetentionDays} days + + + {/if} + - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/store.ts b/src/routes/(console)/project-[region]-[project]/databases/store.ts index d503891d3..5c57731f0 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/store.ts @@ -23,8 +23,15 @@ export const columns = writable( ] ); -export function getDatabaseTypeTitle(database: Models.Database) { +export function getDatabaseTypeTitle(database: Models.Database & { engine?: string }) { switch (database.type as DatabaseType) { + case 'prisma': + return 'Prisma Postgres'; + case 'dedicated': { + const engine = database.engine || 'postgres'; + const engineName = engine === 'postgres' ? 'PostgreSQL' : engine === 'mysql' ? 'MySQL' : engine; + return `Dedicated ${engineName}`; + } default: case 'legacy': case 'tablesdb':