Skip to content

Commit

Permalink
Merge pull request #67 from appwrite/feat-roles-component
Browse files Browse the repository at this point in the history
feat: add roles component
  • Loading branch information
TorstenDittmann authored Oct 10, 2022
2 parents c7f4d2b + 42b31f3 commit 9586aab
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 117 deletions.
52 changes: 52 additions & 0 deletions src/lib/components/permissions/actions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { Button } from '$lib/elements/forms';
import { DropList, DropListItem } from '..';
import Custom from './custom.svelte';
import Team from './team.svelte';
import User from './user.svelte';
import type { Permission } from './permissions.svelte';
import type { Writable } from 'svelte/store';
export let showDropdown: boolean;
export let showUser: boolean;
export let showTeam: boolean;
export let showCustom: boolean;
export let groups: Writable<Map<string, Permission>>;
const dispatch = createEventDispatcher();
</script>

<DropList
bind:show={showDropdown}
position="bottom"
horizontal="right"
arrow={true}
arrowPosition="start">
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Add role</span>
</Button>
<svelte:fragment slot="list">
<DropListItem disabled={$groups.has('any')} on:click={() => dispatch('create', ['any'])}>
Any
</DropListItem>
<DropListItem
disabled={$groups.has('guests')}
on:click={() => dispatch('create', ['guests'])}>
All guests
</DropListItem>
<DropListItem
disabled={$groups.has('users')}
on:click={() => dispatch('create', ['users'])}>
All users
</DropListItem>
<DropListItem on:click={() => (showUser = true)}>Select users</DropListItem>
<DropListItem on:click={() => (showTeam = true)}>Select teams</DropListItem>
<DropListItem on:click={() => (showCustom = true)}>Custom permission</DropListItem>
</svelte:fragment>
</DropList>

<User bind:show={showUser} on:create {groups} />
<Team bind:show={showTeam} on:create {groups} />
<Custom bind:show={showCustom} on:create {groups} />
200 changes: 84 additions & 116 deletions src/lib/components/permissions/permissions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@
</script>

<script lang="ts">
import { Button } from '$lib/elements/forms';
import {
Table,
TableBody,
TableCell,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import { difference } from '$lib/helpers/array';
import { onDestroy, onMount } from 'svelte';
import { writable, type Unsubscriber } from 'svelte/store';
import { DropList, DropListItem } from '..';
import Custom from './custom.svelte';
import Actions from './actions.svelte';
import Row from './row.svelte';
import Team from './team.svelte';
import User from './user.svelte';
export let withCreate = false;
export let permissions: string[] = [];
Expand Down Expand Up @@ -139,114 +144,77 @@
}
</script>

