Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { Container } from '$lib/layout';
import { preferences } from '$lib/stores/preferences';
import { canWriteTables, canWriteRows } from '$lib/stores/roles';
import { Icon, Layout, Divider, Tooltip, Typography, Link } from '@appwrite.io/pink-svelte';
import { Dialog, Icon, Layout, Divider, Selector, Tooltip, Typography, Link } from '@appwrite.io/pink-svelte';
import type { PageData } from './$types';
import {
tableColumns,
Expand Down Expand Up @@ -44,6 +44,7 @@
import { EmptySheet, EmptySheetCards, type Field } from '$database/(entity)';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';

import {
Empty as SuggestionsEmptySheet,
tableColumnSuggestions,
Expand All @@ -57,6 +58,11 @@

let isRefreshing = false;
let showImportCSV = false;
let showImportOptions = false;
let importOverwrite = false;
let importSkip = false;
let pendingFile: Models.File | null = null;
let pendingLocalFile = false;

// todo: might need a type fix here.
const filterColumns = writable<Column[]>([]);
Expand Down Expand Up @@ -108,17 +114,30 @@

$: disableButton = canShowSuggestionsSheet;

async function onSelect(file: Models.File, localFile = false) {
function onSelect(file: Models.File, localFile = false) {
pendingFile = file;
pendingLocalFile = localFile;
importOverwrite = false;
importSkip = false;
showImportOptions = true;
}

async function startImport() {
if (!pendingFile) return;

showImportOptions = false;
$isCsvImportInProgress = 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,
overwrite: importOverwrite,
skip: importSkip
});

addNotification({
Expand All @@ -135,6 +154,7 @@
});
} finally {
$isCsvImportInProgress = false;
pendingFile = null;
}
}

Expand Down Expand Up @@ -424,6 +444,40 @@
}} />
{/if}

<Dialog title="Import options" bind:open={showImportOptions}>
<Layout.Stack gap="l">
<Typography.Text variant="m-400">
Choose how to handle documents that already exist in this table.
</Typography.Text>
<Layout.Stack gap="m">
<Selector.Checkbox
size="s"
checked={importOverwrite}
on:change={(e) => {
importOverwrite = e.detail;
if (e.detail) importSkip = false;
}}
label="Overwrite existing documents"
description="Documents with matching IDs will be updated with the imported data." />
<Selector.Checkbox
size="s"
checked={importSkip}
on:change={(e) => {
importSkip = e.detail;
if (e.detail) importOverwrite = false;
}}
label="Skip existing documents"
description="Documents with matching IDs will be silently skipped." />
</Layout.Stack>
</Layout.Stack>
<svelte:fragment slot="footer">
<Layout.Stack direction="row" gap="s" justifyContent="flex-end">
<Button text on:click={() => (showImportOptions = false)}>Cancel</Button>
<Button on:click={startImport}>Start import</Button>
</Layout.Stack>
</svelte:fragment>
</Dialog>

<CreateRow
{table}
bind:showSheet={$showRowCreateSheet.show}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Fieldset,
Icon,
Layout,
Selector,
Typography
} from '@appwrite.io/pink-svelte';
import { Link } from '$lib/elements';
Expand All @@ -38,6 +39,9 @@
import { capitalize } from '$lib/helpers/string';
import { page } from '$app/state';

let importOverwrite = false;
let importSkip = false;

const onExit = () => {
resetImportStores();
};
Expand All @@ -46,6 +50,11 @@
try {
const resources = migrationFormToResources($formData, $provider.provider);

const importOptions = {
overwrite: importOverwrite,
skip: importSkip
};

switch ($provider.provider) {
case 'appwrite': {
await sdk
Expand All @@ -54,7 +63,8 @@
resources: resources as AppwriteMigrationResource[],
endpoint: $provider.endpoint,
projectId: $provider.projectID,
apiKey: $provider.apiKey
apiKey: $provider.apiKey,
...importOptions
});

await invalidate(Dependencies.MIGRATIONS);
Expand All @@ -70,7 +80,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;
Expand All @@ -80,7 +91,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;
Expand All @@ -95,7 +107,8 @@
adminSecret: $provider.adminSecret,
database: $provider.database || $provider.subdomain,
username: $provider.username || 'postgres',
password: $provider.password
password: $provider.password,
...importOptions
});

await invalidate(Dependencies.MIGRATIONS);
Expand Down Expand Up @@ -196,6 +209,31 @@
projectSdk={sdk.forProject(page.params.region, page.params.project)} />
</Layout.Stack>
</Fieldset>

{#if $formData.databases.root}
<Fieldset legend="Import options">
<Layout.Stack gap="m">
<Selector.Checkbox
size="s"
checked={importOverwrite}
on:change={(e) => {
importOverwrite = e.detail;
if (e.detail) importSkip = false;
}}
label="Overwrite existing documents"
description="Documents with matching IDs will be updated with the imported data." />
<Selector.Checkbox
size="s"
checked={importSkip}
on:change={(e) => {
importSkip = e.detail;
if (e.detail) importOverwrite = false;
}}
label="Skip existing documents"
description="Documents with matching IDs will be silently skipped." />
</Layout.Stack>
</Fieldset>
{/if}
Comment on lines +213 to +236
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Stale import options sent when databases is deselected

importOverwrite and importSkip are local variables that persist even when the "Import options" fieldset is hidden. If a user:

  1. Selects Databases → enables "Overwrite existing documents" (sets importOverwrite = true)
  2. Then unchecks Databases ($formData.databases.root becomes false)
  3. Finishes the wizard

The importOptions object is still constructed with the stale importOverwrite: true and spread into every migration API call, sending unintended overwrite/skip flags to the backend even though no databases are being migrated.

Reset both values when databases is deselected, e.g. by deriving them reactively:

$: effectiveOverwrite = $formData.databases.root ? importOverwrite : false;
$: effectiveSkip = $formData.databases.root ? importSkip : false;

const importOptions = {
    overwrite: effectiveOverwrite,
    skip: effectiveSkip
};

{/if}
</Layout.Stack>
</Layout.Stack>
Expand Down
Loading