mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
add: multiSelectTable to auth > user > identities.
update: add a basic `getPluralResource` helper in component.
add: a todo for later 👍
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
+59
-92
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user