diff --git a/authentication/src/app/flow/consent/page.tsx b/authentication/src/app/flow/consent/page.tsx index 122b8a7..9b55ee2 100644 --- a/authentication/src/app/flow/consent/page.tsx +++ b/authentication/src/app/flow/consent/page.tsx @@ -2,11 +2,11 @@ import React from 'react'; import { Card } from '@/components/ui/card'; -import getHydra from '@/ory/sdk/hydra'; import { OAuth2ConsentRequest, OAuth2RedirectTo } from '@ory/client'; import ConsentForm from '@/components/consentForm'; import { redirect } from 'next/navigation'; import { toast } from 'sonner'; +import { getOAuth2Api } from '@/ory/sdk/server'; export default async function Consent(props: { searchParams: Promise<{ consent_challenge: string }> }) { @@ -18,7 +18,7 @@ export default async function Consent(props: { searchParams: Promise<{ consent_c const onAccept = async (challenge: string, scopes: string[], remember: boolean) => { 'use server'; - const hydra = await getHydra(); + const hydra = await getOAuth2Api(); const response = await hydra .acceptOAuth2ConsentRequest({ consentChallenge: challenge, @@ -43,7 +43,7 @@ export default async function Consent(props: { searchParams: Promise<{ consent_c const onReject = async (challenge: string) => { 'use server'; - const hydra = await getHydra(); + const hydra = await getOAuth2Api(); const response: OAuth2RedirectTo | void = await hydra .rejectOAuth2ConsentRequest({ consentChallenge: challenge, @@ -64,7 +64,7 @@ export default async function Consent(props: { searchParams: Promise<{ consent_c return; } - const hydra = await getHydra(); + const hydra = await getOAuth2Api(); await hydra .getOAuth2ConsentRequest({ consentChallenge }) .then(({ data }) => { diff --git a/authentication/src/app/flow/error/page.tsx b/authentication/src/app/flow/error/page.tsx index 66153da..e35626f 100644 --- a/authentication/src/app/flow/error/page.tsx +++ b/authentication/src/app/flow/error/page.tsx @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { FlowError } from '@ory/client'; import { AxiosError } from 'axios'; -import { kratos } from '@/ory/sdk/kratos'; +import { kratos } from '@/ory'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; diff --git a/authentication/src/app/flow/login/page.tsx b/authentication/src/app/flow/login/page.tsx index 74e75a9..6d08e30 100644 --- a/authentication/src/app/flow/login/page.tsx +++ b/authentication/src/app/flow/login/page.tsx @@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Flow, HandleError, LogoutLink } from '@/ory'; +import { Flow, HandleError, kratos, LogoutLink } from '@/ory'; import Link from 'next/link'; import { LoginFlow, UpdateLoginFlowBody } from '@ory/client'; -import { kratos } from '@/ory/sdk/kratos'; import { Button } from '@/components/ui/button'; import { useRouter, useSearchParams } from 'next/navigation'; import Image from 'next/image'; diff --git a/authentication/src/app/flow/recovery/page.tsx b/authentication/src/app/flow/recovery/page.tsx index 12fde67..7d699be 100644 --- a/authentication/src/app/flow/recovery/page.tsx +++ b/authentication/src/app/flow/recovery/page.tsx @@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Flow, HandleError } from '@/ory'; +import { Flow, HandleError, kratos } from '@/ory'; import { RecoveryFlow, UpdateRecoveryFlowBody } from '@ory/client'; import { AxiosError } from 'axios'; -import { kratos } from '@/ory/sdk/kratos'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; diff --git a/authentication/src/app/flow/registration/page.tsx b/authentication/src/app/flow/registration/page.tsx index 0b020d5..7a26aca 100644 --- a/authentication/src/app/flow/registration/page.tsx +++ b/authentication/src/app/flow/registration/page.tsx @@ -2,11 +2,10 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Flow, HandleError } from '@/ory'; +import { Flow, HandleError, kratos } from '@/ory'; import Link from 'next/link'; import { RegistrationFlow, UpdateRegistrationFlowBody } from '@ory/client'; import { AxiosError } from 'axios'; -import { kratos } from '@/ory/sdk/kratos'; import { useRouter, useSearchParams } from 'next/navigation'; import { Button } from '@/components/ui/button'; import { Skeleton } from '@/components/ui/skeleton'; diff --git a/authentication/src/app/flow/verification/page.tsx b/authentication/src/app/flow/verification/page.tsx index c165776..ac18b79 100644 --- a/authentication/src/app/flow/verification/page.tsx +++ b/authentication/src/app/flow/verification/page.tsx @@ -2,10 +2,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Flow, HandleError } from '@/ory'; +import { Flow, HandleError, kratos } from '@/ory'; import { UpdateVerificationFlowBody, VerificationFlow } from '@ory/client'; import { AxiosError } from 'axios'; -import { kratos } from '@/ory/sdk/kratos'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; diff --git a/authentication/src/middleware.ts b/authentication/src/middleware.ts index 7867e96..676100f 100644 --- a/authentication/src/middleware.ts +++ b/authentication/src/middleware.ts @@ -1,5 +1,5 @@ import { NextRequest, NextResponse } from 'next/server'; -import { getFrontendApi } from '@/ory/sdk/hydra'; +import { getFrontendApi } from 'ory/sdk/server'; import { cookies } from 'next/headers'; export async function middleware(request: NextRequest) { diff --git a/authentication/src/ory/hooks.tsx b/authentication/src/ory/hooks.tsx index a87ad2d..5c81e04 100644 --- a/authentication/src/ory/hooks.tsx +++ b/authentication/src/ory/hooks.tsx @@ -3,7 +3,7 @@ import { AxiosError } from 'axios'; import React, { DependencyList, useEffect, useState } from 'react'; -import { kratos } from './sdk/kratos'; +import { kratos } from './sdk/client'; import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime'; export const HandleError = ( diff --git a/authentication/src/ory/index.ts b/authentication/src/ory/index.ts index 7e4d8b3..762b5dc 100644 --- a/authentication/src/ory/index.ts +++ b/authentication/src/ory/index.ts @@ -1,3 +1,3 @@ export * from './hooks'; export * from './ui'; -export * from './sdk/kratos'; +export * from './sdk/client'; diff --git a/authentication/src/ory/sdk/kratos/index.ts b/authentication/src/ory/sdk/client/index.ts similarity index 100% rename from authentication/src/ory/sdk/kratos/index.ts rename to authentication/src/ory/sdk/client/index.ts diff --git a/authentication/src/ory/sdk/hydra/index.ts b/authentication/src/ory/sdk/hydra/index.ts deleted file mode 100644 index 335cd85..0000000 --- a/authentication/src/ory/sdk/hydra/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -'use server'; - -import { Configuration, OAuth2Api } from '@ory/client'; - -// implemented as a function because of 'use server' -export default async function getHydra() { - return new OAuth2Api(new Configuration( - new Configuration({ - basePath: process.env.ORY_HYDRA_ADMIN_URL, - baseOptions: { - withCredentials: true, - }, - }), - )); -} \ No newline at end of file diff --git a/authentication/src/ory/sdk/server/index.ts b/authentication/src/ory/sdk/server/index.ts new file mode 100644 index 0000000..dd43e75 --- /dev/null +++ b/authentication/src/ory/sdk/server/index.ts @@ -0,0 +1,39 @@ +'use server'; + +import { Configuration, FrontendApi, OAuth2Api } from '@ory/client'; + + +// #################################################################################### +// OAuth2 API +// #################################################################################### + +const oAuth2Api = new OAuth2Api(new Configuration( + { + basePath: process.env.ORY_HYDRA_ADMIN_URL, + baseOptions: { + withCredentials: true, + }, + }, +)); + +export async function getOAuth2Api() { + return oAuth2Api; +} + + +// #################################################################################### +// Frontend API +// #################################################################################### + +const frontendApi = new FrontendApi( + new Configuration({ + basePath: process.env.NEXT_PUBLIC_ORY_KRATOS_URL, + baseOptions: { + withCredentials: true, + }, + }), +); + +export async function getFrontendApi() { + return frontendApi; +} diff --git a/dashboard/src/app/layout.tsx b/dashboard/src/app/layout.tsx index 68326d3..51548bd 100644 --- a/dashboard/src/app/layout.tsx +++ b/dashboard/src/app/layout.tsx @@ -5,8 +5,10 @@ import { cn } from '@/lib/utils'; import { Toaster } from '@/components/ui/sonner'; import React from 'react'; import { ThemeProvider } from 'next-themes'; -import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; +import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; import { AppSidebar } from '@/components/app-sidebar'; +import { Separator } from '@/components/ui/separator'; +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList } from '@/components/ui/breadcrumb'; const inter = Inter({ subsets: ['latin'] }); @@ -48,23 +50,38 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac /> -
- - - - -
+ + + + +
+ + + { + // TODO: implement dynamic Breadcrumbs + } + + + + + Ory Dashboard + + + + +
+
{children} -
-
-
-
+ + + + ); diff --git a/dashboard/src/app/page.tsx b/dashboard/src/app/page.tsx index 279b6e1..72fa7dc 100644 --- a/dashboard/src/app/page.tsx +++ b/dashboard/src/app/page.tsx @@ -1,3 +1,81 @@ +import { getHydraMetadataApi, getKratosMetadataApi } from '@/ory/sdk/server'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; + export default async function RootPage() { - return <>; + + const kratosMetadataApi = await getKratosMetadataApi(); + + const kratosVersion = await kratosMetadataApi + .getVersion() + .then(res => res.data.version) + .catch(() => ''); + + const kratosStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive'); + const kratosStatus = await kratosStatusData.json() as { status: string }; + + const kratosDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready'); + const kratosDBStatus = await kratosDBStatusData.json() as { status: string }; + + const hydraMetadataApi = await getHydraMetadataApi(); + + const hydraVersion = await hydraMetadataApi + .getVersion() + .then(res => res.data.version) + .catch(() => ''); + + const hydraStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive'); + const hydraStatus = await hydraStatusData.json() as { status: string }; + + const hydraDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready'); + const hydraDBStatus = await hydraDBStatusData.json() as { status: string }; + + return ( +
+
+

Software Stack

+

See the list of all applications in your stack

+
+
+ + + + Ory Kratos + + + Version {kratosVersion} + + + + + Kratos {kratosStatus.status.toUpperCase()} + + + Database {kratosDBStatus.status.toUpperCase()} + + + + + + + Ory Hydra + + + Version {hydraVersion} + + + + + Hydra {hydraStatus.status.toUpperCase()} + + + Database {hydraDBStatus.status.toUpperCase()} + + + +
+
+
+
+ ); } diff --git a/dashboard/src/components/app-sidebar.tsx b/dashboard/src/components/app-sidebar.tsx index d506db8..5598b4a 100644 --- a/dashboard/src/components/app-sidebar.tsx +++ b/dashboard/src/components/app-sidebar.tsx @@ -45,7 +45,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { ]; return ( - + Application diff --git a/dashboard/src/components/ui/badge.tsx b/dashboard/src/components/ui/badge.tsx index a59a355..fdf0a19 100644 --- a/dashboard/src/components/ui/badge.tsx +++ b/dashboard/src/components/ui/badge.tsx @@ -14,6 +14,8 @@ const badgeVariants = cva( 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', + success: + 'border-transparent bg-emerald-600 text-white hover:bg-emerald-600/80', outline: 'text-foreground', }, }, diff --git a/dashboard/src/components/ui/breadcrumb.tsx b/dashboard/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..a76f836 --- /dev/null +++ b/dashboard/src/components/ui/breadcrumb.tsx @@ -0,0 +1,115 @@ +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { ChevronRight, MoreHorizontal } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<'nav'> & { + separator?: React.ReactNode +} +>(({ ...props }, ref) =>