diff --git a/dashboard/bun.lockb b/dashboard/bun.lockb
index 4148b6f..457965a 100755
Binary files a/dashboard/bun.lockb and b/dashboard/bun.lockb differ
diff --git a/dashboard/package.json b/dashboard/package.json
index 589ca60..9641b8b 100644
--- a/dashboard/package.json
+++ b/dashboard/package.json
@@ -14,15 +14,13 @@
"@ory/integrations": "^1.1.5",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-checkbox": "^1.0.4",
- "@radix-ui/react-dialog": "^1.1.6",
+ "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-scroll-area": "^1.0.5",
- "@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.1",
- "@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.4",
"@serwist/next": "^9.0.0-preview.21",
@@ -32,7 +30,6 @@
"@tanstack/react-table": "^8.20.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.0",
- "cmdk": "1.0.0",
"dotenv": "^16.4.7",
"drizzle-orm": "^0.38.3",
"lucide-react": "^0.462.0",
diff --git a/dashboard/src/app/(inside)/client/create/page.tsx b/dashboard/src/app/(inside)/client/create/page.tsx
deleted file mode 100644
index 3aa3c9a..0000000
--- a/dashboard/src/app/(inside)/client/create/page.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { CreateClientForm } from '@/components/forms/client-form';
-import { createClient } from '@/lib/action/client';
-import { checkPermission, requireSession } from '@/lib/action/authentication';
-import { permission, relation } from '@/lib/permission';
-import { redirect } from 'next/navigation';
-
-export default async function CreateClientPage() {
-
- const session = await requireSession();
- const identityId = session.identity!.id;
-
- const pmCreateClient = await checkPermission(permission.client.it, relation.create, identityId);
- if (!pmCreateClient) {
- return redirect('/client');
- }
-
- return (
-
-
-
Create OAuth2 Client
-
- Configure your new OAuth2 Client.
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/dashboard/src/app/(inside)/client/page.tsx b/dashboard/src/app/(inside)/client/page.tsx
index 42e0092..0d3f5a3 100644
--- a/dashboard/src/app/(inside)/client/page.tsx
+++ b/dashboard/src/app/(inside)/client/page.tsx
@@ -1,9 +1,4 @@
import { getOAuth2Api } from '@/ory/sdk/server';
-import { Button } from '@/components/ui/button';
-import Link from 'next/link';
-import { checkPermission, requireSession } from '@/lib/action/authentication';
-import { permission, relation } from '@/lib/permission';
-import InsufficientPermission from '@/components/insufficient-permission';
import { ClientDataTable } from '@/app/(inside)/client/data-table';
export interface FetchClientPageProps {
@@ -34,12 +29,6 @@ function parseTokens(link: string) {
async function fetchClientPage({ pageSize, pageToken }: FetchClientPageProps) {
'use server';
- const session = await requireSession();
- const allowed = await checkPermission(permission.client.it, relation.access, session.identity!.id);
- if (!allowed) {
- throw Error('Unauthorised');
- }
-
const oAuth2Api = await getOAuth2Api();
const response = await oAuth2Api.listOAuth2Clients({
pageSize: pageSize,
@@ -54,49 +43,24 @@ async function fetchClientPage({ pageSize, pageToken }: FetchClientPageProps) {
export default async function ListClientPage() {
- const session = await requireSession();
- const identityId = session.identity!.id;
-
- const pmAccessClient = await checkPermission(permission.client.it, relation.access, identityId);
- const pmCreateClient = await checkPermission(permission.client.it, relation.create, identityId);
-
let pageSize = 100;
let pageToken: string = '00000000-0000-0000-0000-000000000000';
- const initialFetch = pmAccessClient && await fetchClientPage({ pageSize, pageToken });
+ const initialFetch = await fetchClientPage({ pageSize, pageToken });
return (
-
+
OAuth2 Clients
See and manage all OAuth2 clients registered with your Ory Hydra instance
- {
- pmCreateClient && (
-
- )
- }
- {
- pmAccessClient ?
- (
- initialFetch &&
- )
- :
-
- }
+
);
}
diff --git a/dashboard/src/app/globals.css b/dashboard/src/app/globals.css
index 65bc799..262da57 100644
--- a/dashboard/src/app/globals.css
+++ b/dashboard/src/app/globals.css
@@ -75,15 +75,4 @@
body {
@apply bg-sidebar text-foreground;
}
-}
-
-
-@layer base {
- * {
- @apply border-border outline-ring/50;
- }
-
- body {
- @apply bg-background text-foreground;
- }
}
\ No newline at end of file
diff --git a/dashboard/src/components/forms/client-form.tsx b/dashboard/src/components/forms/client-form.tsx
deleted file mode 100644
index 0ca84b6..0000000
--- a/dashboard/src/components/forms/client-form.tsx
+++ /dev/null
@@ -1,588 +0,0 @@
-'use client';
-
-import { z } from 'zod';
-import { clientFormSchema } from '@/lib/forms/client-form';
-import { useForm } from 'react-hook-form';
-import { zodResolver } from '@hookform/resolvers/zod';
-import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
-import { Input } from '@/components/ui/input';
-import { Button } from '@/components/ui/button';
-import { useState } from 'react';
-import { OAuth2Client } from '@ory/client';
-import { AxiosResponse } from 'axios';
-import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
-import { useRouter } from 'next/navigation';
-import { Minus } from 'lucide-react';
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
-import { Switch } from '@/components/ui/switch';
-import Link from 'next/link';
-
-interface CreateClientFormProps {
- action: (data: z.infer
) => Promise>;
-}
-
-export function CreateClientForm({ action }: CreateClientFormProps) {
-
- const router = useRouter();
-
- const [redirectUris, setRedirectUris] = useState(['']);
- const [postLogoutRedirectUris, setPostLogoutRedirectUris] = useState(['']);
-
- const form = useForm>({
- resolver: zodResolver(clientFormSchema),
- defaultValues: {
- client_name: '',
- scope: '',
- redirect_uris: [''],
- skip: false,
- logo_uri: '',
- policy_uri: '',
- tos_uri: '',
- owner: '',
- },
- });
-
- const [successDialogOpen, setSuccessDialogOpen] = useState(false);
- const [createdClient, setCreatedClient] = useState();
- const handleSubmit = async (data: z.infer) => {
- await action(data)
- .then((response) => {
- console.log(response);
- return response.data;
- })
- .then((client) => {
- setCreatedClient(client);
- setSuccessDialogOpen(true);
- })
- .catch((error) => {
- console.error(error);
- });
- };
-
- const addRedirectUri = () => {
- setRedirectUris([...redirectUris, '']);
- };
-
- const addPostLogoutRedirectUri = () => {
- setPostLogoutRedirectUris([...postLogoutRedirectUris, '']);
- };
-
- const removeRedirectUri = (index: number) => {
- const updatedRedirectUris = redirectUris.filter((_, i) => i !== index);
- setRedirectUris(updatedRedirectUris);
- form.setValue('redirect_uris', updatedRedirectUris);
- };
-
- const removePostLogoutRedirectUri = (index: number) => {
- const updatedPostLogoutRedirectUris = postLogoutRedirectUris.filter((_, i) => i !== index);
- setPostLogoutRedirectUris(postLogoutRedirectUris);
- form.setValue('post_logout_redirect_uris', updatedPostLogoutRedirectUris);
- };
-
- const handleInputChange = (index: number, event: any) => {
- const updatedRedirectUris = [...redirectUris];
- updatedRedirectUris[index] = event.target.value;
- setRedirectUris(updatedRedirectUris);
- form.setValue('redirect_uris', updatedRedirectUris);
- };
-
- const handlePostLogoutInputChange = (index: number, event: any) => {
- const updatedPostLogoutRedirectUris = [...postLogoutRedirectUris];
- updatedPostLogoutRedirectUris[index] = event.target.value;
- setPostLogoutRedirectUris(updatedPostLogoutRedirectUris);
- form.setValue('post_logout_redirect_uris', updatedPostLogoutRedirectUris);
- };
-
- return (
- <>
- {
- createdClient && (
- setSuccessDialogOpen(false)}>
-
-
- Client created
-
- Your client was created successfully. Make sure to safe the client secret!
-
-
-
- )
- }
-
-
- >
- );
-}
diff --git a/dashboard/src/components/ui/card.tsx b/dashboard/src/components/ui/card.tsx
index 22ccc98..3c69472 100644
--- a/dashboard/src/components/ui/card.tsx
+++ b/dashboard/src/components/ui/card.tsx
@@ -23,7 +23,7 @@ const CardHeader = React.forwardRef<
>(({ className, ...props }, ref) => (
));
@@ -60,7 +60,7 @@ const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
-
+
));
CardContent.displayName = 'CardContent';
@@ -70,7 +70,7 @@ const CardFooter = React.forwardRef<
>(({ className, ...props }, ref) => (
));
diff --git a/dashboard/src/components/ui/command.tsx b/dashboard/src/components/ui/command.tsx
deleted file mode 100644
index f485776..0000000
--- a/dashboard/src/components/ui/command.tsx
+++ /dev/null
@@ -1,154 +0,0 @@
-'use client';
-
-import * as React from 'react';
-import { type DialogProps } from '@radix-ui/react-dialog';
-import { Command as CommandPrimitive } from 'cmdk';
-import { Search } from 'lucide-react';
-
-import { cn } from '@/lib/utils';
-import { Dialog, DialogContent } from '@/components/ui/dialog';
-
-const Command = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-Command.displayName = CommandPrimitive.displayName;
-
-const CommandDialog = ({ children, ...props }: DialogProps) => {
- return (
-
- );
-};
-
-const CommandInput = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-
-));
-
-CommandInput.displayName = CommandPrimitive.Input.displayName;
-
-const CommandList = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-
-CommandList.displayName = CommandPrimitive.List.displayName;
-
-const CommandEmpty = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->((props, ref) => (
-
-));
-
-CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
-
-const CommandGroup = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-
-CommandGroup.displayName = CommandPrimitive.Group.displayName;
-
-const CommandSeparator = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
-
-const CommandItem = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-
-CommandItem.displayName = CommandPrimitive.Item.displayName;
-
-const CommandShortcut = ({
- className,
- ...props
- }: React.HTMLAttributes) => {
- return (
-
- );
-};
-CommandShortcut.displayName = 'CommandShortcut';
-
-export {
- Command,
- CommandDialog,
- CommandInput,
- CommandList,
- CommandEmpty,
- CommandGroup,
- CommandItem,
- CommandShortcut,
- CommandSeparator,
-};
diff --git a/dashboard/src/components/ui/dialog.tsx b/dashboard/src/components/ui/dialog.tsx
deleted file mode 100644
index c7b4160..0000000
--- a/dashboard/src/components/ui/dialog.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-'use client';
-
-import * as React from 'react';
-import * as DialogPrimitive from '@radix-ui/react-dialog';
-import { X } from 'lucide-react';
-
-import { cn } from '@/lib/utils';
-
-const Dialog = DialogPrimitive.Root;
-
-const DialogTrigger = DialogPrimitive.Trigger;
-
-const DialogPortal = DialogPrimitive.Portal;
-
-const DialogClose = DialogPrimitive.Close;
-
-const DialogOverlay = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
-
-const DialogContent = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
-
-
-
- {children}
-
-
- Close
-
-
-
-));
-DialogContent.displayName = DialogPrimitive.Content.displayName;
-
-const DialogHeader = ({
- className,
- ...props
- }: React.HTMLAttributes) => (
-
-);
-DialogHeader.displayName = 'DialogHeader';
-
-const DialogFooter = ({
- className,
- ...props
- }: React.HTMLAttributes) => (
-
-);
-DialogFooter.displayName = 'DialogFooter';
-
-const DialogTitle = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-DialogTitle.displayName = DialogPrimitive.Title.displayName;
-
-const DialogDescription = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-DialogDescription.displayName = DialogPrimitive.Description.displayName;
-
-export {
- Dialog,
- DialogPortal,
- DialogOverlay,
- DialogClose,
- DialogTrigger,
- DialogContent,
- DialogHeader,
- DialogFooter,
- DialogTitle,
- DialogDescription,
-};
diff --git a/dashboard/src/components/ui/multi-select.tsx b/dashboard/src/components/ui/multi-select.tsx
deleted file mode 100644
index 266eea7..0000000
--- a/dashboard/src/components/ui/multi-select.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-'use client';
-
-import * as React from 'react';
-import { X } from 'lucide-react';
-
-import { Badge } from '@/components/ui/badge';
-import { Command, CommandGroup, CommandItem, CommandList } from '@/components/ui/command';
-import { Command as CommandPrimitive } from 'cmdk';
-
-type MultiSelectItem = Record<'value' | 'label', string>;
-
-interface MultiSelectProps {
- items: MultiSelectItem[];
- placeholder?: string;
-}
-
-// Credits: https://github.com/mxkaske/mxkaske.dev/blob/main/components/craft/fancy-multi-select.tsx
-export function MultiSelect({ items, placeholder }: MultiSelectProps) {
- const inputRef = React.useRef(null);
- const [open, setOpen] = React.useState(false);
- const [selected, setSelected] = React.useState([]);
- const [inputValue, setInputValue] = React.useState('');
-
- const handleUnselect = React.useCallback((item: MultiSelectItem) => {
- setSelected((prev) => prev.filter((s) => s.value !== item.value));
- }, []);
-
- const handleKeyDown = React.useCallback(
- (e: React.KeyboardEvent) => {
- const input = inputRef.current;
- if (input) {
- if (e.key === 'Delete' || e.key === 'Backspace') {
- if (input.value === '') {
- setSelected((prev) => {
- const newSelected = [...prev];
- newSelected.pop();
- return newSelected;
- });
- }
- }
- // This is not a default behaviour of the field
- if (e.key === 'Escape') {
- input.blur();
- }
- }
- },
- [],
- );
-
- const selectables = items.filter(
- (item) => !selected.includes(item),
- );
-
- console.log(selectables, selected, inputValue);
-
- return (
-
-
-
- {selected.map((item) => {
- return (
-
- {item.label}
-
-
- );
- })}
- {/* Avoid having the "Search" Icon */}
- setOpen(false)}
- onFocus={() => setOpen(true)}
- placeholder={placeholder ?? 'Select an item...'}
- className="ml-2 flex-1 bg-transparent outline-none placeholder:text-muted-foreground"
- />
-
-
-
-
- {open && selectables.length > 0 ? (
-
-
- {selectables.map((item) => {
- return (
- {
- e.preventDefault();
- e.stopPropagation();
- }}
- onSelect={(value) => {
- setInputValue('');
- setSelected((prev) => [...prev, item]);
- }}
- className={'cursor-pointer'}
- >
- {item.label}
-
- );
- })}
-
-
- ) : null}
-
-
-
- );
-}
\ No newline at end of file
diff --git a/dashboard/src/components/ui/select.tsx b/dashboard/src/components/ui/select.tsx
deleted file mode 100644
index ddd77ac..0000000
--- a/dashboard/src/components/ui/select.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-'use client';
-
-import * as React from 'react';
-import * as SelectPrimitive from '@radix-ui/react-select';
-import { Check, ChevronDown, ChevronUp } from 'lucide-react';
-
-import { cn } from '@/lib/utils';
-
-const Select = SelectPrimitive.Root;
-
-const SelectGroup = SelectPrimitive.Group;
-
-const SelectValue = SelectPrimitive.Value;
-
-const SelectTrigger = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
- span]:line-clamp-1',
- className,
- )}
- {...props}
- >
- {children}
-
-
-
-
-));
-SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
-
-const SelectScrollUpButton = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-));
-SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
-
-const SelectScrollDownButton = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-));
-SelectScrollDownButton.displayName =
- SelectPrimitive.ScrollDownButton.displayName;
-
-const SelectContent = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, position = 'popper', ...props }, ref) => (
-
-
-
-
- {children}
-
-
-
-
-));
-SelectContent.displayName = SelectPrimitive.Content.displayName;
-
-const SelectLabel = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-SelectLabel.displayName = SelectPrimitive.Label.displayName;
-
-const SelectItem = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, children, ...props }, ref) => (
-
-
-
-
-
-
-
- {children}
-
-));
-SelectItem.displayName = SelectPrimitive.Item.displayName;
-
-const SelectSeparator = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-));
-SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
-
-export {
- Select,
- SelectGroup,
- SelectValue,
- SelectTrigger,
- SelectContent,
- SelectLabel,
- SelectItem,
- SelectSeparator,
- SelectScrollUpButton,
- SelectScrollDownButton,
-};
diff --git a/dashboard/src/components/ui/switch.tsx b/dashboard/src/components/ui/switch.tsx
deleted file mode 100644
index 4c01734..0000000
--- a/dashboard/src/components/ui/switch.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-'use client';
-
-import * as React from 'react';
-import * as SwitchPrimitives from '@radix-ui/react-switch';
-
-import { cn } from '@/lib/utils';
-
-const Switch = React.forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
-
-
-
-));
-Switch.displayName = SwitchPrimitives.Root.displayName;
-
-export { Switch };
diff --git a/dashboard/src/lib/action/client.ts b/dashboard/src/lib/action/client.ts
deleted file mode 100644
index fb5156b..0000000
--- a/dashboard/src/lib/action/client.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-'use server';
-
-import { clientFormSchema } from '@/lib/forms/client-form';
-import { z } from 'zod';
-import { getOAuth2Api } from '@/ory/sdk/server';
-import { checkPermission, requireSession } from '@/lib/action/authentication';
-import { permission, relation } from '@/lib/permission';
-
-export async function createClient(
- formData: z.infer,
-) {
-
- const session = await requireSession();
- const allowed = await checkPermission(permission.client.it, relation.create, session.identity!.id);
- if (!allowed) {
- throw Error('Unauthorised');
- }
-
- console.log(session.identity?.traits.email, 'posted form', formData);
-
- const oauthApi = await getOAuth2Api();
- return await oauthApi.createOAuth2Client({ oAuth2Client: formData });
-}
diff --git a/dashboard/src/lib/forms/client-form.ts b/dashboard/src/lib/forms/client-form.ts
deleted file mode 100644
index ea3814e..0000000
--- a/dashboard/src/lib/forms/client-form.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { z } from 'zod';
-
-export const clientFormSchema = z.object({
- access_token_strategy: z.string().default('opaque').readonly(),
- client_name: z.string().min(1, 'Client name is required'),
- scope: z.string(),
- redirect_uris: z.array(z.string().url({ message: 'Invalid URL' })).min(1, { message: 'At least one redirect URI is required' }),
- skip: z.boolean(),
- logo_uri: z.string().url(),
- tos_uri: z.string().url(),
- policy_uri: z.string().url(),
- owner: z.string().min(1, 'Owner is required'),
- grant_types: z.array(z.string()),
- response_types: z.array(z.string()),
- token_endpoint_auth_method: z.string(),
- backchannel_logout_session_required: z.boolean().default(false),
- backchannel_logout_uri: z.string().url(),
- frontchannel_logout_session_required: z.boolean().default(false),
- frontchannel_logout_uri: z.string().url(),
- skip_logout_consent: z.boolean().default(false),
- post_logout_redirect_uris: z.array(z.string().url({ message: 'Invalid URL' })).min(1, { message: 'At least one redirect URI is required' }),
-});
diff --git a/dashboard/src/lib/permission.ts b/dashboard/src/lib/permission.ts
index 38619ac..9fc8ba0 100644
--- a/dashboard/src/lib/permission.ts
+++ b/dashboard/src/lib/permission.ts
@@ -13,9 +13,6 @@ export const permission = {
state: 'admin.user.state',
trait: 'admin.user.trait',
},
- client: {
- it: 'admin.client',
- },
};
export const relation = {