Skip to content

Commit bd6a94d

Browse files
authored
Merge pull request #457 from appwrite/feat-user-labels
Add user labels to user list and detail pages
2 parents 874f7a7 + 2b98065 commit bd6a94d

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed

src/lib/actions/analytics.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export enum Submit {
118118
UserCreate = 'submit_user_create',
119119
UserDelete = 'submit_user_delete',
120120
UserUpdateEmail = 'submit_user_update_email',
121+
UserUpdateLabels = 'submit_user_update_labels',
121122
UserUpdateName = 'submit_user_update_name',
122123
UserUpdatePassword = 'submit_user_update_password',
123124
UserUpdatePhone = 'submit_user_update_phone',

src/routes/console/project-[project]/auth/+page.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<TableCellHead onlyDesktop>Identifiers</TableCellHead>
5757
<TableCellHead onlyDesktop width={130}>Status</TableCellHead>
5858
<TableCellHead onlyDesktop width={100}>ID</TableCellHead>
59+
<TableCellHead onlyDesktop width={100}>Labels</TableCellHead>
5960
<TableCellHead onlyDesktop>Joined</TableCellHead>
6061
<TableCellHead onlyDesktop>Last Activity</TableCellHead>
6162
</TableHeader>
@@ -110,6 +111,9 @@
110111
</Pill>
111112
</Copy>
112113
</TableCell>
114+
<TableCellText onlyDesktop title="Labels">
115+
{user.labels.join(', ')}
116+
</TableCellText>
113117
<TableCellText onlyDesktop title="Joined">
114118
{toLocaleDateTime(user.registration)}
115119
</TableCellText>

src/routes/console/project-[project]/auth/user-[user]/+page.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Container } from '$lib/layout';
33
import DangerZone from './dangerZone.svelte';
44
import UpdateEmail from './updateEmail.svelte';
5+
import UpdateLabels from './updateLabels.svelte';
56
import UpdateName from './updateName.svelte';
67
import UpdatePassword from './updatePassword.svelte';
78
import UpdatePhone from './updatePhone.svelte';
@@ -15,6 +16,7 @@
1516
<UpdateEmail />
1617
<UpdatePhone />
1718
<UpdatePassword />
19+
<UpdateLabels />
1820
<UpdatePrefs />
1921
<DangerZone />
2022
</Container>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<script lang="ts">
2+
import { onMount } from 'svelte';
3+
import { invalidate } from '$app/navigation';
4+
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
5+
import { CardGrid, Heading } from '$lib/components';
6+
import { Dependencies } from '$lib/constants';
7+
import { Button, Form, Helper, InputTags } from '$lib/elements/forms';
8+
import { symmetricDifference } from '$lib/helpers/array';
9+
import { addNotification } from '$lib/stores/notifications';
10+
import { sdk } from '$lib/stores/sdk';
11+
import { user } from './store';
12+
import { Pill } from '$lib/elements';
13+
14+
const alphaNumericRegExp = /^[a-zA-Z0-9]+$/;
15+
let suggestedLabels = ['admin', 'premium', 'mvp'];
16+
let labels: string[] = [];
17+
let error = '';
18+
19+
onMount(async () => {
20+
// TODO: Remove type cast when console SDK is updated
21+
labels = [...($user as unknown as { labels: string[] }).labels];
22+
});
23+
24+
async function updateLabels() {
25+
try {
26+
// TODO: Use SDK method when console SDK is updated
27+
// await sdk.forProject.users.updateLabels($user.$id, labels);
28+
const path = `/users/${$user.$id}/labels`;
29+
await sdk.forProject.client.call(
30+
'PUT',
31+
new URL(sdk.forConsole.client.config.endpoint + path),
32+
{
33+
'content-type': 'application/json'
34+
},
35+
{
36+
labels: labels
37+
}
38+
);
39+
await invalidate(Dependencies.USER);
40+
isDisabled = true;
41+
42+
addNotification({
43+
message: 'User labels have been updated',
44+
type: 'success'
45+
});
46+
trackEvent(Submit.UserUpdateLabels);
47+
} catch (error) {
48+
addNotification({
49+
message: error.message,
50+
type: 'error'
51+
});
52+
trackError(error, Submit.UserUpdateLabels);
53+
}
54+
}
55+
56+
// TODO: Remove type cast when console SDK is updated
57+
$: isDisabled =
58+
!!error ||
59+
!symmetricDifference(labels, ($user as unknown as { labels: string[] }).labels).length;
60+
$: if (labels) {
61+
const invalidLabels = [];
62+
63+
labels.forEach((label) => {
64+
if (!alphaNumericRegExp.test(label)) {
65+
invalidLabels.push(label);
66+
}
67+
});
68+
69+
if (invalidLabels.length) {
70+
error = `Invalid labels: ${invalidLabels.join(', ')}`;
71+
} else {
72+
error = '';
73+
}
74+
}
75+
</script>
76+
77+
<Form onSubmit={updateLabels}>
78+
<CardGrid>
79+
<Heading tag="h6" size="7">Labels</Heading>
80+
<p class="text">
81+
Categorize and manage your users based on specific criteria by assigning them
82+
customizable labels. New label-based roles will be assigned.
83+
</p>
84+
<svelte:fragment slot="aside">
85+
<ul class="common-section">
86+
<InputTags
87+
id="user-labels"
88+
label="Labels"
89+
placeholder="Select or tyype user labels"
90+
bind:tags={labels} />
91+
<li>
92+
<Helper type={error ? 'warning' : 'neutral'}
93+
>{error ? error : 'Only alphanumeric characters are allowed'}</Helper>
94+
</li>
95+
<li class="u-flex u-gap-12 u-margin-block-start-8">
96+
{#each suggestedLabels as suggestedLabel}
97+
<Pill
98+
selected={labels.includes(suggestedLabel)}
99+
button
100+
on:click={() => {
101+
if (!labels.includes(suggestedLabel)) {
102+
labels = [...labels, suggestedLabel];
103+
} else {
104+
labels = labels.filter((e) => e !== suggestedLabel);
105+
}
106+
}}>
107+
<span class="icon-plus" aria-hidden="true" />
108+
{suggestedLabel}
109+
</Pill>
110+
{/each}
111+
</li>
112+
</ul>
113+
</svelte:fragment>
114+
115+
<svelte:fragment slot="actions">
116+
<Button disabled={isDisabled} submit>Update</Button>
117+
</svelte:fragment>
118+
</CardGrid>
119+
</Form>

0 commit comments

Comments
 (0)