Skip to content

Commit 75b5db3

Browse files
committed
✨ List all auth method in console
1 parent 066946f commit 75b5db3

File tree

17 files changed

+317
-99
lines changed

17 files changed

+317
-99
lines changed

console/src/lib/components/common/card/Card.svelte

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<script lang="ts">
22
export let clickable = false;
3+
export let disabled = false;
34
45
const clickableClass = clickable ? "cursor-pointer hover:shadow-xl transition-shadow" : "";
6+
const disabledClass = disabled ? "opacity-50 cursor-not-allowed" : "";
57
// import svelte event dispatcher and dispatch onclick event
68
import { createEventDispatcher } from "svelte";
79
const dispatch = createEventDispatcher();
@@ -13,10 +15,10 @@
1315
</script>
1416

1517
<div
16-
role="button"
18+
role={clickable ? "button" : ""}
1719
tabindex="0"
1820
on:click={handleClick}
1921
on:keydown={() => {}}
20-
class="{clickableClass} w-full rounded-2xl border border-stroke-base dark:border-stroke-base-dark bg-background-tertiary dark:bg-background-tertiary-dark">
22+
class="{clickableClass} {disabledClass} w-full rounded-2xl border border-stroke-base dark:border-stroke-base-dark bg-background-tertiary dark:bg-background-tertiary-dark">
2123
<slot />
2224
</div>

