diff --git a/app/dashboard/index.html b/app/dashboard/index.html
index 4fc5208..c21c605 100644
--- a/app/dashboard/index.html
+++ b/app/dashboard/index.html
@@ -1,41 +1,26 @@
-
-
-
-
- Marzban
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ Marzneshin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/dashboard/public/locales/en.json b/app/dashboard/public/locales/en.json
index 75ce0b0..db20623 100644
--- a/app/dashboard/public/locales/en.json
+++ b/app/dashboard/public/locales/en.json
@@ -86,6 +86,10 @@
"port": "Port",
"total": "Total"
},
+ "noInboundsCallout": {
+ "header": "Configure Nodes!",
+ "body": "Please configure nodes to access inbounds hosts"
+ },
"userDialog": {
"dataLimit": "Data Limit",
"periodicUsageReset": "Periodic Usage Reset",
@@ -204,12 +208,16 @@
"host.wildcard": "Use * to generate a random string (works for wildcard domain names)"
},
"revoke": "Revoke",
- "deleteNode.title": "Delete Node",
- "deleteNode.prompt": "Are you sure you want to delete the {{name}} node?",
- "deleteNode.deleteSuccess": "Node {{name}} removed successfully",
- "deleteService.title": "Delete Service",
- "deleteService.prompt": "Are you sure you want to delete the {{name}} node?",
- "deleteService.deleteSuccess": "Service {{name}} removed successfully",
+ "deleteNode": {
+ "title": "Delete Node",
+ "prompt": "Are you sure you want to delete the {{name}} node?",
+ "deleteSuccess": "Node {{name}} removed successfully"
+ },
+ "deleteService": {
+ "title": "Delete Service",
+ "prompt": "Are you sure you want to delete the {{name}} node?",
+ "deleteSuccess": "Service {{name}} removed successfully"
+ },
"users": "Users",
"active": "active",
"disabled": "disabled",
diff --git a/app/dashboard/src/components/callout/index.tsx b/app/dashboard/src/components/callout/index.tsx
new file mode 100644
index 0000000..5cdae9e
--- /dev/null
+++ b/app/dashboard/src/components/callout/index.tsx
@@ -0,0 +1,20 @@
+
+
+import { Box, ChakraProps, Text } from '@chakra-ui/react'
+import { FC } from 'react'
+
+type CalloutProps = {
+ header: string,
+ body: string,
+};
+
+export const Callout: FC = ({ header, body, ...props }) => {
+ return (
+
+
+ {header}
+
+ {body}
+
+ )
+}
diff --git a/app/dashboard/src/pages/hosts/container.tsx b/app/dashboard/src/pages/hosts/container.tsx
index cf67977..aafaf0f 100644
--- a/app/dashboard/src/pages/hosts/container.tsx
+++ b/app/dashboard/src/pages/hosts/container.tsx
@@ -5,6 +5,8 @@ import { queryIds } from 'constants/query-ids';
import { useQuery } from '@tanstack/react-query';
import { fetchInbounds, fetchInboundHosts, useInbounds } from 'stores';
import { Grid, GridItem, } from '@chakra-ui/react';
+import { useTranslation } from 'react-i18next';
+import { Callout } from 'components/callout';
export const InboundsHostsManager = () => {
const { selectedInbound } = useInbounds();
@@ -25,21 +27,26 @@ export const InboundsHostsManager = () => {
}
});
- return (
- <>
-
-
-
-
-
-
-
-
-
- >
- )
+ const { t } = useTranslation('noInboundsCallout');
+
+ return inbounds.length === 0 ?
+
+ : (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+
+ )
}
diff --git a/app/dashboard/src/pages/hosts/dialog/default-values.ts b/app/dashboard/src/pages/hosts/dialog/default-values.ts
index e9df7b1..f6627cc 100644
--- a/app/dashboard/src/pages/hosts/dialog/default-values.ts
+++ b/app/dashboard/src/pages/hosts/dialog/default-values.ts
@@ -3,7 +3,7 @@ export const getDefaultValues = (): HostSchema => {
return {
host: '',
sni: '',
- port: 1,
+ port: null,
path: '',
address: '',
remark: '',
diff --git a/app/dashboard/src/pages/hosts/dialog/index.tsx b/app/dashboard/src/pages/hosts/dialog/index.tsx
index fefaffe..4ff37ab 100644
--- a/app/dashboard/src/pages/hosts/dialog/index.tsx
+++ b/app/dashboard/src/pages/hosts/dialog/index.tsx
@@ -104,7 +104,7 @@ export const HostsDialog: FC = () => {
.then(() => {
toast({
title: t(
- isEditingHost ? 'hostsDialog.editHost' : 'hostsDialog.createNewHost',
+ isEditingHost ? 'hostsDialog.editHost' : 'hostsDialog.createHost',
{ hoshtName: values.host }
),
status: 'success',
diff --git a/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx b/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx
index 41cb365..1f9736d 100644
--- a/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx
+++ b/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx
@@ -4,6 +4,7 @@ import { InboundCard } from 'components/inbounds-card';
import { handleSort } from 'components/table';
import { FC } from 'react';
import { useTranslation } from 'react-i18next';
+import { useEffect } from 'react';
import { useInbounds } from 'stores';
import { InboundType } from 'types';
@@ -22,6 +23,9 @@ export const InboundsSidebar: FC = ({
refetchHosts,
} = useInbounds();
+ useEffect(() => {
+ selectedInbound === undefined && selectInbound(inbounds[0]);
+ }, [selectedInbound, inbounds]);
const { t } = useTranslation();
diff --git a/app/dashboard/src/pages/nodes/dialog.tsx b/app/dashboard/src/pages/nodes/dialog.tsx
index c435760..738da0a 100644
--- a/app/dashboard/src/pages/nodes/dialog.tsx
+++ b/app/dashboard/src/pages/nodes/dialog.tsx
@@ -210,7 +210,6 @@ export const NodesDialog: FC = () => {
aria-label="delete node"
onClick={() => {
if (editingNode !== null) {
- console.log('deleting')
onDeletingNode(editingNode);
onClose();
}
diff --git a/app/dashboard/src/stores/inbounds.store.ts b/app/dashboard/src/stores/inbounds.store.ts
index ef112f7..7b6974b 100644
--- a/app/dashboard/src/stores/inbounds.store.ts
+++ b/app/dashboard/src/stores/inbounds.store.ts
@@ -14,7 +14,8 @@ export const hostSchema = z.object({
address: z.string().min(1, 'Address is required'),
port: z.coerce.number()
.gte(1, 'Port must be more than 1')
- .lte(65535, 'Port can not be more than 65535'),
+ .lte(65535, 'Port can not be more than 65535')
+ .or(z.string().nullable()),
path: z.string(),
sni: z.string(),
host: z.string(),
@@ -136,6 +137,7 @@ export const useInbounds = create(
.catch(() => false)
.finally(() => {
useDashboard.setState({ loading: false });
+ get().refetchHosts();
});
}
},
@@ -150,6 +152,7 @@ export const useInbounds = create(
.catch(() => false)
.finally(() => {
useDashboard.setState({ loading: false });
+ get().refetchHosts();
});
}
},
@@ -159,7 +162,10 @@ export const useInbounds = create(
deleteHost: async (hostId: number): Promise => {
useDashboard.setState({ loading: true });
return fetch(`/inbounds/hosts/${hostId}`, { method: 'DELETE' })
- .then(() => true)
+ .then(() => {
+ get().refetchHosts();
+ return true;
+ })
.catch(() => false)
.finally(() => {
useDashboard.setState({ loading: false });
diff --git a/makefile b/makefile
index 053e7a4..7e31509 100644
--- a/makefile
+++ b/makefile
@@ -14,16 +14,15 @@ dashboard-dev:
VITE_BASE_API=http://0.0.0.0:8000/api/ npm run dev \
--prefix './app/dashboard/' \
-- --host 0.0.0.0 \
- --base ./app/dashboard/ \
+ --base /dashboard/ \
--clearScreen false
dashboard-preview:
VITE_BASE_API=http://0.0.0.0:8000/api/ npm run preview \
--prefix './app/dashboard/' \
-- --host 0.0.0.0 \
- --base ./app/dashboard/ \
+ --base /dashboard/ \
--clearScreen false
-
dashboard-cleanup:
rm -rf app/dashboard/node_modules/