mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
add: multiSelectTable to auth > teams.
This commit is contained in:
@@ -10,7 +10,9 @@
|
||||
EmptySearch,
|
||||
AvatarInitials,
|
||||
SearchQuery,
|
||||
PaginationWithLimit
|
||||
PaginationWithLimit,
|
||||
type DeleteOperationState,
|
||||
MultiSelectionTable
|
||||
} from '$lib/components';
|
||||
import Create from '../createTeam.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
@@ -19,31 +21,16 @@
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { writable } from 'svelte/store';
|
||||
import { canWriteTeams } from '$lib/stores/roles';
|
||||
import {
|
||||
Icon,
|
||||
Layout,
|
||||
Table,
|
||||
FloatingActionBar,
|
||||
Badge,
|
||||
Typography
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Layout, Table } from '@appwrite.io/pink-svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
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 Confirm from '$lib/components/confirm.svelte';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
export let data;
|
||||
|
||||
const region = page.params.region;
|
||||
const project = page.params.project;
|
||||
|
||||
let selectedTeams: string[] = [];
|
||||
let showDelete = false;
|
||||
let deleting = false;
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
const columns = writable([
|
||||
{ id: 'name', title: 'Name', type: 'string', width: { min: 200, max: 300 } },
|
||||
@@ -52,37 +39,26 @@
|
||||
]);
|
||||
|
||||
const teamCreated = async (event: CustomEvent<Models.Team<Record<string, unknown>>>) => {
|
||||
await goto(`${base}/project-${region}-${project}/auth/teams/team-${event.detail.$id}`);
|
||||
await goto(
|
||||
`${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${event.detail.$id}`
|
||||
);
|
||||
};
|
||||
|
||||
async function handleDelete() {
|
||||
showDelete = false;
|
||||
deleting = true;
|
||||
|
||||
const promises = selectedTeams.map((teamId) =>
|
||||
sdk.forProject(page.params.region, page.params.project).teams.delete(teamId)
|
||||
);
|
||||
async function handleDelete(selectedRows: string[]): Promise<DeleteOperationState> {
|
||||
const promises = selectedRows.map((teamId) => {
|
||||
return sdk.forProject(page.params.region, page.params.project).teams.delete({ teamId });
|
||||
});
|
||||
|
||||
try {
|
||||
await Promise.all(promises);
|
||||
trackEvent(Submit.TeamDelete, {
|
||||
total: selectedTeams.length
|
||||
});
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `${selectedTeams.length} team${selectedTeams.length > 1 ? 's' : ''} deleted`
|
||||
});
|
||||
invalidate(Dependencies.TEAMS);
|
||||
|
||||
trackEvent(Submit.TeamDelete, { total: selectedRows.length });
|
||||
return true;
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: error.message
|
||||
});
|
||||
trackError(error, Submit.TeamDelete);
|
||||
return error.message;
|
||||
} finally {
|
||||
selectedTeams = [];
|
||||
showDelete = false;
|
||||
deleting = false;
|
||||
await invalidate(Dependencies.TEAMS);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -101,54 +77,47 @@
|
||||
</Layout.Stack>
|
||||
|
||||
{#if data.teams.total}
|
||||
<Table.Root
|
||||
<MultiSelectionTable
|
||||
resource="team"
|
||||
columns={$columns}
|
||||
allowSelection={$canWriteTeams}
|
||||
bind:selectedRows={selectedTeams}
|
||||
let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
onDelete={handleDelete}
|
||||
allowSelection={$canWriteTeams}>
|
||||
{#snippet header(root)}
|
||||
{#each $columns as { id, title }}
|
||||
<Table.Header.Cell column={id} {root}>{title}</Table.Header.Cell>
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
{#each data.teams.teams as team (team.$id)}
|
||||
<Table.Row.Link
|
||||
{root}
|
||||
href={`${base}/project-${region}-${project}/auth/teams/team-${team.$id}`}
|
||||
id={team.$id}>
|
||||
{#each $columns as column}
|
||||
<Table.Cell column={column.id} {root}>
|
||||
{#if column.id === 'name'}
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<AvatarInitials size="xs" name={team.name} />
|
||||
<span class="u-trim">{team.name}</span>
|
||||
</Layout.Stack>
|
||||
{:else if column.id === 'members'}
|
||||
{team.total} members
|
||||
{:else if column.id === 'created'}
|
||||
<DualTimeView time={team.$createdAt} />
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</Table.Row.Link>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/snippet}
|
||||
|
||||
{#if selectedTeams.length > 0}
|
||||
<FloatingActionBar>
|
||||
<svelte:fragment slot="start">
|
||||
<Badge content={selectedTeams.length.toString()} />
|
||||
<span>
|
||||
{selectedTeams.length > 1 ? 'teams' : 'team'}
|
||||
selected
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="end">
|
||||
<Button text on:click={() => (selectedTeams = [])}>Cancel</Button>
|
||||
<Button secondary on:click={() => (showDelete = true)}>Delete</Button>
|
||||
</svelte:fragment>
|
||||
</FloatingActionBar>
|
||||
{/if}
|
||||
{#snippet children(root)}
|
||||
{@const TableRowComponent = $canWriteTeams ? Table.Row.Link : Table.Row.Base}
|
||||
{#each data.teams.teams as team (team.$id)}
|
||||
{@const href = $canWriteTeams
|
||||
? `${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${team.$id}`
|
||||
: undefined}
|
||||
<TableRowComponent {root} {href} id={team.$id}>
|
||||
{#each $columns as column}
|
||||
<Table.Cell column={column.id} {root}>
|
||||
{#if column.id === 'name'}
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<AvatarInitials size="xs" name={team.name} />
|
||||
<span class="u-trim">{team.name}</span>
|
||||
</Layout.Stack>
|
||||
{:else if column.id === 'members'}
|
||||
{team.total} members
|
||||
{:else if column.id === 'created'}
|
||||
<DualTimeView time={team.$createdAt} />
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
{/each}
|
||||
</TableRowComponent>
|
||||
{/each}
|
||||
{/snippet}
|
||||
|
||||
{#snippet deleteContentNotice()}
|
||||
This action is irreversible and will permanently remove the selected teams and all
|
||||
their memberships.
|
||||
{/snippet}
|
||||
</MultiSelectionTable>
|
||||
|
||||
<PaginationWithLimit
|
||||
name="Teams"
|
||||
@@ -157,7 +126,10 @@
|
||||
total={data.teams.total} />
|
||||
{:else if data.search}
|
||||
<EmptySearch target="teams" search={data.search} hidePagination={data.teams.total === 0}>
|
||||
<Button secondary size="s" href={`${base}/project-${region}-${project}/auth/teams`}>
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
href={`${base}/project-${page.params.region}-${page.params.project}/auth/teams`}>
|
||||
Clear Search
|
||||
</Button>
|
||||
</EmptySearch>
|
||||
@@ -172,14 +144,3 @@
|
||||
</Container>
|
||||
|
||||
<Create bind:showCreate={$showCreateTeam} on:created={teamCreated} />
|
||||
|
||||
<Confirm title="Delete teams" bind:open={showDelete} onSubmit={handleDelete} disabled={deleting}>
|
||||
<Typography.Text>
|
||||
Are you sure you want to delete <b>{selectedTeams.length}</b>
|
||||
{selectedTeams.length > 1 ? 'teams' : 'team'}?
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
This action is irreversible and will permanently remove the selected teams and all their
|
||||
memberships.
|
||||
</Typography.Text>
|
||||
</Confirm>
|
||||
|
||||
Reference in New Issue
Block a user