mirror of
https://github.com/house-of-vanity/OutFleet.git
synced 2025-10-25 09:49:08 +00:00
feat: added template innbounding feature
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { useForm, type SubmitHandler } from 'react-hook-form'
|
||||
import type { CreateTemplateForm } from '../../types';
|
||||
import { useAppDispatch } from '../../../../common/hooks';
|
||||
import { protocolOptions } from './util'
|
||||
import type { CreateTemplateDTO } from '../../duck/dto';
|
||||
import { createTemplateAction } from '../../duck';
|
||||
|
||||
|
||||
export const AddTemplate = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const { register, handleSubmit, reset } = useForm<CreateTemplateForm>({
|
||||
defaultValues: {
|
||||
default_port: '443'
|
||||
}
|
||||
});
|
||||
|
||||
const onSubmit: SubmitHandler<CreateTemplateForm> = (values) => {
|
||||
const data: CreateTemplateDTO = {
|
||||
...values,
|
||||
default_port: parseInt(values.default_port),
|
||||
config_template: ''
|
||||
}
|
||||
dispatch(createTemplateAction(data)).then(() => {
|
||||
reset();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} id="templateForm">
|
||||
<div className="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" {...register('name', { required: true })} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Protocol:</label>
|
||||
<select {...register('protocol', {required: true})}>
|
||||
{Object.entries(protocolOptions).map((protocolTupple)=> (
|
||||
<option value={protocolTupple[0]}>{protocolTupple[1]}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Default Port:</label>
|
||||
<input type="number" {...register('default_port', {required: true})} />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<input type="checkbox" {...register('requires_tls')}/> Requires TLS
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Add Template
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './add-template'
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Protocol } from '../../duck/dto'
|
||||
|
||||
export const protocolOptions: Record<Protocol, string> = {
|
||||
vless: 'VLESS',
|
||||
vmess: 'VMess',
|
||||
trojan: 'Trojan',
|
||||
shadowsocks: 'Shadowsocks'
|
||||
}
|
||||
|
||||
2
client/src/features/templates/components/index.ts
Normal file
2
client/src/features/templates/components/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './add-template'
|
||||
export * from './template-list'
|
||||
@@ -0,0 +1 @@
|
||||
export * from './template-list'
|
||||
@@ -0,0 +1,122 @@
|
||||
import { useEffect, type FC } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import {
|
||||
Modal,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Button,
|
||||
} from '@heroui/react';
|
||||
import type { EditTemplateForm } from '../../types';
|
||||
import { useAppDispatch } from '../../../../common/hooks';
|
||||
import { getTemplateById } from '../../duck/api';
|
||||
import { protocolOptions } from '../add-template/util';
|
||||
import { updateTemplate } from '../../duck';
|
||||
|
||||
export interface ServerEditProps {
|
||||
templateId: string;
|
||||
isOpen: boolean;
|
||||
onOpenChange: () => void;
|
||||
}
|
||||
|
||||
export const TemplateEdit: FC<ServerEditProps> = (props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { templateId, isOpen, onOpenChange } = props;
|
||||
const { register, handleSubmit, reset } = useForm<EditTemplateForm>();
|
||||
|
||||
useEffect(() => {
|
||||
getTemplateById(templateId).then((response) => {
|
||||
const { data } = response;
|
||||
reset({
|
||||
...data,
|
||||
default_port: String(data.default_port),
|
||||
});
|
||||
});
|
||||
}, [templateId]);
|
||||
|
||||
const onSubmit = (values: EditTemplateForm) => {
|
||||
const data = {
|
||||
...values,
|
||||
default_port: parseInt(values.default_port),
|
||||
};
|
||||
|
||||
console.log({data})
|
||||
|
||||
dispatch(
|
||||
updateTemplate({
|
||||
id: templateId,
|
||||
server: data,
|
||||
}),
|
||||
).then(() => {
|
||||
onOpenChange();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<ModalContent>
|
||||
{(onClose) => (
|
||||
<>
|
||||
<ModalHeader className="flex flex-col gap-1">
|
||||
Modal Title
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<div>
|
||||
<div className="form-group">
|
||||
<label>Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
{...register('name', { required: true })}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Protocol:</label>
|
||||
<select
|
||||
id="editProtocol"
|
||||
{...register('protocol', { required: true })}
|
||||
>
|
||||
{Object.entries(protocolOptions).map((protocolTupple) => (
|
||||
<option value={protocolTupple[0]}>
|
||||
{protocolTupple[1]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Default Port:</label>
|
||||
<input
|
||||
type="number"
|
||||
{...register('default_port', {required: true})}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<input type="checkbox" {...register('requires_tls')} />{' '}
|
||||
Requires TLS
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>
|
||||
<input type="checkbox" {...register('is_active')} />{' '}
|
||||
Active
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="primary" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</>
|
||||
)}
|
||||
</ModalContent>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { FC } from 'react';
|
||||
import type { TemplateDTO } from '../../duck';
|
||||
import { TemplateView } from './template-view';
|
||||
|
||||
export interface TemplateListProps {
|
||||
templates: TemplateDTO[];
|
||||
}
|
||||
|
||||
export const TemplateList: FC<TemplateListProps> = ({ templates }) => {
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Protocol</th>
|
||||
<th>Port</th>
|
||||
<th>TLS</th>
|
||||
<th>Active</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{templates.map((template) => (
|
||||
<TemplateView template={template} key={template.id}/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { FC } from 'react';
|
||||
import { deleteTemplateAction, type TemplateDTO } from '../../duck';
|
||||
import { useDisclosure } from '@heroui/react';
|
||||
import { TemplateEdit } from './template-edit';
|
||||
import { useAppDispatch } from '../../../../common/hooks';
|
||||
|
||||
export interface TemplateViewProps {
|
||||
template: TemplateDTO;
|
||||
}
|
||||
|
||||
export const TemplateView: FC<TemplateViewProps> = ({ template }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isOpen, onOpen, onOpenChange } = useDisclosure();
|
||||
|
||||
const handleDeleteTemplate = () => {
|
||||
if (confirm('Delete template?')) {
|
||||
dispatch(deleteTemplateAction(template.id));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr>
|
||||
<td>{template.name}</td>
|
||||
<td>{template.protocol}</td>
|
||||
<td>{template.default_port}</td>
|
||||
<td>{template.requires_tls ? 'Yes' : 'No'}</td>
|
||||
<td>{template.is_active ? 'Yes' : 'No'}</td>
|
||||
<td>
|
||||
<button className="btn btn-primary" onClick={onOpen}>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-danger"
|
||||
onClick={handleDeleteTemplate}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<TemplateEdit
|
||||
templateId={template.id}
|
||||
onOpenChange={onOpenChange}
|
||||
isOpen={isOpen}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user