(fix): gate dedicated database features behind isCloud

- Filter dedicateddb from databaseTypes for self-hosted instances
- Hide dedicated DB cards in empty state when not cloud
- Default create wizard to tablesdb for self-hosted
- Disable dedicated-only header tabs for self-hosted
- Fix null as DatabaseType cast and selectedEngine typing
This commit is contained in:
Jake Barnby
2026-03-31 15:36:24 +13:00
parent eaf93ad20d
commit 2d2a563019
4 changed files with 39 additions and 30 deletions
@@ -8,7 +8,7 @@
import { CustomId } from '$lib/components';
import { page } from '$app/state';
import { addNotification } from '$lib/stores/notifications';
import { BackupServices, ID, type Models } from '@appwrite.io/console';
import { BackupServices, Engine, ID, type Models } from '@appwrite.io/console';
import {
type DatabaseType,
type DedicatedDatabaseParams,
@@ -40,7 +40,7 @@
let formComponent: Form;
const params = page.url.searchParams;
const typeFromParams = params.get('type') ?? (null as DatabaseType);
const typeFromParams: DatabaseType | null = params.get('type') as DatabaseType | null;
let showCreatePolicies = $state(false);
let totalPolicies: UserBackupPolicy[] = $state([]);
@@ -48,7 +48,7 @@
let showExitModal = $state(false);
let isSubmitting = $state(writable(false));
let previousPage: string = $state(resolveRoute('/'));
let type = $state(typeFromParams ?? 'dedicateddb') as DatabaseType;
let type = $state(typeFromParams ?? (isCloud ? 'dedicateddb' : 'tablesdb')) as DatabaseType;
const isDark = $derived($app.themeInUse === 'dark');
const backupsImg = $derived(isDark ? EmptyDarkMobile : EmptyLightMobile);
@@ -81,7 +81,7 @@
}));
// State for dedicated options (pre-populated from URL params)
let selectedEngine = $state(params.get('engine') ?? 'postgres');
let selectedEngine = $state<Engine>((params.get('engine') as Engine) ?? Engine.Postgres);
let selectedRegion = $state<string | null>(params.get('region') ?? null);
let selectedTier = $state(params.get('tier') ?? 'free');
@@ -526,21 +526,23 @@
{/snippet}
{#snippet selectDatabaseType(disabled = false)}
<Layout.Grid columns={4} columnsS={2} columnsXS={1}>
<Layout.Grid columns={databaseTypes.length} columnsS={2} columnsXS={1}>
{#each databaseTypes as databaseType}
<div class="card-selector">
<Card.Selector
{disabled}
variant="secondary"
bind:group={type}
name={databaseType.type}
id={databaseType.type}
value={databaseType.type}
title={databaseType.title}
imageRadius="s">
{databaseType.subtitle}
</Card.Selector>
</div>
{#if databaseType.type !== 'dedicateddb' || isCloud}
<div class="card-selector">
<Card.Selector
{disabled}
variant="secondary"
bind:group={type}
name={databaseType.type}
id={databaseType.type}
value={databaseType.type}
title={databaseType.title}
imageRadius="s">
{databaseType.subtitle}
</Card.Selector>
</div>
{/if}
{/each}
</Layout.Grid>
{/snippet}
@@ -6,6 +6,7 @@
import { canWriteDatabases } from '$lib/stores/roles';
import { resolveRoute, withPath } from '$lib/stores/navigation';
import { useTerminology, type DatabaseType } from '$database/(entity)';
import { isCloud } from '$lib/system';
import { isSmallViewport } from '$lib/stores/viewport';
const terminology = useTerminology(page);
@@ -20,7 +21,6 @@
page.params
);
// Check if this is a dedicated database type
const isDedicatedType = $derived((database?.type as DatabaseType) === 'dedicateddb');
const tabs = $derived(
@@ -41,13 +41,13 @@
href: withPath(baseDatabasePath, '/auth'),
title: 'Auth',
event: 'auth',
disabled: !isDedicatedType
disabled: !isDedicatedType || !isCloud
},
{
href: withPath(baseDatabasePath, '/monitoring'),
title: 'Monitoring',
event: 'monitoring',
disabled: !isDedicatedType
disabled: !isDedicatedType || !isCloud
},
{
href: withPath(baseDatabasePath, '/usage'),
@@ -17,6 +17,7 @@
import DedicatedDB from './(assets)/dedicated-db.svg';
import DedicatedDBDark from './(assets)/dark/dedicated-db.svg';
import { isCloud } from '$lib/system';
import { isSmallViewport } from '$lib/stores/viewport';
import type { DatabaseType } from '$database/(entity)';
import { databaseTypes } from './store';
@@ -56,14 +57,16 @@
>Store, organize, and manage your app data</Typography.Text>
</Layout.Stack>
<Layout.Grid columns={4} columnsS={2} columnsXS={1} gap="xl">
<Layout.Grid columns={databaseTypes.length} columnsS={2} columnsXS={1} gap="xl">
{#each databaseTypes as db}
{@render databaseTypeCard({
type: db.type,
title: db.title,
subtitle: db.subtitle,
image: images[db.type]
})}
{#if db.type !== 'dedicateddb' || isCloud}
{@render databaseTypeCard({
type: db.type,
title: db.title,
subtitle: db.subtitle,
image: images[db.type]
})}
{/if}
{/each}
</Layout.Grid>
</Layout.Stack>
@@ -23,16 +23,18 @@ export const columns = writable<Column[]>(
]
);
export const databaseTypes: Array<{
const allDatabaseTypes: Array<{
type: DatabaseType;
title: string;
subtitle: string;
cloudOnly?: boolean;
}> = [
{
type: 'dedicateddb',
title: 'DedicatedDB',
subtitle:
'Always-on dedicated instances with high availability. Best for production workloads.'
'Always-on dedicated instances with high availability. Best for production workloads.',
cloudOnly: true
},
{
type: 'tablesdb',
@@ -54,6 +56,8 @@ export const databaseTypes: Array<{
}
];
export const databaseTypes = allDatabaseTypes.filter((db) => !db.cloudOnly || isCloud);
export function getDatabaseTypeTitle(database: Models.Database & { engine?: string }) {
switch (database.type as DatabaseType) {
case 'dedicateddb': {