add: multiSelectTable to auth > user > identities.

update: add a basic `getPluralResource` helper in component.
add: a todo for later 👍
This commit is contained in:
Darshan
2025-10-26 13:24:30 +05:30
parent 901cdd535c
commit 7334d8bc76
2 changed files with 71 additions and 94 deletions
+12 -2
View File
@@ -1,4 +1,5 @@
<script lang="ts" module>
// TODO: @itznotabug - true | string | Error | void
export type DeleteOperationState = true | string | void;
</script>
@@ -60,6 +61,15 @@
message: `${count} ${label} deleted`
});
}
// this is kept very basic!
function getPluralResource() {
if (resource.endsWith('y')) {
return `${resource}ies`;
}
return `${resource}s`;
}
</script>
<Table.Root let:root {columns} {allowSelection} bind:selectedRows>
@@ -75,7 +85,7 @@
<svelte:fragment slot="start">
<Badge content={selectedRows.length.toString()} />
<span>
{selectedRows.length > 1 ? `${resource}s` : resource}
{selectedRows.length > 1 ? getPluralResource() : resource}
selected
</span>
</svelte:fragment>
@@ -135,7 +145,7 @@
{@render deleteContent(selectionCount)}
{:else}
Are you sure you want to delete <strong>{selectionCount}</strong>
{selectionCount > 1 ? `${resource}s` : resource}?
{selectionCount > 1 ? getPluralResource() : resource}?
{/if}
</Typography.Text>
@@ -1,122 +1,89 @@
<script lang="ts">
import { Id } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { type DeleteOperationState, Id, MultiSelectionTable } from '$lib/components';
import type { PageData } from './$types';
import DualTimeView from '$lib/components/dualTimeView.svelte';
import { sdk } from '$lib/stores/sdk';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
import { addNotification } from '$lib/stores/notifications';
import { invalidate } from '$app/navigation';
import type { Column } from '$lib/helpers/types';
import { oAuthProviders } from '$lib/stores/oauth-providers';
import { app } from '$lib/stores/app';
import { base } from '$app/paths';
import { Badge, FloatingActionBar, Table, Typography } from '@appwrite.io/pink-svelte';
import Confirm from '$lib/components/confirm.svelte';
import { Table } from '@appwrite.io/pink-svelte';
import { page } from '$app/state';
export let columns: Column[];
export let data: PageData;
let {
data,
columns
}: {
data: PageData;
columns: Column[];
} = $props();
let selectedIds: string[] = [];
let showDelete = false;
async function handleDelete() {
showDelete = false;
const promises = selectedIds.map((id) =>
sdk
async function handleDelete(selectedRows: string[]): Promise<DeleteOperationState> {
const promises = selectedRows.map((id) => {
return sdk
.forProject(page.params.region, page.params.project)
.users.deleteIdentity({ identityId: id })
);
.users.deleteIdentity({ identityId: id });
});
try {
await Promise.all(promises);
trackEvent(Submit.UserIdentityDelete, {
total: selectedIds.length
});
addNotification({
type: 'success',
message: `${selectedIds.length} target${selectedIds.length > 1 ? 's' : ''} deleted`
});
invalidate(Dependencies.USER_IDENTITIES);
await invalidate(Dependencies.USER_IDENTITIES);
trackEvent(Submit.UserIdentityDelete, { total: selectedRows.length });
return true;
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.UserIdentityDelete);
} finally {
selectedIds = [];
showDelete = false;
return error.message;
}
}
</script>
<Table.Root {columns} allowSelection let:root bind:selectedRows={selectedIds}>
<svelte:fragment slot="header" let:root>
<MultiSelectionTable {columns} resource="identity" onDelete={handleDelete}>
{#snippet header(root)}
{#each columns as { id, title }}
<Table.Header.Cell column={id} {root}>{title}</Table.Header.Cell>
{/each}
</svelte:fragment>
{#each data.identities.identities as identity (identity.$id)}
<Table.Row.Base {root} id={identity.$id}>
{#each columns as column}
<Table.Cell column={column.id} {root}>
{#if column.id === '$id'}
{#key columns}
<Id value={identity[column.id]}>
{identity[column.id]}
</Id>
{/key}
{:else if column.id === 'provider'}
{@const provider = oAuthProviders[identity[column.id]]}
<div class="u-inline-flex u-cross-center u-gap-8">
<div class="avatar is-size-small">
<img
style="--p-text-size: 1rem"
height="20"
width="20"
src={`${base}/icons/${$app.themeInUse}/color/${provider.icon}.svg`}
alt={provider.name} />
{/snippet}
{#snippet children(root)}
{#each data.identities.identities as identity (identity.$id)}
<Table.Row.Base {root} id={identity.$id}>
{#each columns as column}
<Table.Cell column={column.id} {root}>
{#if column.id === '$id'}
{#key columns}
<Id value={identity[column.id]}>
{identity[column.id]}
</Id>
{/key}
{:else if column.id === 'provider'}
{@const provider = oAuthProviders[identity[column.id]]}
<div class="u-inline-flex u-cross-center u-gap-8">
<div class="avatar is-size-small">
<img
style="--p-text-size: 1rem"
height="20"
width="20"
src={`${base}/icons/${$app.themeInUse}/color/${provider.icon}.svg`}
alt={provider.name} />
</div>
{provider.name}
</div>
{provider.name}
</div>
{:else if column.type === 'datetime'}
{#if !identity[column.id]}
-
{:else if column.type === 'datetime'}
{#if !identity[column.id]}
-
{:else}
<DualTimeView time={identity[column.id]} />
{/if}
{:else}
<DualTimeView time={identity[column.id]} />
{identity[column.id]}
{/if}
{:else}
{identity[column.id]}
{/if}
</Table.Cell>
{/each}
</Table.Row.Base>
{/each}
</Table.Root>
{#if selectedIds.length > 0}
<FloatingActionBar>
<svelte:fragment slot="start">
<Badge content={selectedIds.length.toString()} />
<span>
{selectedIds.length > 1 ? 'identities' : 'identity'}
selected
</span>
</svelte:fragment>
<svelte:fragment slot="end">
<Button text on:click={() => (selectedIds = [])}>Cancel</Button>
<Button secondary on:click={() => (showDelete = true)}>Delete</Button>
</svelte:fragment>
</FloatingActionBar>
{/if}
<Confirm title="Delete Identity" bind:open={showDelete} onSubmit={handleDelete}>
<Typography.Text>
Are you sure you want to delete <b>{selectedIds.length}</b>
{selectedIds.length > 1 ? 'identities' : 'identity'}?
</Typography.Text>
</Confirm>
</Table.Cell>
{/each}
</Table.Row.Base>
{/each}
{/snippet}
</MultiSelectionTable>