mirror of
https://github.com/tale/headplane.git
synced 2026-08-21 10:16:37 +00:00
feat: reach an initial working stage
This commit is contained in:
@@ -4,29 +4,29 @@ import { useEffect, useState } from 'react';
|
||||
import type { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router';
|
||||
import { useLoaderData, useSubmit } from 'react-router';
|
||||
import { ClientOnly } from 'remix-utils/client-only';
|
||||
|
||||
import Attribute from '~/components/Attribute';
|
||||
import Card from '~/components/Card';
|
||||
import { ErrorPopup } from '~/components/Error';
|
||||
import StatusCircle from '~/components/StatusCircle';
|
||||
import type { LoadContext } from '~/server';
|
||||
import type { Machine, User } from '~/types';
|
||||
import cn from '~/utils/cn';
|
||||
import { pull } from '~/utils/headscale';
|
||||
import { getSession } from '~/utils/sessions.server';
|
||||
|
||||
import { hs_getConfig } from '~/utils/config/loader';
|
||||
import type { AppContext } from '~server/context/app';
|
||||
import { hp_getConfig } from '~server/context/global';
|
||||
import ManageBanner from './components/manage-banner';
|
||||
import DeleteUser from './dialogs/delete-user';
|
||||
import RenameUser from './dialogs/rename-user';
|
||||
import { userAction } from './user-actions';
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs<AppContext>) {
|
||||
const session = await getSession(request.headers.get('Cookie'));
|
||||
export async function loader({
|
||||
request,
|
||||
context,
|
||||
}: LoaderFunctionArgs<LoadContext>) {
|
||||
const session = await context.sessions.auth(request);
|
||||
const [machines, apiUsers] = await Promise.all([
|
||||
pull<{ nodes: Machine[] }>('v1/node', session.get('hsApiKey')!),
|
||||
pull<{ users: User[] }>('v1/user', session.get('hsApiKey')!),
|
||||
context.client.get<{ nodes: Machine[] }>(
|
||||
'v1/node',
|
||||
session.get('api_key')!,
|
||||
),
|
||||
context.client.get<{ users: User[] }>('v1/user', session.get('api_key')!),
|
||||
]);
|
||||
|
||||
const users = apiUsers.users.map((user) => ({
|
||||
@@ -34,18 +34,15 @@ export async function loader({ request }: LoaderFunctionArgs<AppContext>) {
|
||||
machines: machines.nodes.filter((machine) => machine.user.id === user.id),
|
||||
}));
|
||||
|
||||
const { oidc } = hp_getConfig();
|
||||
const { mode, config } = hs_getConfig();
|
||||
let magic: string | undefined;
|
||||
|
||||
if (mode !== 'no') {
|
||||
if (config.dns.magic_dns) {
|
||||
magic = config.dns.base_domain;
|
||||
if (context.hs.readable()) {
|
||||
if (context.hs.c?.dns.magic_dns) {
|
||||
magic = context.hs.c.dns.base_domain;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
oidc,
|
||||
oidc: context.config.oidc,
|
||||
magic,
|
||||
users,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ActionFunctionArgs, data } from 'react-router';
|
||||
import { del, post } from '~/utils/headscale';
|
||||
import { auth } from '~/utils/sessions.server';
|
||||
import type { LoadContext } from '~/server';
|
||||
|
||||
export async function userAction({ request }: ActionFunctionArgs) {
|
||||
const session = await auth(request);
|
||||
if (!session) {
|
||||
return data({ success: false }, 401);
|
||||
}
|
||||
export async function userAction({
|
||||
request,
|
||||
context,
|
||||
}: ActionFunctionArgs<LoadContext>) {
|
||||
const session = await context.sessions.auth(request);
|
||||
const apiKey = session.get('api_key')!;
|
||||
|
||||
const formData = await request.formData();
|
||||
const action = formData.get('action_id')?.toString();
|
||||
@@ -14,26 +14,25 @@ export async function userAction({ request }: ActionFunctionArgs) {
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
|
||||
const apiKey = session.get('hsApiKey');
|
||||
if (!apiKey) {
|
||||
return data({ success: false }, 401);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case 'create_user':
|
||||
return createUser(formData, apiKey);
|
||||
return createUser(formData, apiKey, context);
|
||||
case 'delete_user':
|
||||
return deleteUser(formData, apiKey);
|
||||
return deleteUser(formData, apiKey, context);
|
||||
case 'rename_user':
|
||||
return renameUser(formData, apiKey);
|
||||
return renameUser(formData, apiKey, context);
|
||||
case 'change_owner':
|
||||
return changeOwner(formData, apiKey);
|
||||
return changeOwner(formData, apiKey, context);
|
||||
default:
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
}
|
||||
|
||||
async function createUser(formData: FormData, apiKey: string) {
|
||||
async function createUser(
|
||||
formData: FormData,
|
||||
apiKey: string,
|
||||
context: LoadContext,
|
||||
) {
|
||||
const name = formData.get('username')?.toString();
|
||||
const displayName = formData.get('display_name')?.toString();
|
||||
const email = formData.get('email')?.toString();
|
||||
@@ -42,40 +41,52 @@ async function createUser(formData: FormData, apiKey: string) {
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
|
||||
await post('v1/user', apiKey, {
|
||||
await context.client.post('v1/user', apiKey, {
|
||||
name,
|
||||
displayName,
|
||||
email,
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteUser(formData: FormData, apiKey: string) {
|
||||
async function deleteUser(
|
||||
formData: FormData,
|
||||
apiKey: string,
|
||||
context: LoadContext,
|
||||
) {
|
||||
const userId = formData.get('user_id')?.toString();
|
||||
if (!userId) {
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
|
||||
await del(`v1/user/${userId}`, apiKey);
|
||||
await context.client.delete(`v1/user/${userId}`, apiKey);
|
||||
}
|
||||
|
||||
async function renameUser(formData: FormData, apiKey: string) {
|
||||
async function renameUser(
|
||||
formData: FormData,
|
||||
apiKey: string,
|
||||
context: LoadContext,
|
||||
) {
|
||||
const userId = formData.get('user_id')?.toString();
|
||||
const newName = formData.get('new_name')?.toString();
|
||||
if (!userId || !newName) {
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
|
||||
await post(`v1/user/${userId}/rename/${newName}`, apiKey);
|
||||
await context.client.post(`v1/user/${userId}/rename/${newName}`, apiKey);
|
||||
}
|
||||
|
||||
async function changeOwner(formData: FormData, apiKey: string) {
|
||||
async function changeOwner(
|
||||
formData: FormData,
|
||||
apiKey: string,
|
||||
context: LoadContext,
|
||||
) {
|
||||
const userId = formData.get('user_id')?.toString();
|
||||
const nodeId = formData.get('node_id')?.toString();
|
||||
if (!userId || !nodeId) {
|
||||
return data({ success: false }, 400);
|
||||
}
|
||||
|
||||
await post(`v1/node/${nodeId}/user`, apiKey, {
|
||||
await context.client.post(`v1/node/${nodeId}/user`, apiKey, {
|
||||
user: userId,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user