gitscope
https://dev.kronoz.win/r/marzneshin.git
app/dashboard/src/pages/nodes/dialog.tsx · v0.2.1
Source
1 a47eb4c Dawsh 2y ago import {
2 a47eb4c Dawsh 2y ago Box,
3 a47eb4c Dawsh 2y ago Button,
4 a47eb4c Dawsh 2y ago chakra,
5 a47eb4c Dawsh 2y ago Checkbox,
6 a47eb4c Dawsh 2y ago FormControl,
7 a47eb4c Dawsh 2y ago FormLabel,
8 a47eb4c Dawsh 2y ago HStack,
9 a47eb4c Dawsh 2y ago Modal,
10 a47eb4c Dawsh 2y ago ModalBody,
11 a47eb4c Dawsh 2y ago ModalCloseButton,
12 a47eb4c Dawsh 2y ago ModalContent,
13 a47eb4c Dawsh 2y ago ModalOverlay,
14 a47eb4c Dawsh 2y ago Switch,
15 a47eb4c Dawsh 2y ago Tooltip,
16 a47eb4c Dawsh 2y ago useToast,
17 5bb2712 Mardin 2y ago VStack, IconButton, Spacer
18 bf7c131 Mardin 2y ago } from '@chakra-ui/react';
19 bf7c131 Mardin 2y ago import { zodResolver } from '@hookform/resolvers/zod';
20 a47eb4c Dawsh 2y ago import {
21 5bb2712 Mardin 2y ago getNodeCreateDefaultValues,
22 5bb2712 Mardin 2y ago NodeCreate,
23 5bb2712 Mardin 2y ago NodeCreateSchema,
24 a47eb4c Dawsh 2y ago useNodes,
25 89f8f93 Mardin 2y ago } from 'stores';
26 5bb2712 Mardin 2y ago import { FC, useEffect, useState } from 'react';
27 5bb2712 Mardin 2y ago import { Controller, useForm } from 'react-hook-form';
28 bf7c131 Mardin 2y ago import { useTranslation } from 'react-i18next';
29 bf7c131 Mardin 2y ago import 'slick-carousel/slick/slick-theme.css';
30 bf7c131 Mardin 2y ago import 'slick-carousel/slick/slick.css';
31 5825ea4 Mardin 2y ago import { DialogModalHeader, DeleteIcon, AddIcon, EditIcon } from 'components/dialog';
32 5825ea4 Mardin 2y ago import { Input } from 'components/input';
33 a47eb4c Dawsh 2y ago
34 a47eb4c Dawsh 2y ago const CustomInput = chakra(Input, {
35 a47eb4c Dawsh 2y ago baseStyle: {
36 bf7c131 Mardin 2y ago bg: 'white',
37 a47eb4c Dawsh 2y ago _dark: {
38 bf7c131 Mardin 2y ago bg: 'gray.700',
39 a47eb4c Dawsh 2y ago },
40 a47eb4c Dawsh 2y ago },
41 a47eb4c Dawsh 2y ago });
42 a47eb4c Dawsh 2y ago
43 5bb2712 Mardin 2y ago export const NodesDialog: FC = () => {
44 5bb2712 Mardin 2y ago const { editingNode, isEditingNode, onEditingNode, isAddingNode, refetchNodes, updateNode, addNode, onAddingNode, onDeletingNode } = useNodes();
45 5bb2712 Mardin 2y ago const [loading, setLoading] = useState(false);
46 5bb2712 Mardin 2y ago const [, setError] = useState<string | null>('');
47 a47eb4c Dawsh 2y ago
48 a47eb4c Dawsh 2y ago const { t } = useTranslation();
49 a47eb4c Dawsh 2y ago const toast = useToast();
50 5bb2712 Mardin 2y ago const defaultValueNode: NodeCreate = (isEditingNode === true && editingNode !== null && editingNode !== undefined) ? editingNode : getNodeCreateDefaultValues();
51 5bb2712 Mardin 2y ago const form = useForm<NodeCreate>({
52 5bb2712 Mardin 2y ago resolver: zodResolver(NodeCreateSchema),
53 5bb2712 Mardin 2y ago defaultValues: defaultValueNode,
54 a47eb4c Dawsh 2y ago });
55 5bb2712 Mardin 2y ago const isOpen = isEditingNode || isAddingNode;
56 a47eb4c Dawsh 2y ago const onClose = () => {
57 5bb2712 Mardin 2y ago onAddingNode(false);
58 5bb2712 Mardin 2y ago onEditingNode(undefined);
59 a47eb4c Dawsh 2y ago };
60 5bb2712 Mardin 2y ago useEffect(() => {
61 5bb2712 Mardin 2y ago if (isOpen) {
62 5bb2712 Mardin 2y ago refetchNodes();
63 5bb2712 Mardin 2y ago form.reset(defaultValueNode);
64 5bb2712 Mardin 2y ago }
65 5bb2712 Mardin 2y ago }, [isOpen]);
66 5bb2712 Mardin 2y ago
67 5bb2712 Mardin 2y ago const submit = async (values: NodeCreate) => {
68 5bb2712 Mardin 2y ago setLoading(true);
69 5bb2712 Mardin 2y ago const methods = { edited: updateNode, created: addNode };
70 5bb2712 Mardin 2y ago const method = isEditingNode ? 'edited' : 'created';
71 5bb2712 Mardin 2y ago const { name, port, id, address, usage_coefficient } = values;
72 5bb2712 Mardin 2y ago setError(null);
73 5bb2712 Mardin 2y ago let body: NodeCreate = {
74 5bb2712 Mardin 2y ago id,
75 5bb2712 Mardin 2y ago name,
76 5bb2712 Mardin 2y ago address,
77 5bb2712 Mardin 2y ago port,
78 5bb2712 Mardin 2y ago status: values.status,
79 5bb2712 Mardin 2y ago usage_coefficient,
80 5bb2712 Mardin 2y ago add_as_new_host: values.add_as_new_host,
81 5bb2712 Mardin 2y ago };
82 5bb2712 Mardin 2y ago
83 5bb2712 Mardin 2y ago await methods[method](body)
84 5bb2712 Mardin 2y ago .then(() => {
85 5bb2712 Mardin 2y ago toast({
86 5bb2712 Mardin 2y ago title: t(
87 5bb2712 Mardin 2y ago isEditingNode ? 'nodeDialog.editNode' : 'nodeDialog.createNewNode',
88 5bb2712 Mardin 2y ago { name: values.name }
89 5bb2712 Mardin 2y ago ),
90 5bb2712 Mardin 2y ago status: 'success',
91 5bb2712 Mardin 2y ago isClosable: true,
92 5bb2712 Mardin 2y ago position: 'top',
93 5bb2712 Mardin 2y ago duration: 3000,
94 5bb2712 Mardin 2y ago });
95 5bb2712 Mardin 2y ago refetchNodes();
96 5bb2712 Mardin 2y ago onClose();
97 5bb2712 Mardin 2y ago })
98 5bb2712 Mardin 2y ago .catch((err) => {
99 5bb2712 Mardin 2y ago if (err?.response?.status === 409 || err?.response?.status === 400)
100 5bb2712 Mardin 2y ago setError(err?.response?._data?.detail);
101 5bb2712 Mardin 2y ago if (err?.response?.status === 422) {
102 5bb2712 Mardin 2y ago Object.keys(err.response._data.detail).forEach((key) => {
103 5bb2712 Mardin 2y ago setError(err?.response._data.detail[key] as string);
104 5bb2712 Mardin 2y ago form.setError(
105 5bb2712 Mardin 2y ago key as 'address' | 'port' | 'name' | 'status',
106 5bb2712 Mardin 2y ago {
107 5bb2712 Mardin 2y ago type: 'custom',
108 5bb2712 Mardin 2y ago message: err.response._data.detail[key],
109 5bb2712 Mardin 2y ago }
110 5bb2712 Mardin 2y ago );
111 5bb2712 Mardin 2y ago });
112 5bb2712 Mardin 2y ago }
113 5bb2712 Mardin 2y ago })
114 5bb2712 Mardin 2y ago .finally(() => {
115 5bb2712 Mardin 2y ago setLoading(false);
116 5bb2712 Mardin 2y ago });
117 a47eb4c Dawsh 2y ago };
118 a47eb4c Dawsh 2y ago
119 a47eb4c Dawsh 2y ago return (
120 a47eb4c Dawsh 2y ago <>
121 5bb2712 Mardin 2y ago <Modal isOpen={isOpen} onClose={onClose}>
122 a47eb4c Dawsh 2y ago <ModalOverlay bg="blackAlpha.300" backdropFilter="blur(10px)" />
123 a47eb4c Dawsh 2y ago <ModalContent mx="3" w="fit-content" maxW="3xl">
124 5bb2712 Mardin 2y ago <DialogModalHeader HeaderIcon={isEditingNode ? EditIcon : AddIcon} title={isEditingNode ? t('nodeDialog.editNode') : t('nodeDialog.addNode')} />
125 a47eb4c Dawsh 2y ago <ModalCloseButton mt={3} />
126 a47eb4c Dawsh 2y ago <ModalBody w="440px" pb={6} pt={3}>
127 5bb2712 Mardin 2y ago <VStack>
128 5bb2712 Mardin 2y ago {loading && 'loading...'}
129 5bb2712 Mardin 2y ago
130 5bb2712 Mardin 2y ago <form onSubmit={form.handleSubmit((v) => submit(v))}>
131 5bb2712 Mardin 2y ago <VStack>
132 5bb2712 Mardin 2y ago <HStack w="full">
133 5bb2712 Mardin 2y ago <FormControl>
134 5bb2712 Mardin 2y ago <CustomInput
135 89f8f93 Mardin 2y ago label={t('nodeDialog.nodeName')}
136 5bb2712 Mardin 2y ago size="sm"
137 5bb2712 Mardin 2y ago placeholder="Marzn-Node-2"
138 5bb2712 Mardin 2y ago {...form.register('name')}
139 5bb2712 Mardin 2y ago error={form.formState?.errors?.name?.message}
140 a47eb4c Dawsh 2y ago />
141 5bb2712 Mardin 2y ago </FormControl>
142 5bb2712 Mardin 2y ago <HStack px={1}>
143 5bb2712 Mardin 2y ago <Controller
144 5bb2712 Mardin 2y ago name="status"
145 5bb2712 Mardin 2y ago control={form.control}
146 5bb2712 Mardin 2y ago render={({ field }) => {
147 5bb2712 Mardin 2y ago return (
148 5bb2712 Mardin 2y ago <Tooltip
149 5bb2712 Mardin 2y ago key={field.value}
150 5bb2712 Mardin 2y ago placement="top"
151 5bb2712 Mardin 2y ago label={
152 5bb2712 Mardin 2y ago `${t('usersTable.status')}: ` +
153 5bb2712 Mardin 2y ago (field.value !== 'disabled' ? t('active') : t('disabled'))
154 5bb2712 Mardin 2y ago }
155 5bb2712 Mardin 2y ago textTransform="capitalize"
156 5bb2712 Mardin 2y ago >
157 5bb2712 Mardin 2y ago <Box mt="6">
158 5bb2712 Mardin 2y ago <Switch
159 5bb2712 Mardin 2y ago colorScheme="primary"
160 5bb2712 Mardin 2y ago isChecked={field.value !== 'disabled'}
161 5bb2712 Mardin 2y ago onChange={(e) => {
162 5bb2712 Mardin 2y ago if (e.target.checked) {
163 5bb2712 Mardin 2y ago field.onChange('none');
164 5bb2712 Mardin 2y ago } else {
165 5bb2712 Mardin 2y ago field.onChange('disabled');
166 5bb2712 Mardin 2y ago }
167 5bb2712 Mardin 2y ago }}
168 5bb2712 Mardin 2y ago />
169 5bb2712 Mardin 2y ago </Box>
170 5bb2712 Mardin 2y ago </Tooltip>
171 5bb2712 Mardin 2y ago );
172 5bb2712 Mardin 2y ago }}
173 5bb2712 Mardin 2y ago />
174 5bb2712 Mardin 2y ago </HStack>
175 5bb2712 Mardin 2y ago </HStack>
176 5bb2712 Mardin 2y ago <HStack alignItems="flex-start">
177 5bb2712 Mardin 2y ago <Box w="65%">
178 5bb2712 Mardin 2y ago <CustomInput
179 89f8f93 Mardin 2y ago label={t('nodeDialog.nodeAddress')}
180 5bb2712 Mardin 2y ago size="sm"
181 5bb2712 Mardin 2y ago placeholder="51.20.12.13"
182 5bb2712 Mardin 2y ago {...form.register('address')}
183 5bb2712 Mardin 2y ago error={form.formState?.errors?.address?.message}
184 5bb2712 Mardin 2y ago />
185 5bb2712 Mardin 2y ago </Box>
186 5bb2712 Mardin 2y ago <Box w="35%">
187 5bb2712 Mardin 2y ago <CustomInput
188 89f8f93 Mardin 2y ago label={t('nodeDialog.nodePort')}
189 5bb2712 Mardin 2y ago size="sm"
190 5bb2712 Mardin 2y ago placeholder="62050"
191 5bb2712 Mardin 2y ago {...form.register('port')}
192 5bb2712 Mardin 2y ago error={form.formState?.errors?.port?.message}
193 5bb2712 Mardin 2y ago />
194 5bb2712 Mardin 2y ago </Box>
195 5bb2712 Mardin 2y ago </HStack>
196 5bb2712 Mardin 2y ago {!editingNode && (
197 5bb2712 Mardin 2y ago <FormControl py={1}>
198 5bb2712 Mardin 2y ago <Checkbox {...form.register('add_as_new_host')}>
199 89f8f93 Mardin 2y ago <FormLabel m={0}>{t('nodeDialog.addHostForEveryInbound')}</FormLabel>
200 5bb2712 Mardin 2y ago </Checkbox>
201 5bb2712 Mardin 2y ago </FormControl>
202 5bb2712 Mardin 2y ago )}
203 5bb2712 Mardin 2y ago <Spacer m={2}></Spacer>
204 5bb2712 Mardin 2y ago <HStack w="full">
205 5bb2712 Mardin 2y ago <Tooltip label={t('delete')} placement="top">
206 5bb2712 Mardin 2y ago <IconButton
207 5bb2712 Mardin 2y ago colorScheme="red"
208 5bb2712 Mardin 2y ago variant="ghost"
209 5bb2712 Mardin 2y ago size="sm"
210 5bb2712 Mardin 2y ago aria-label="delete node"
211 5bb2712 Mardin 2y ago onClick={() => {
212 5bb2712 Mardin 2y ago if (editingNode !== null) {
213 5bb2712 Mardin 2y ago onDeletingNode(editingNode);
214 5bb2712 Mardin 2y ago onClose();
215 5bb2712 Mardin 2y ago }
216 5bb2712 Mardin 2y ago }}
217 5bb2712 Mardin 2y ago >
218 5bb2712 Mardin 2y ago <DeleteIcon />
219 5bb2712 Mardin 2y ago </IconButton>
220 5bb2712 Mardin 2y ago </Tooltip>
221 5bb2712 Mardin 2y ago <Button
222 5bb2712 Mardin 2y ago flexGrow={1}
223 5bb2712 Mardin 2y ago type="submit"
224 5bb2712 Mardin 2y ago colorScheme="primary"
225 5bb2712 Mardin 2y ago size="sm"
226 5bb2712 Mardin 2y ago px={5}
227 5bb2712 Mardin 2y ago w="full"
228 5bb2712 Mardin 2y ago isLoading={loading}
229 5bb2712 Mardin 2y ago >
230 5bb2712 Mardin 2y ago {isEditingNode ? t('nodeDialog.updateSubmit') : t('nodeDialog.addSubmit')}
231 5bb2712 Mardin 2y ago </Button>
232 5bb2712 Mardin 2y ago </HStack>
233 5bb2712 Mardin 2y ago </VStack>
234 5bb2712 Mardin 2y ago </form>
235 5bb2712 Mardin 2y ago </VStack>
236 a47eb4c Dawsh 2y ago </ModalBody>
237 a47eb4c Dawsh 2y ago </ModalContent>
238 a47eb4c Dawsh 2y ago </Modal>
239 a47eb4c Dawsh 2y ago </>
240 a47eb4c Dawsh 2y ago );
241 5bb2712 Mardin 2y ago }