diff --git a/app/dashboard/public/locales/en.json b/app/dashboard/public/locales/en.json
@@ -76,12 +76,13 @@
"total": "Total"
},
"hostsTable": {
+ "inboundIsNotSelectedToCreate": "An inbound must be selected first",
"status": "status",
"editHost": "Edit host",
"createHosts": "Create host",
"address": "Address",
"noHostMatched": "It seems there is no host matched with what you are looking for",
- "noHost": "There is no host in the system",
+ "noHost": "Select an inbound, there is no host in the system",
"port": "Port",
"total": "Total"
},
@@ -188,6 +189,7 @@
"createSubmit": "Submit",
"editSubmit": "Submit",
"createHost": "Create host",
+ "editHost": "Edit host",
"savedSuccess": "Hosts saved successfully",
"loading": "loading...",
"apply": "Apply",
diff --git a/app/dashboard/src/components/table/empty-section.tsx b/app/dashboard/src/components/table/empty-section.tsx
@@ -5,11 +5,11 @@ import { ReactComponent as AddFileIcon } from 'assets/add_file.svg';
import { t } from 'i18next';
type EmptySectionProps = {
- isFiltered: boolean;
- noObjectMatchedT: string;
- noObjectT: string;
- createObjectT: string;
- onCreateObject: (isOpen: boolean) => void;
+ isFiltered: boolean;
+ noObjectMatchedT: string;
+ noObjectT: string;
+ createObjectT: string;
+ onCreateObject?: (isOpen: boolean) => void;
};
const EmptySectionIcon = chakra(AddFileIcon);
@@ -24,7 +24,9 @@ const EmptySectionIcon = chakra(AddFileIcon);
* @param onCreateObject - Create object event handler on click
*
*/
-export const EmptySection: FC<EmptySectionProps> = ({ isFiltered, noObjectT, noObjectMatchedT, createObjectT, onCreateObject }) => {
+export const EmptySection: FC<EmptySectionProps> = ({
+ isFiltered, noObjectT, noObjectMatchedT, createObjectT, onCreateObject
+}) => {
return (
<Box
padding="5"
@@ -61,7 +63,7 @@ export const EmptySection: FC<EmptySectionProps> = ({ isFiltered, noObjectT, noO
<Text fontWeight="medium" color="gray.600" _dark={{ color: 'gray.400' }}>
{isFiltered ? t(noObjectMatchedT) : t(noObjectT)}
</Text>
- {!isFiltered && (
+ {(!isFiltered && onCreateObject !== undefined) && (
<Button
size="sm"
colorScheme="primary"
diff --git a/app/dashboard/src/pages/home/statistics.tsx b/app/dashboard/src/pages/home/statistics.tsx
@@ -50,9 +50,9 @@ export const Statistics: FC<BoxProps> = (props) => {
});
useEffect(() => {
- if (systemData?.version !== currentVersion)
+ if (systemData?.version !== currentVersion && systemData !== undefined)
useDashboard.setState({ version: systemData.version })
- } )
+ }, [systemData]);
const { t } = useTranslation();
return (
diff --git a/app/dashboard/src/pages/hosts/filters.tsx b/app/dashboard/src/pages/hosts/filters.tsx
@@ -11,6 +11,7 @@ import {
InputLeftElement,
InputRightElement,
Spinner,
+ useToast,
} from '@chakra-ui/react';
import {
ArrowPathIcon,
@@ -45,7 +46,28 @@ const setSearchField = debounce((tag: string) => {
export const InboundsHostsFilters: FC<FilterProps> = ({ ...props }) => {
const { loading } = useDashboard();
- const { inboundsFilters: filters, onInboundsFilterChange, refetchHosts, onCreatingHost } = useInbounds();
+ const {
+ inboundsFilters: filters,
+ onInboundsFilterChange,
+ refetchHosts,
+ onCreatingHost,
+ selectedInbound,
+ } = useInbounds();
+ const toast = useToast();
+ const onCreateClick = () => {
+ if (selectedInbound) {
+ onCreatingHost(true);
+ } else {
+ toast({
+ title: t('hostsTable.inboundIsNotSelectedToCreate'),
+ status: 'error',
+ isClosable: true,
+ position: 'top',
+ duration: 3000,
+ });
+ }
+ }
+
const { t } = useTranslation();
const [search, setSearch] = useState('');
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -125,7 +147,7 @@ export const InboundsHostsFilters: FC<FilterProps> = ({ ...props }) => {
<Button
colorScheme="primary"
size="sm"
- onClick={() => onCreatingHost(true)}
+ onClick={() => onCreateClick()}
px={5}
>
{t('hostsTable.createHosts')}
diff --git a/app/dashboard/src/pages/hosts/table/index.tsx b/app/dashboard/src/pages/hosts/table/index.tsx
@@ -114,8 +114,7 @@ export const HostsTable: FC<NodesTableProps> = ({ hosts }) => {
isFiltered={/* isFiltered */ false}
noObjectT="hostsTable.noHost"
noObjectMatchedT='hostsTable.noHostMatched'
- createObjectT="addNode"
- onCreateObject={onCreatingHost}
+ createObjectT="hostsTable.createHosts"
/>
</Td>
</Tr>
diff --git a/app/dashboard/src/stores/inbounds.store.ts b/app/dashboard/src/stores/inbounds.store.ts
@@ -45,14 +45,16 @@ export const fetchInbounds = async () => {
};
export const fetchInboundHosts = async (id: number | undefined): Promise<Hosts> => {
- useDashboard.setState({ loading: true });
- return fetch(`/inbounds/${id}/hosts`)
- .then((hosts: Hosts) => {
- return hosts
- })
- .finally(() => {
- useDashboard.setState({ loading: false });
- });
+ if (id !== undefined) {
+ useDashboard.setState({ loading: true });
+ return fetch(`/inbounds/${id}/hosts`)
+ .then((hosts: Hosts) => {
+ return hosts
+ })
+ .finally(() => {
+ useDashboard.setState({ loading: false });
+ });
+ } else { return [] }
};
type InboundsStateType = {