mirror of
https://github.com/nikdoof/pocket-id.git
synced 2025-12-22 13:59:24 +00:00
feat: map allowed groups to OIDC clients (#202)
This commit is contained in:
75
frontend/src/lib/components/collapsible-card.svelte
Normal file
75
frontend/src/lib/components/collapsible-card.svelte
Normal file
@@ -0,0 +1,75 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils/style';
|
||||
import { LucideChevronDown } from 'lucide-svelte';
|
||||
import { onMount, type Snippet } from 'svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { Button } from './ui/button';
|
||||
import * as Card from './ui/card';
|
||||
|
||||
let {
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
defaultExpanded = false,
|
||||
children
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
defaultExpanded?: boolean;
|
||||
children: Snippet;
|
||||
} = $props();
|
||||
|
||||
let expanded = $state(defaultExpanded);
|
||||
|
||||
function loadExpandedState() {
|
||||
const state = JSON.parse(localStorage.getItem('collapsible-cards-expanded') || '{}');
|
||||
expanded = state[id] || false;
|
||||
}
|
||||
|
||||
function saveExpandedState() {
|
||||
const state = JSON.parse(localStorage.getItem('collapsible-cards-expanded') || '{}');
|
||||
state[id] = expanded;
|
||||
localStorage.setItem('collapsible-cards-expanded', JSON.stringify(state));
|
||||
}
|
||||
|
||||
function toggleExpanded() {
|
||||
expanded = !expanded;
|
||||
saveExpandedState();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (defaultExpanded) {
|
||||
saveExpandedState();
|
||||
}
|
||||
loadExpandedState();
|
||||
});
|
||||
</script>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header class="cursor-pointer" onclick={toggleExpanded}>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Card.Title>{title}</Card.Title>
|
||||
{#if description}
|
||||
<Card.Description>{description}</Card.Description>
|
||||
{/if}
|
||||
</div>
|
||||
<Button class="ml-10 h-8 p-3" variant="ghost" aria-label="Expand card">
|
||||
<LucideChevronDown
|
||||
class={cn(
|
||||
'h-5 w-5 transition-transform duration-200',
|
||||
expanded && 'rotate-180 transform'
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Card.Header>
|
||||
{#if expanded}
|
||||
<div transition:slide={{ duration: 200 }}>
|
||||
<Card.Content>
|
||||
{@render children()}
|
||||
</Card.Content>
|
||||
</div>
|
||||
{/if}
|
||||
</Card.Root>
|
||||
@@ -8,6 +8,6 @@
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<p class={cn('text-sm text-muted-foreground', className)} {...$$restProps}>
|
||||
<p class={cn('text-sm text-muted-foreground mt-1', className)} {...$$restProps}>
|
||||
<slot />
|
||||
</p>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { AuthorizeResponse, OidcClient, OidcClientCreate } from '$lib/types/oidc.type';
|
||||
import type {
|
||||
AuthorizeResponse,
|
||||
OidcClient,
|
||||
OidcClientCreate,
|
||||
OidcClientWithAllowedUserGroups
|
||||
} from '$lib/types/oidc.type';
|
||||
import type { Paginated, SearchPaginationSortRequest } from '$lib/types/pagination.type';
|
||||
import APIService from './api-service';
|
||||
|
||||
@@ -23,24 +28,13 @@ class OidcService extends APIService {
|
||||
return res.data as AuthorizeResponse;
|
||||
}
|
||||
|
||||
async authorizeNewClient(
|
||||
clientId: string,
|
||||
scope: string,
|
||||
callbackURL: string,
|
||||
nonce?: string,
|
||||
codeChallenge?: string,
|
||||
codeChallengeMethod?: string
|
||||
) {
|
||||
const res = await this.api.post('/oidc/authorize/new-client', {
|
||||
async isAuthorizationRequired(clientId: string, scope: string) {
|
||||
const res = await this.api.post('/oidc/authorization-required', {
|
||||
scope,
|
||||
nonce,
|
||||
callbackURL,
|
||||
clientId,
|
||||
codeChallenge,
|
||||
codeChallengeMethod
|
||||
clientId
|
||||
});
|
||||
|
||||
return res.data as AuthorizeResponse;
|
||||
return res.data.authorizationRequired as boolean;
|
||||
}
|
||||
|
||||
async listClients(options?: SearchPaginationSortRequest) {
|
||||
@@ -59,7 +53,7 @@ class OidcService extends APIService {
|
||||
}
|
||||
|
||||
async getClient(id: string) {
|
||||
return (await this.api.get(`/oidc/clients/${id}`)).data as OidcClient;
|
||||
return (await this.api.get(`/oidc/clients/${id}`)).data as OidcClientWithAllowedUserGroups;
|
||||
}
|
||||
|
||||
async updateClient(id: string, client: OidcClientCreate) {
|
||||
@@ -88,6 +82,11 @@ class OidcService extends APIService {
|
||||
async createClientSecret(id: string) {
|
||||
return (await this.api.post(`/oidc/clients/${id}/secret`)).data.secret as string;
|
||||
}
|
||||
|
||||
async updateAllowedUserGroups(id: string, userGroupIds: string[]) {
|
||||
const res = await this.api.put(`/oidc/clients/${id}/allowed-user-groups`, { userGroupIds });
|
||||
return res.data as OidcClientWithAllowedUserGroups;
|
||||
}
|
||||
}
|
||||
|
||||
export default OidcService;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { UserGroup } from './user-group.type';
|
||||
|
||||
export type OidcClient = {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -8,6 +10,10 @@ export type OidcClient = {
|
||||
pkceEnabled: boolean;
|
||||
};
|
||||
|
||||
export type OidcClientWithAllowedUserGroups = OidcClient & {
|
||||
allowedUserGroups: UserGroup[];
|
||||
};
|
||||
|
||||
export type OidcClientCreate = Omit<OidcClient, 'id' | 'logoURL' | 'hasLogo'>;
|
||||
|
||||
export type OidcClientCreateWithLogo = OidcClientCreate & {
|
||||
|
||||
Reference in New Issue
Block a user