<div class="table-with-scroll">
<div class="table-wrapper">
<table class="table is-table-layout-auto is-remove-outer-styles">
<thead class="table-thead">
<tr class="table-row">
<th class="table-thead-col">
<span class="eyebrow-heading-3">Role</span>
</th>
{#if withCreate}
<th class="table-thead-col" style="--p-col-width:70">
<span class="eyebrow-heading-3">Create</span>
</th>
{/if}
<th class="table-thead-col" style="--p-col-width:70">
<span class="eyebrow-heading-3">Read</span>
</th>
<th class="table-thead-col" style="--p-col-width:70">
<span class="eyebrow-heading-3">Update</span>
</th>
<th class="table-thead-col" style="--p-col-width:70">
<span class="eyebrow-heading-3">Delete</span>
</th>
<th class="table-thead-col" style="--p-col-width:40" />
</tr>
</thead>
<tbody class="table-tbody">
{#each [...$groups].sort(sortRoles) as [role, permission]}
<tr class="table-row">
<td class="table-col" data-title="Role">
<Row {role} />
</td>
{#if withCreate}
<td class="table-col" data-title="Create">
<input
type="checkbox"
class="icon-check"
aria-label="Create"
checked={permission.create}
on:change={() => togglePermission(role, 'create')} />
</td>
{/if}
<td class="table-col" data-title="Read">
<input
type="checkbox"
class="icon-check"
aria-label="Read"
checked={permission.read}
on:change={() => togglePermission(role, 'read')} />
</td>
<td class="table-col" data-title="Update">
<input
type="checkbox"
class="icon-check"
aria-label="Update"
checked={permission.update}
on:change={() => togglePermission(role, 'update')} />
</td>
<td class="table-col" data-title="Delete">
<input
type="checkbox"
class="icon-check"
aria-label="Delete"
checked={permission.delete}
on:change={() => togglePermission(role, 'delete')} />
</td>
<td class="table-col u-overflow-visible">
<div class="u-flex">
<button
class="button is-text is-only-icon"
type="button"
aria-label="delete"
on:click={() => deleteRole(role)}>
<span class="icon-x" aria-hidden="true" />
</button>
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<DropList
bind:show={showDropdown}
position="bottom"
horizontal="right"
arrow={true}
arrowPosition="start">
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Add role</span>
</Button>
<svelte:fragment slot="list">
<DropListItem disabled={$groups.has('any')} on:click={() => addRole('any')}>
Any
</DropListItem>
<DropListItem disabled={$groups.has('guests')} on:click={() => addRole('guests')}>
All guests
</DropListItem>
<DropListItem disabled={$groups.has('users')} on:click={() => addRole('users')}>
All users
</DropListItem>
<DropListItem on:click={() => (showUser = true)}>Select users</DropListItem>
<DropListItem on:click={() => (showTeam = true)}>Select teams</DropListItem>
<DropListItem on:click={() => (showCustom = true)}>Custom permission</DropListItem>
</svelte:fragment>
</DropList>

<User bind:show={showUser} on:create={create} {groups} />
<Team bind:show={showTeam} on:create={create} {groups} />
<Custom bind:show={showCustom} on:create={create} {groups} />
<Table noMargin noStyles noMobile>
<TableHeader>
<TableCellHead>Role</TableCellHead>
{#if withCreate}
<TableCellHead width={70}>Create</TableCellHead>
{/if}
<TableCellHead width={70}>Read</TableCellHead>
<TableCellHead width={70}>Update</TableCellHead>
<TableCellHead width={70}>Delete</TableCellHead>
<TableCellHead width={40} />
</TableHeader>
<TableBody>
{#each [...$groups].sort(sortRoles) as [role, permission]}
<TableRow>
<TableCellText title="Role">
<Row {role} />
</TableCellText>
{#if withCreate}
<TableCell title="Create">
<input
type="checkbox"
class="icon-check"
aria-label="Create"
checked={permission.create}
on:change={() => togglePermission(role, 'create')} />
</TableCell>
{/if}
<TableCell title="Read">
<input
type="checkbox"
class="icon-check"
aria-label="Read"
checked={permission.create}
on:change={() => togglePermission(role, 'read')} />
</TableCell>
<TableCell title="Update">
<input
type="checkbox"
class="icon-check"
aria-label="Update"
checked={permission.create}
on:change={() => togglePermission(role, 'update')} />
</TableCell>
<TableCell title="Delete">
<input
type="checkbox"
class="icon-check"
aria-label="Delete"
checked={permission.create}
on:change={() => togglePermission(role, 'delete')} />
</TableCell>
<TableCellText title="Remove">
<div class="u-flex">
<button
class="button is-text is-only-icon"
type="button"
aria-label="delete"
on:click={() => deleteRole(role)}>
<span class="icon-x" aria-hidden="true" />
</button>
</div>
</TableCellText>
</TableRow>
{/each}
</TableBody>
</Table>

<Actions
bind:showCustom
bind:showDropdown
bind:showTeam
bind:showUser
{groups}
on:create={create} />
107 changes: 107 additions & 0 deletions src/lib/components/permissions/roles.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<script lang="ts">
import {
Table,
TableBody,
TableCellHead,
TableCellText,
TableHeader,
TableRow
} from '$lib/elements/table';
import { difference } from '$lib/helpers/array';
import { onDestroy, onMount } from 'svelte';
import { writable, type Unsubscriber } from 'svelte/store';
import Actions from './actions.svelte';
import type { Permission } from './permissions.svelte';
import Row from './row.svelte';
export let roles: string[] = [];
let showUser = false;
let showTeam = false;
let showCustom = false;
let showDropdown = false;
let unsubscribe: Unsubscriber;
const groups = writable<Map<string, Permission>>(new Map());
onMount(() => {
roles.forEach(addRole);
unsubscribe = groups.subscribe((n) => {
const current = Array.from(n.keys());
if (difference(current, roles).length || difference(roles, current).length) {
roles = current;
}
});
});
onDestroy(() => {
if (unsubscribe) {
unsubscribe();
}
});
function create(event: CustomEvent<string[]>) {
for (const role of event.detail) {
addRole(role);
}
showTeam = showUser = false;
}
function addRole(role: string) {
if ($groups.has(role)) {
return;
}
groups.update((n) => {
n.set(role, null);
return n;
});
showDropdown = false;
}
function deleteRole(role: string): void {
groups.update((n) => {
n.delete(role);
return n;
});
}
</script>

<Table noMargin noStyles noMobile>
<TableHeader>
<TableCellHead>Role</TableCellHead>
<TableCellHead width={40} />
</TableHeader>
<TableBody>
{#each [...$groups.keys()] as role}
<TableRow>
<TableCellText title="Role">
<Row {role} />
</TableCellText>
<TableCellText title="Remove">
<div class="u-flex">
<button
class="button is-text is-only-icon"
type="button"
aria-label="delete"
on:click={() => deleteRole(role)}>
<span class="icon-x" aria-hidden="true" />
</button>
</div>
</TableCellText>
</TableRow>
{/each}
</TableBody>
</Table>

<Actions
bind:showCustom
bind:showDropdown
bind:showTeam
bind:showUser
{groups}
on:create={create} />
13 changes: 12 additions & 1 deletion src/lib/elements/table/table.svelte
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
<div class="table is-vertical u-margin-block-start-32" role="table">
<script lang="ts">
export let noMargin = false;
export let noStyles = false;
export let noMobile = false;
</script>

<div
class="table is-vertical"
class:is-vertical={!noMobile}
class:u-margin-block-start-32={!noMargin}
class:is-remove-outer-styles={noStyles}
role="table">
<slot />
</div>

1 comment on commit 9586aab

@vercel
Copy link

@vercel vercel bot commented on 9586aab Oct 10, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.