diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx
new file mode 100644
index 0000000..4a949b9
--- /dev/null
+++ b/app/components/Footer.tsx
@@ -0,0 +1,44 @@
+import { cn } from '~/utils/cn'
+import Link from '~/components/Link'
+
+interface FooterProps {
+ url: string
+ debug: boolean
+}
+
+export default function Footer({ url, debug, integration }: FooterProps) {
+ return (
+
+ )
+}
+
diff --git a/app/routes/_data.tsx b/app/layouts/dashboard.tsx
similarity index 66%
rename from app/routes/_data.tsx
rename to app/layouts/dashboard.tsx
index 31c0cd9..c855bb1 100644
--- a/app/routes/_data.tsx
+++ b/app/layouts/dashboard.tsx
@@ -4,6 +4,7 @@ import { ProgressBar } from 'react-aria-components'
import { ErrorPopup } from '~/components/Error'
import Header from '~/components/Header'
+import Footer from '~/components/Footer'
import Link from '~/components/Link'
import { cn } from '~/utils/cn'
import { loadContext } from '~/utils/config/headplane'
@@ -17,14 +18,12 @@ export async function loader({ request }: LoaderFunctionArgs) {
}
try {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
await pull('v1/apikey', session.get('hsApiKey')!)
} catch (error) {
if (error instanceof HeadscaleError) {
// Safest to just redirect to login if we can't pull
return redirect('/login', {
headers: {
- // eslint-disable-next-line @typescript-eslint/naming-convention
'Set-Cookie': await destroySession(session),
},
})
@@ -43,47 +42,6 @@ export async function loader({ request }: LoaderFunctionArgs) {
}
}
-interface FooterProps {
- url: string
- debug: boolean
-}
-
-function Footer({ url, debug, integration }: FooterProps) {
- return (
-
- )
-}
-
export default function Layout() {
const data = useLoaderData()
const nav = useNavigation()
diff --git a/app/routes.ts b/app/routes.ts
index 1185cfe..98aa317 100644
--- a/app/routes.ts
+++ b/app/routes.ts
@@ -1,3 +1,35 @@
-import { flatRoutes } from '@remix-run/fs-routes'
+//import { flatRoutes } from '@remix-run/fs-routes'
+import { index, layout, prefix, route } from '@remix-run/route-config'
+
+export default [
+ // Utility Routes
+ index('routes/_index.tsx'),
+ route('/healthz', 'routes/healthz.tsx'),
+
+ // Authentication Routes
+ route('/login', 'routes/auth/login.tsx'),
+ route('/logout', 'routes/auth/logout.ts'),
+ route('/oidc/callback', 'routes/auth/oidc-callback.ts'),
+
+ // All the main logged-in dashboard routes
+ layout('layouts/dashboard.tsx', [
+ ...prefix('/machines', [
+ index('routes/_data.machines._index/route.tsx'),
+ route('/:id', 'routes/_data.machines.$id/route.tsx'),
+ ]),
+ ...prefix('/users', [
+ index('routes/_data.users._index/route.tsx'),
+ ]),
+ ...prefix('/dns', [
+ index('routes/_data.dns._index/route.tsx'),
+ ]),
+ ...prefix('/acls', [
+ index('routes/_data.acls._index/route.tsx'),
+ ]),
+ ...prefix('/settings', [
+ index('routes/_data.settings._index/route.tsx'),
+ route('/auth-keys', 'routes/_data.settings.auth-keys._index/route.tsx'),
+ ]),
+ ])
+]
-export default flatRoutes()
diff --git a/app/routes/login.tsx b/app/routes/auth/login.tsx
similarity index 96%
rename from app/routes/login.tsx
rename to app/routes/auth/login.tsx
index 67a0e13..6eebd7f 100644
--- a/app/routes/login.tsx
+++ b/app/routes/auth/login.tsx
@@ -17,7 +17,6 @@ export async function loader({ request }: LoaderFunctionArgs) {
if (session.has('hsApiKey')) {
return redirect('/machines', {
headers: {
- // eslint-disable-next-line @typescript-eslint/naming-convention
'Set-Cookie': await commitSession(session),
},
})
@@ -74,7 +73,6 @@ export async function action({ request }: ActionFunctionArgs) {
return redirect('/machines', {
headers: {
- // eslint-disable-next-line @typescript-eslint/naming-convention
'Set-Cookie': await commitSession(session, {
maxAge: expiresIn,
}),
diff --git a/app/routes/logout.tsx b/app/routes/auth/logout.ts
similarity index 52%
rename from app/routes/logout.tsx
rename to app/routes/auth/logout.ts
index 8539078..c5ddab2 100644
--- a/app/routes/logout.tsx
+++ b/app/routes/auth/logout.ts
@@ -1,14 +1,14 @@
-import { type ActionFunctionArgs, redirect } from '@remix-run/node'
-
+import { ActionFunctionArgs, redirect } from '@remix-run/node'
import { destroySession, getSession } from '~/utils/sessions'
+export async function loader() {
+ return redirect('/machines')
+}
+
export async function action({ request }: ActionFunctionArgs) {
const session = await getSession(request.headers.get('Cookie'))
- const returnTo = new URL(request.url).pathname
-
- return redirect(`/login?returnTo=${returnTo}`, {
+ return redirect('/login', {
headers: {
- // eslint-disable-next-line @typescript-eslint/naming-convention
'Set-Cookie': await destroySession(session)
}
})
diff --git a/app/routes/auth/oidc-callback.ts b/app/routes/auth/oidc-callback.ts
new file mode 100644
index 0000000..e2a197b
--- /dev/null
+++ b/app/routes/auth/oidc-callback.ts
@@ -0,0 +1,17 @@
+import { LoaderFunctionArgs, data } from '@remix-run/node'
+import { loadContext } from '~/utils/config/headplane'
+import { finishOidc } from '~/utils/oidc'
+
+export async function loader({ request }: LoaderFunctionArgs) {
+ try {
+ const context = await loadContext()
+ if (!context.oidc) {
+ throw new Error('An invalid OIDC configuration was provided')
+ }
+
+ return finishOidc(context.oidc, request)
+ } catch (error) {
+ // Gracefully present OIDC errors
+ return data({ error }, { status: 500 })
+ }
+}
diff --git a/app/routes/oidc.callback.tsx b/app/routes/oidc.callback.tsx
deleted file mode 100644
index ed40b87..0000000
--- a/app/routes/oidc.callback.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { type LoaderFunctionArgs } from '@remix-run/node'
-
-import { loadContext } from '~/utils/config/headplane'
-import { finishOidc } from '~/utils/oidc'
-
-export async function loader({ request }: LoaderFunctionArgs) {
- const context = await loadContext()
- if (!context.oidc) {
- throw new Error('An invalid OIDC configuration was provided')
- }
-
- return finishOidc(context.oidc, request)
-}