console/src/lib/components/common/spacer/Spacer.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script lang="ts">
2-
type Size = "sm" | "md" | "lg";
2+
type Size = "xs" | "sm" | "md" | "lg";
33
export let size: Size = "sm";
44
55
export const sizeClassMap: Record<Size, string> = {
6+
xs: "my-2",
67
sm: "my-5",
78
md: "my-10",
89
lg: "my-20"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
export let type: "info" | "success" | "error" | "warning" = "info";
3+
4+
const classPerType = {
5+
success:
6+
"border-stroke-success dark:border-stroke-success-dark bg-background-success dark:bg-background-success-dark text-body-filled-success dark:text-body-filled-success-dark",
7+
warning:
8+
"border-stroke-warning dark:border-stroke-warning-dark bg-background-warning dark:bg-background-warning-dark text-body-filled-warning dark:text-body-filled-warning-dark",
9+
error: "border-stroke-error dark:border-stroke-error-dark bg-background-error dark:bg-background-error-dark text-body-filled-error dark:text-body-filled-error-dark",
10+
info: "border-stroke-info dark:border-stroke-info-dark bg-background-info dark:bg-background-info-dark text-body-filled-info dark:text-body-filled-info-dark"
11+
};
12+
</script>
13+
14+
<div class="{classPerType[type]} rounded-full px-3 py-1 text-sm">
15+
<slot />
16+
</div>

console/src/lib/components/common/typography/Typography.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
| "mainTitle"
44
| "mainSectionTitle"
55
| "sectionTitle"
6+
| "cardSmallTitle"
67
| "subTitle"
78
| "label"
89
| "body";
@@ -15,6 +16,7 @@
1516
mainTitle: "text-body-accent dark:text-body-accent-dark font-semibold text-2xl",
1617
mainSectionTitle: "text-body-accent dark:text-body-accent-dark font-medium text-2xl",
1718
sectionTitle: "text-body-accent dark:text-body-accent-dark font-medium text-xl",
19+
cardSmallTitle: "text-sm text-body-base dark:text-body-base-dark text-md",
1820
subTitle: "text-sm text-body-base dark:text-body-base-dark",
1921
label: "text-body-subdued dark:text-body-subdued-dark uppercase font-medium text-sm",
2022
body: "text-sm text-body-base dark:text-body-base-dark"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { SvelteComponent } from "svelte";
2+
import type { IconSource } from "svelte-hero-icons";
3+
4+
export type AuthMethodListItem = {
5+
id: string;
6+
name: string;
7+
value: string;
8+
heroIcon: IconSource | null;
9+
componentIcon: typeof SvelteComponent | null;
10+
available: boolean;
11+
isEnabled: boolean;
12+
statusLabel: string;
13+
};
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import GithubIcon from "$lib/components/auth/GithubIcon.svelte";
2+
import GitlabIcon from "$lib/components/auth/GitlabIcon.svelte";
3+
import GoogleIcon from "$lib/components/auth/GoogleIcon.svelte";
4+
import MicrosoftIcon from "$lib/components/auth/MicrosoftIcon.svelte";
5+
import type { AuthMethodListItem } from "$lib/entities/auth-method/auth-method-list-item";
6+
import { AuthMethodsService } from "$lib/services/gen-api";
7+
import { ChatBubbleLeft, Envelope, EyeSlash, Key } from "svelte-hero-icons";
8+
9+
export type fetchAvailableAuthMethodsResponse = {
10+
builtIn: AuthMethodListItem[];
11+
oauth: AuthMethodListItem[];
12+
};
13+
export const fetchAvailableAuthMethods = async (
14+
projectId: string
15+
): Promise<fetchAvailableAuthMethodsResponse> => {
16+
await new Promise((resolve) => setTimeout(resolve, 1000));
17+
const methods = await AuthMethodsService.listAuthMethods({
18+
projectId
19+
});
20+
21+
const builtInMethods: AuthMethodListItem[] = [
22+
{
23+
id: "passwordless-email",
24+
name: "Passwordless email",
25+
value: "PASSWORDLESS_EMAIL",
26+
heroIcon: Envelope,
27+
componentIcon: null,
28+
available: true,
29+
statusLabel: "ACTIVE",
30+
isEnabled: false
31+
},
32+
{
33+
id: "anonymous",
34+
name: "Anonymous",
35+
value: "ANONYMOUS",
36+
heroIcon: EyeSlash,
37+
componentIcon: null,
38+
available: false,
39+
statusLabel: "COMING SOON",
40+
isEnabled: false
41+
},
42+
{
43+
id: "email-and-password",
44+
name: "Email and password",
45+
value: "EMAIL_AND_PASSWORD",
46+
heroIcon: Key,
47+
componentIcon: null,
48+
available: false,
49+
statusLabel: "COMING SOON",
50+
isEnabled: false
51+
},
52+
{
53+
id: "SMS",
54+
name: "SMS",
55+
value: "SMS",
56+
heroIcon: ChatBubbleLeft,
57+
componentIcon: null,
58+
available: false,
59+
statusLabel: "COMING SOON",
60+
isEnabled: false
61+
}
62+
].map((method) => {
63+
const foundMethod = methods.items.find((m) => m.provider === method.value);
64+
65+
if (foundMethod) {
66+
return {
67+
...method,
68+
isEnabled: foundMethod.isEnabled,
69+
statusLabel: foundMethod.isEnabled ? "ENABLED" : "DISABLED"
70+
};
71+
}
72+
73+
return method;
74+
});
75+
76+
const oauthMethods: AuthMethodListItem[] = [
77+
{
78+
id: "google",
79+
name: "Google / Gmail",
80+
value: "GOOGLE",
81+
heroIcon: null,
82+
componentIcon: GoogleIcon,
83+
available: true,
84+
statusLabel: "ACTIVE",
85+
isEnabled: false
86+
},
87+
{
88+
id: "gitlab",
89+
name: "Gitlab",
90+
value: "GITLAB",
91+
heroIcon: null,
92+
componentIcon: GitlabIcon,
93+
available: false,
94+
statusLabel: "COMING SOON",
95+
isEnabled: false
96+
},
97+
{
98+
id: "github",
99+
name: "GitHub",
100+
value: "GITHUB",
101+
heroIcon: null,
102+
componentIcon: GithubIcon,
103+
available: false,
104+
statusLabel: "COMING SOON",
105+
isEnabled: false
106+
},
107+
{
108+
id: "microsoft",
109+
name: "Microsoft",
110+
value: "MICROSOFT",
111+
heroIcon: null,
112+
componentIcon: MicrosoftIcon,
113+
available: false,
114+
statusLabel: "COMING SOON",
115+
isEnabled: false
116+
}
117+
].map((method) => {
118+
const foundMethod = methods.items.find((m) => m.provider === method.value);
119+
120+
if (foundMethod) {
121+
return {
122+
...method,
123+
isEnabled: foundMethod.isEnabled,
124+
statusLabel: foundMethod.isEnabled ? "ENABLED" : "DISABLED"
125+
};
126+
}
127+
128+
return method;
129+
});
130+
131+
return {
132+
builtIn: builtInMethods,
133+
oauth: oauthMethods
134+
};
135+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script lang="ts">
2+
import TopCover from "$lib/components/common/top-cover/TopCover.svelte";
3+
import Spacer from "$lib/components/common/spacer/Spacer.svelte";
4+
import TabNav from "$lib/components/common/navigation/tab-nav/TabNav.svelte";
5+
import { projectStore } from "$lib/stores/project";
6+
7+
import { projectAuthMethodsRoute, projectMembersRoute } from "$lib/routes/routes";
8+
9+
$: navItems = $projectStore?.currentProjectId
10+
? [
11+
{
12+
label: "Members",
13+
path: projectMembersRoute.path($projectStore.currentProjectId)
14+
},
15+
{
16+
label: "Auth methods",
17+
path: projectAuthMethodsRoute.path($projectStore.currentProjectId)
18+
}
19+
]
20+
: [];
21+
</script>
22+
23+
<div>
24+
<TopCover>
25+
<section class="px-12 pt-12 pb-0 h-full flex flex-col gap-4 justify-between">
26+
<span class="text-body-accent dark:text-body-accent-dark font-semibold text-2xl"
27+
>Authentication</span>
28+
29+
<TabNav items={navItems} />
30+
</section>
31+
</TopCover>
32+
<slot />
33+
</div>

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

Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
import dayjs from "dayjs";
77
import type { TableColumn, TableRow } from "$lib/components/common/table/types";
88
import type { Member } from "$lib/entities/member/member";
9-
import TabNav from "$lib/components/common/navigation/tab-nav/TabNav.svelte";
109
import { projectStore } from "$lib/stores/project";
1110
import { fetchProjectMembers } from "$lib/usecases/members/fetchProjectMembers";
12-
13-
import { projectAuthMethodsRoute, projectMembersRoute } from "$lib/routes/routes";
1411
import { onMount } from "svelte";
1512
import CopiableCell from "$lib/components/common/table/CopiableCell.svelte";
1613
@@ -70,19 +67,6 @@
7067
}
7168
];
7269
73-
$: navItems = $projectStore.currentProjectId
74-
? [
75-
{
76-
label: "Members",
77-
path: projectMembersRoute.path($projectStore.currentProjectId)
78-
},
79-
{
80-
label: "Auth methods",
81-
path: projectAuthMethodsRoute.path($projectStore.currentProjectId)
82-
}
83-
]
84-
: [];
85-
8670
$: filteredResults = () => {
8771
if (!searchValue) return users;
8872
return users.filter((user) => {
@@ -94,36 +78,26 @@
9478
};
9579
</script>
9680

97-
<div>
98-
<TopCover>
99-
<section class="px-12 pt-12 pb-0 h-full flex flex-col gap-4 justify-between">
100-
<span class="text-body-accent dark:text-body-accent-dark font-semibold text-2xl"
101-
>Authentication</span>
102-
103-
<TabNav items={navItems} />
104-
</section>
105-
</TopCover>
106-
<div class="w-full p-10 pb-32">
107-
<div class="max-w-6xl m-auto mt-10">
108-
<div class="flex w-full justify-between items-center">
109-
<div class="w-[400px]">
110-
<Input
111-
name="search"
112-
placeholder="Search a user by email, ID or name"
113-
type="text"
114-
bind:value={searchValue} />
115-
</div>
116-
<!-- <Button leftIcon={PlusSmall}>Create a new user</Button>-->
81+
<div class="w-full p-10 pb-32">
82+
<div class="max-w-6xl m-auto mt-10">
83+
<div class="flex w-full justify-between items-center">
84+
<div class="w-[400px]">
85+
<Input
86+
name="search"
87+
placeholder="Search a user by email, ID or name"
88+
type="text"
89+
bind:value={searchValue} />
11790
</div>
118-
<Spacer size="md" />
119-
120-
<Table
121-
isLoadingData={isLoadingData}
122-
totalCount={users.length}
123-
columns={columns}
124-
rows={filteredResults()}
125-
emptyTitle="You don't have any users yet"
126-
emptyDescription="Share your AI Agent publicly to get your first users." />
91+
<!-- <Button leftIcon={PlusSmall}>Create a new user</Button>-->
12792
</div>
93+
<Spacer size="md" />
94+
95+
<Table
96+
isLoadingData={isLoadingData}
97+
totalCount={users.length}
98+
columns={columns}
99+
rows={filteredResults()}
100+
emptyTitle="You don't have any users yet"
101+
emptyDescription="Share your AI Agent publicly to get your first users." />
128102
</div>
129103
</div>

0 commit comments

Comments
 (0)