diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
index 1df280dcef..017e1a03a0 100644
--- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte
@@ -5,7 +5,15 @@
import type { Column, ColumnType } from '$lib/helpers/types';
import { Container } from '$lib/layout';
import { preferences } from '$lib/stores/preferences';
- import { Icon, Layout, Divider, Tooltip } from '@appwrite.io/pink-svelte';
+ import {
+ Icon,
+ Layout,
+ Divider,
+ Tooltip,
+ Selector,
+ Typography,
+ Dialog
+ } from '@appwrite.io/pink-svelte';
import type { PageProps } from './$types';
import FilePicker from '$lib/components/filePicker.svelte';
import { page } from '$app/state';
@@ -21,7 +29,7 @@
IconUpload,
IconDownload
} from '@appwrite.io/pink-icons-svelte';
- import { type Models } from '@appwrite.io/console';
+ import { OnDuplicate, type Models } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
@@ -49,7 +57,11 @@
let isRefreshing = $state(false);
let showImportJson = $state(false);
+ let showImportOptions = $state(false);
let showCustomColumnsModal = $state(false);
+ let importOnDuplicate: OnDuplicate = $state(OnDuplicate.Fail);
+ let pendingFile: Models.File | null = $state(null);
+ let pendingLocalFile = $state(false);
let columnsError: string = $state(null);
let spreadsheet: SpreadSheet | null = $state(null);
@@ -74,17 +86,28 @@
return queryParam ? `${url}?query=${encodeURIComponent(queryParam)}` : url;
}
- async function onSelect(file: Models.File, localFile = false) {
+ function onSelect(file: Models.File, localFile = false) {
+ pendingFile = file;
+ pendingLocalFile = localFile;
+ importOnDuplicate = OnDuplicate.Fail;
+ showImportOptions = true;
+ }
+
+ async function startImport() {
+ if (!pendingFile) return;
+
+ showImportOptions = false;
$isCollectionsJsonImportInProgress = true;
try {
await sdk
.forProject(page.params.region, page.params.project)
.migrations.createJSONImport({
- bucketId: file.bucketId,
- fileId: file.$id,
+ bucketId: pendingFile.bucketId,
+ fileId: pendingFile.$id,
resourceId: `${page.params.database}:${page.params.collection}`,
- internalFile: localFile
+ internalFile: pendingLocalFile,
+ onDuplicate: importOnDuplicate
});
addNotification({
@@ -101,6 +124,7 @@
});
} finally {
$isCollectionsJsonImportInProgress = false;
+ pendingFile = null;
}
}
@@ -343,6 +367,52 @@
}} />
{/if}
+
+
([]);
@@ -107,17 +120,28 @@
$: disableButton = canShowSuggestionsSheet;
- async function onSelect(file: Models.File, localFile = false) {
+ function onSelect(file: Models.File, localFile = false) {
+ pendingFile = file;
+ pendingLocalFile = localFile;
+ importOnDuplicate = OnDuplicate.Fail;
+ showImportOptions = true;
+ }
+
+ async function startImport() {
+ if (!pendingFile) return;
+
+ showImportOptions = false;
$isTablesCsvImportInProgress = true;
try {
await sdk
.forProject(page.params.region, page.params.project)
.migrations.createCSVImport({
- bucketId: file.bucketId,
- fileId: file.$id,
+ bucketId: pendingFile.bucketId,
+ fileId: pendingFile.$id,
resourceId: `${page.params.database}:${page.params.table}`,
- internalFile: localFile
+ internalFile: pendingLocalFile,
+ onDuplicate: importOnDuplicate
});
addNotification({
@@ -134,6 +158,7 @@
});
} finally {
$isTablesCsvImportInProgress = false;
+ pendingFile = null;
}
}
@@ -434,6 +459,52 @@
}} />
{/if}
+
+
{
resetImportStores();
};
@@ -46,6 +50,15 @@
try {
const resources = migrationFormToResources($formData, $provider.provider);
+ // Gate onDuplicate to Fail when databases isn't selected. The radios
+ // are only shown when databases.root is checked, but the local value
+ // persists across toggles — without this gate, deselecting databases
+ // after picking Overwrite/Skip would silently apply that mode to
+ // other resource types (users, teams, functions, etc.) on submit.
+ const importOptions = {
+ onDuplicate: $formData.databases.root ? importOnDuplicate : OnDuplicate.Fail
+ };
+
switch ($provider.provider) {
case 'appwrite': {
await sdk
@@ -54,7 +67,8 @@
resources: resources as AppwriteMigrationResource[],
endpoint: $provider.endpoint,
projectId: $provider.projectID,
- apiKey: $provider.apiKey
+ apiKey: $provider.apiKey,
+ ...importOptions
});
await invalidate(Dependencies.MIGRATIONS);
@@ -70,7 +84,8 @@
databaseHost: $provider.host,
username: $provider.username || 'postgres',
password: $provider.password,
- port: $provider.port || 5432
+ port: $provider.port || 5432,
+ ...importOptions
});
await invalidate(Dependencies.MIGRATIONS);
break;
@@ -80,7 +95,8 @@
.forProject(page.params.region, page.params.project)
.migrations.createFirebaseMigration({
resources: resources as FirebaseMigrationResource[],
- serviceAccount: $provider.serviceAccount
+ serviceAccount: $provider.serviceAccount,
+ ...importOptions
});
await invalidate(Dependencies.MIGRATIONS);
break;
@@ -95,7 +111,8 @@
adminSecret: $provider.adminSecret,
database: $provider.database || $provider.subdomain,
username: $provider.username || 'postgres',
- password: $provider.password
+ password: $provider.password,
+ ...importOptions
});
await invalidate(Dependencies.MIGRATIONS);
@@ -196,6 +213,46 @@
projectSdk={sdk.forProject(page.params.region, page.params.project)} />
+
+ {#if $formData.databases.root}
+
+ {/if}
{/if}