Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
title,
closeOnBlur = false,
submit,
children = null
children = null,
footer = null
}: {
show: boolean;
title: string;
Expand All @@ -17,10 +18,11 @@
| {
text: string;
disabled?: boolean;
onClick?: () => void | Promise<void>;
onClick?: () => boolean | Promise<boolean>;
}
| undefined;
children?: Snippet;
footer?: Snippet | null;
} = $props();
</script>

Expand All @@ -38,8 +40,10 @@
<Form
onSubmit={async () => {
try {
await submit?.onClick();
show = false;
const keepOpen = await submit?.onClick?.();
if (!keepOpen) {
show = false;
}
} catch (error) {
// error occurred, dont close the sidebar
}
Expand All @@ -54,10 +58,16 @@
<Divider />

<div class="sheet-footer-actions">
<Layout.Stack gap="m" direction="row" justifyContent="flex-end">
<Layout.Stack
gap="m"
direction="row"
justifyContent="flex-end"
alignItems="center">
{#if footer}
{@render footer?.()}
{/if}
<Button size="s" secondary on:click={() => (show = false)}
>Cancel</Button>

<Button size="s" submit disabled={submit.disabled}>
{submit.text}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import { Permissions } from '$lib/components/permissions';
import type { Columns } from '../store';
import { ID, type Models } from '@appwrite.io/console';
import { Alert, Layout, Typography } from '@appwrite.io/pink-svelte';
import { Alert, Layout, Typography, Selector } from '@appwrite.io/pink-svelte';
import SideSheet from '../layout/sidesheet.svelte';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { tick } from 'svelte';

let {
table,
Expand All @@ -26,6 +27,7 @@

let isSubmitting = $state(false);
let columnFormWrapper: HTMLDivElement | null = $state(null);
let createMore = $state(false);

type CreateRow = {
id?: string;
Expand All @@ -34,28 +36,32 @@
columns: Columns[];
};

function createRowWritable() {
function computeInitialCreateRow(): CreateRow {
const availableColumns = table.columns.filter((a) => a.status === 'available');

const initial = {
return {
id: null,
row: existingData
? existingData
: availableColumns.reduce((acc, attr) => {
acc[attr.key] = attr.array ? [] : null;

return acc;
}, {}),
: availableColumns.reduce(
(acc, attr) => {
acc[attr.key] = attr.array ? [] : null;
return acc;
},
{} as Record<string, unknown>
),
permissions: [],
columns: availableColumns
};
}

return writable<CreateRow>({ ...initial });
function resetCreateRow(): void {
createRow.set(computeInitialCreateRow());
}

let createRow = createRowWritable();
let createRow = writable<CreateRow>(computeInitialCreateRow());

async function create() {
async function create(): Promise<boolean> {
isSubmitting = true;

try {
Expand All @@ -67,24 +73,31 @@
permissions: $createRow.permissions
});

showSheet = false;
addNotification({
message: 'Row has been created',
type: 'success'
});

// post op clear.
existingData = null;
trackEvent(Submit.RowCreate, {
customId: !!$createRow.id
});
await invalidate(Dependencies.ROW);

if (createMore) {
resetCreateRow();
existingData = null;
await tick();
focusFirstInput();
return true; // keep sheet open
}
return false; // close sheet
} catch (error) {
addNotification({
message: error.message,
type: 'error'
});
trackError(error, Submit.RowCreate);
return true; // keep open on error
} finally {
isSubmitting = false;
}
Expand All @@ -101,49 +114,62 @@
$effect(() => {
if (showSheet) {
focusFirstInput();
createRow = createRowWritable();
resetCreateRow();
} else {
createMore = false;
}
});
</script>

{#if $createRow}
<SideSheet
title={`${existingData ? 'Duplicate' : 'Create'} row`}
bind:show={showSheet}
closeOnBlur={false}
submit={{
text: 'Create',
disabled: isSubmitting,
onClick: () => create()
}}>
<Layout.Stack gap="xxl">
<div bind:this={columnFormWrapper}>
<ColumnForm
columns={$createRow.columns}
bind:customId={$createRow.id}
bind:formValues={$createRow.row} />
</div>

<Layout.Stack gap="xl">
<Typography.Text>
Choose which permission scopes to grant your application. It is best practice to
allow only the permissions you need to meet your project goals.
</Typography.Text>
{#if table.rowSecurity}
<Alert.Inline status="info">
<svelte:fragment slot="title">Row security is enabled</svelte:fragment>
Users will be able to access this row if they have been granted
<b>either row or table permissions</b>.
</Alert.Inline>
<Permissions bind:permissions={$createRow.permissions} />
{:else}
<Alert.Inline status="info">
<svelte:fragment slot="title">Row security is disabled</svelte:fragment>
If you want to assign row permissions, navigate to Table settings and enable
row security. Otherwise, only table permissions will be used.
</Alert.Inline>
{/if}
<div class="sheet-container">
<SideSheet
title={`${existingData ? 'Duplicate' : 'Create'} row`}
bind:show={showSheet}
closeOnBlur={false}
submit={{
text: 'Create',
disabled: isSubmitting,
onClick: async () => await create()
}}>
{#snippet footer()}
<Layout.Stack inline direction="row" alignItems="center">
<Selector.Switch
id="create-more"
bind:checked={createMore}
label="Create more" />
</Layout.Stack>
{/snippet}

<Layout.Stack gap="xxl">
<div bind:this={columnFormWrapper}>
<ColumnForm
columns={$createRow.columns}
bind:customId={$createRow.id}
bind:formValues={$createRow.row} />
</div>

<Layout.Stack gap="xl">
<Typography.Text>
Choose which permission scopes to grant your application. It is best
practice to allow only the permissions you need to meet your project goals.
</Typography.Text>
{#if table.rowSecurity}
<Alert.Inline status="info">
<svelte:fragment slot="title">Row security is enabled</svelte:fragment>
Users will be able to access this row if they have been granted
<b>either row or table permissions</b>.
</Alert.Inline>
<Permissions bind:permissions={$createRow.permissions} />
{:else}
<Alert.Inline status="info">
<svelte:fragment slot="title">Row security is disabled</svelte:fragment>
If you want to assign row permissions, navigate to Table settings and enable
row security. Otherwise, only table permissions will be used.
</Alert.Inline>
{/if}
</Layout.Stack>
</Layout.Stack>
</Layout.Stack>
</SideSheet>
</SideSheet>
</div>
{/if}
Loading