diff --git a/app/components/Error.tsx b/app/components/Error.tsx
index 9297f35..a867a7a 100644
--- a/app/components/Error.tsx
+++ b/app/components/Error.tsx
@@ -1,16 +1,36 @@
import { AlertIcon } from '@primer/octicons-react';
import { isRouteErrorResponse, useRouteError } from 'react-router';
+import ResponseError from '~/server/headscale/api-error';
import cn from '~/utils/cn';
import Card from './Card';
-import Code from './Code';
interface Props {
type?: 'full' | 'embedded';
}
-function getMessage(error: Error | unknown) {
+function getMessage(error: Error | unknown): {
+ title: string;
+ message: string;
+} {
+ if (error instanceof ResponseError) {
+ if (error.responseObject?.message) {
+ return {
+ title: 'Headscale Error',
+ message: String(error.responseObject.message),
+ };
+ }
+
+ return {
+ title: 'Headscale Error',
+ message: error.response,
+ };
+ }
+
if (!(error instanceof Error)) {
- return 'An unknown error occurred';
+ return {
+ title: 'Unknown Error',
+ message: String(error),
+ };
}
let rootError = error;
@@ -25,16 +45,22 @@ function getMessage(error: Error | unknown) {
// If we are aggregate, concat into a single message
if (rootError instanceof AggregateError) {
- return rootError.errors.map((error) => error.message).join('\n');
+ return {
+ title: 'Errors',
+ message: rootError.errors.map((error) => error.message).join('\n'),
+ };
}
- return rootError.message;
+ return {
+ title: 'Error',
+ message: rootError.message,
+ };
}
export function ErrorPopup({ type = 'full' }: Props) {
const error = useRouteError();
const routing = isRouteErrorResponse(error);
- const message = getMessage(error);
+ const { title, message } = getMessage(error);
return (
- {routing ? error.status : 'Error'}
+ {routing ? error.status : title}
-
- {routing ? error.statusText : {message}}
+
+ {routing ? error.data.message : message}
diff --git a/app/layouts/dashboard.tsx b/app/layouts/dashboard.tsx
index 142ae14..7e3b54b 100644
--- a/app/layouts/dashboard.tsx
+++ b/app/layouts/dashboard.tsx
@@ -3,7 +3,7 @@ import { type LoaderFunctionArgs, redirect } from 'react-router';
import { Outlet, useLoaderData } from 'react-router';
import { ErrorPopup } from '~/components/Error';
import type { LoadContext } from '~/server';
-import { ResponseError } from '~/server/headscale/api-client';
+import ResponseError from '~/server/headscale/api-error';
import cn from '~/utils/cn';
import log from '~/utils/log';
diff --git a/app/layouts/shell.tsx b/app/layouts/shell.tsx
index e9ac3fa..8c3d2c3 100644
--- a/app/layouts/shell.tsx
+++ b/app/layouts/shell.tsx
@@ -1,4 +1,4 @@
-import { BanIcon, CircleCheckIcon } from 'lucide-react';
+import { CircleCheckIcon } from 'lucide-react';
import {
LoaderFunctionArgs,
Outlet,
diff --git a/app/routes.ts b/app/routes.ts
index fd56844..1a0adb4 100644
--- a/app/routes.ts
+++ b/app/routes.ts
@@ -23,7 +23,7 @@ export default [
]),
route('/users', 'routes/users/overview.tsx'),
- route('/acls', 'routes/acls/editor.tsx'),
+ route('/acls', 'routes/acls/overview.tsx'),
route('/dns', 'routes/dns/overview.tsx'),
...prefix('/settings', [
diff --git a/app/server/headscale/api-client.ts b/app/server/headscale/api-client.ts
index a64346e..3de5638 100644
--- a/app/server/headscale/api-client.ts
+++ b/app/server/headscale/api-client.ts
@@ -1,6 +1,7 @@
import { readFile } from 'node:fs/promises';
import { Agent, Dispatcher, request } from 'undici';
import log from '~/utils/log';
+import ResponseError from './api-error';
export async function createApiClient(base: string, certPath?: string) {
if (!certPath) {
@@ -20,20 +21,6 @@ export async function createApiClient(base: string, certPath?: string) {
}
}
-// Represents an error that occurred during a response
-// Thrown when status codes are >= 400
-export class ResponseError extends Error {
- status: number;
- response: string;
-
- constructor(status: number, response: string) {
- super(`Response Error (${status}): ${response}`);
- this.name = 'ResponseError';
- this.status = status;
- this.response = response;
- }
-}
-
export class ApiClient {
private agent: Agent;
private base: string;
diff --git a/app/server/web/roles.ts b/app/server/web/roles.ts
index abe99b9..2569cb2 100644
--- a/app/server/web/roles.ts
+++ b/app/server/web/roles.ts
@@ -3,10 +3,10 @@ export const Capabilities = {
// Can access the admin console
ui_access: 1 << 0,
- // Read tailnet policy file
+ // Read tailnet policy file (unimplemented)
read_policy: 1 << 1,
- // Write tailnet policy file
+ // Write tailnet policy file (unimplemented)
write_policy: 1 << 2,
// Read network configurations
@@ -16,13 +16,13 @@ export const Capabilities = {
// make subnet, or allow a node to be an exit node, enable HTTPS
write_network: 1 << 4,
- // Read feature configuration
+ // Read feature configuration (unimplemented)
read_feature: 1 << 5,
- // Write feature configuration, for example, enable Taildrop
+ // Write feature configuration, for example, enable Taildrop (unimplemented)
write_feature: 1 << 6,
- // Configure user & group provisioning
+ // Configure user & group provisioning (unimplemented)
configure_iam: 1 << 7,
// Read machines, for example, see machine names and status
@@ -38,13 +38,13 @@ export const Capabilities = {
// approve users, make Admin
write_users: 1 << 11,
- // Can generate authkeys
+ // Can generate authkeys (unimplemented)
generate_authkeys: 1 << 12,
- // Can use any tag (without being tag owner)
+ // Can use any tag (without being tag owner) (unimplemented)
use_tags: 1 << 13,
- // Write tailnet name
+ // Write tailnet name (unimplemented)
write_tailnet: 1 << 14,
// Owner flag
diff --git a/app/utils/res.ts b/app/utils/res.ts
index 680c864..d0e1e7a 100644
--- a/app/utils/res.ts
+++ b/app/utils/res.ts
@@ -19,10 +19,13 @@ export function data400(message: string) {
}
export function data403(message: string) {
- return data({
- success: false,
- message,
- });
+ return data(
+ {
+ success: false,
+ message,
+ },
+ { status: 403 },
+ );
}
export function data404(message: string) {