diff --git a/app/dashboard/package-lock.json b/app/dashboard/package-lock.json index 7d4dc5e..fb4cc88 100644 --- a/app/dashboard/package-lock.json +++ b/app/dashboard/package-lock.json @@ -1,12 +1,12 @@ { "name": "marzneshin-dashboard", - "version": "0.1.1", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "marzneshin-dashboard", - "version": "0.1.1", + "version": "0.1.3", "hasInstallScript": true, "dependencies": { "@chakra-ui/icons": "^2.1.1", @@ -16,6 +16,7 @@ "@heroicons/react": "^2.0.12", "@hookform/devtools": "^4.3.1", "@hookform/resolvers": "^2.9.10", + "@tanstack/react-query-devtools": "^5.24.8", "apexcharts": "^3.40.0", "classnames": "^2.3.2", "dayjs": "^1.11.6", @@ -2510,6 +2511,57 @@ "@svgr/core": "^6.0.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.24.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.24.8.tgz", + "integrity": "sha512-yH7KnfXMf10p1U5GffTQzFi2Miiw6WJZImGYGdV7eqa5ZbKO8qVx9lOA9SfhIaJXomrMp1Yz5w/CBhVM3yWeTA==", + "peer": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.24.0.tgz", + "integrity": "sha512-pThim455t69zrZaQKa7IRkEIK8UBTS+gHVAdNfhO72Xh4rWpMc63ovRje5/n6iw63+d6QiJzVadsJVdPoodSeQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.24.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.24.8.tgz", + "integrity": "sha512-jB3JS9SzDmBySk9VVOTPt/0ixWEb3K3dy9IExlVl/1NouY3N7HzAqG/1d4m6E9eFfKJoLvA/hBksaLu0lw627A==", + "peer": true, + "dependencies": { + "@tanstack/query-core": "5.24.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.24.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.24.8.tgz", + "integrity": "sha512-OfNbyOF07/3PXH1fdLs/2BxjpXv2hFI777iym2L0lVGQbyVSJAUbGXYaCvgjZIdan/vfiXf3sjCVkO8mD9hf0Q==", + "dependencies": { + "@tanstack/query-devtools": "5.24.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.24.8", + "react": "^18.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -3013,7 +3065,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, + "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3326,7 +3378,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } @@ -3344,7 +3396,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -3565,7 +3617,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "devOptional": true, + "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4348,6 +4400,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "linux" @@ -4962,7 +5015,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5267,7 +5320,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -5665,7 +5718,7 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", - "devOptional": true + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -5802,7 +5855,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5956,7 +6009,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.12.0" } @@ -7098,7 +7151,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -8112,7 +8165,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -8382,7 +8435,7 @@ "version": "1.71.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", - "devOptional": true, + "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -9042,7 +9095,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "dev": true, "dependencies": { "is-number": "^7.0.0" }, diff --git a/app/dashboard/package.json b/app/dashboard/package.json index 22d423b..6a28ad1 100644 --- a/app/dashboard/package.json +++ b/app/dashboard/package.json @@ -1,7 +1,7 @@ { "name": "marzneshin-dashboard", "private": true, - "version": "0.1.1", + "version": "0.1.3", "scripts": { "dev": "vite --port 3000", "build": "tsc && vite build", @@ -19,6 +19,7 @@ "@heroicons/react": "^2.0.12", "@hookform/devtools": "^4.3.1", "@hookform/resolvers": "^2.9.10", + "@tanstack/react-query-devtools": "^5.24.8", "apexcharts": "^3.40.0", "classnames": "^2.3.2", "dayjs": "^1.11.6", diff --git a/app/dashboard/src/index.tsx b/app/dashboard/src/index.tsx index 4a8667e..2dd49f0 100644 --- a/app/dashboard/src/index.tsx +++ b/app/dashboard/src/index.tsx @@ -8,12 +8,13 @@ import utc from 'dayjs/plugin/utc'; import 'locales/i18n'; import React from 'react'; import ReactDOM from 'react-dom/client'; -import { QueryClientProvider } from 'react-query'; +import { QueryClientProvider } from '@tanstack/react-query'; import { queryClient } from 'service/react-query'; import { updateThemeColor } from 'utils/themeColor'; import { theme } from '../chakra.config'; import App from './App'; import 'index.scss'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; dayjs.extend(Timezone); dayjs.extend(LocalizedFormat); @@ -28,6 +29,7 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + diff --git a/app/dashboard/src/pages/home/statistics.tsx b/app/dashboard/src/pages/home/statistics.tsx index 8e3c166..8762a0f 100644 --- a/app/dashboard/src/pages/home/statistics.tsx +++ b/app/dashboard/src/pages/home/statistics.tsx @@ -7,9 +7,10 @@ import { import { useDashboard } from 'stores'; import { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { fetch } from 'service/http'; import { formatBytes, numberWithCommas } from 'utils/formatByte'; +import { useEffect } from 'react'; import { StatisticsCardInLine, StatisticsQueryKey } from 'components/statistics-card'; const TotalUsersIcon = chakra(UsersIcon, { @@ -41,16 +42,18 @@ const MemoryIcon = chakra(ChartPieIcon, { export const Statistics: FC = (props) => { - const { version } = useDashboard(); + const { version: currentVersion } = useDashboard(); const { data: systemData } = useQuery({ - queryKey: StatisticsQueryKey, + queryKey: [StatisticsQueryKey], queryFn: () => fetch('/system'), refetchInterval: 5000, - onSuccess: ({ version: currentVersion }) => { - if (version !== currentVersion) - useDashboard.setState({ version: currentVersion }); - }, }); + + useEffect(() => { + if (systemData?.version !== currentVersion) + useDashboard.setState({ version: systemData.version }) + } ) + const { t } = useTranslation(); return ( { + const { selectedInbound, refetchHosts } = useInbounds(); + + const { data: inbounds } = useQuery({ + queryKey: [queryIds.inbounds], + initialData: [], + queryFn: () => { + return fetchInbounds(); + } + }); + + const { data: hosts } = useQuery({ + queryKey: [queryIds.hosts, selectedInbound?.id], + initialData: [], + queryFn: () => { + return fetchInboundHosts(selectedInbound?.id); + } + }); + + useEffect(() => { + refetchHosts(); + }, [selectedInbound]) + return ( <> - + - + diff --git a/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx b/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx index cd6bb3c..1086ed0 100644 --- a/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx +++ b/app/dashboard/src/pages/hosts/inbounds-sidebar/index.tsx @@ -2,21 +2,26 @@ import { Table, Thead, Tbody, Th, Td, Tr, HStack } from '@chakra-ui/react'; import classNames from 'classnames'; import { InboundCard } from 'components/inbounds-card'; import { handleSort } from 'components/table'; +import { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { useQuery } from 'react-query'; -import { fetchInbounds, useInbounds } from 'stores'; +import { useInbounds } from 'stores'; +import { InboundType } from 'types'; -export const InboundsSidebar = () => { +type InboundsSidebarProps = { + inbounds: InboundType[]; +} + +export const InboundsSidebar: FC = ({ + inbounds, +}) => { const { onInboundsFilterChange, inboundsFilters: filters, selectedInbound, selectInbound, + refetchHosts, } = useInbounds(); - const { data: inbounds } = useQuery('hosts', () => { - return fetchInbounds(); - }); const { t } = useTranslation(); @@ -45,7 +50,10 @@ export const InboundsSidebar = () => { className={classNames('interactive')} bg={active ? 'gray.300' : undefined} _dark={{ bg: active ? 'gray.700' : undefined }} - onClick={() => { selectInbound(inbound) }}> + onClick={() => { + selectInbound(inbound); + refetchHosts(); + }}> = (props) => { +export const HostsTable: FC = ({ hosts }) => { const { hostsFilters: filters, selectedInbound, + refetchHosts, + onHostsFilterChange, onEditingHost, onCreatingHost, - onHostsFilterChange, - refetchHosts, } = useInbounds(); - const { data: hosts } = useQuery('hosts', () => { - if (selectedInbound !== null) { - return fetchInboundHosts(selectedInbound.id); - } - }); - useEffect(() => { refetchHosts() }, [selectedInbound]); + useEffect(() => { + refetchHosts(); + }, [selectedInbound]); const { t } = useTranslation(); - const [selectedRow, setSelectedRow] = useState( - undefined - ); - - const useTable = useBreakpointValue({ base: false, md: true }); - - // TODO: Find a different mechancism to to detect ftiler - // const isFiltered = users.length !== total; - const toggleAccordion = (index: number) => { - setSelectedRow(index === selectedRow ? undefined : index); - }; return ( - - - - - - - - {/* Action buttons (certificate, core settings)*/} - - - - {!useTable && hosts?.map((host, i) => { - return ( - - - - - - - - - - - ); - })} - -
- - {t('remark')} - - - - - {t('hostsTable.address')} - - - - - {t('hostsTable.port')} - - -
- {host.remark} - - {host.address} - - -
- - - - - - - {t('nodesTable.ipPort')} - - - {host.port} - - - - - - { - e.stopPropagation(); - onEditingHost(true, host); - }} - > - - - - - - - - -
-
@@ -257,7 +84,7 @@ export const HostsTable: FC = (props) => { - {useTable && hosts?.map((host, i) => { + {hosts?.map((host, i) => { return ( { const status = getStatus(readyState.toString()); - const { mutate: handleRestartCore, isLoading: isRestarting } = - useMutation(restartCore); + const { + mutate: handleRestartCore, + isPending: isRestarting + } = useMutation({ mutationFn: restartCore }); const handleOnSave = ({ config }: any) => { updateConfig(config) diff --git a/app/dashboard/src/pages/nodes/table/index.tsx b/app/dashboard/src/pages/nodes/table/index.tsx index ecb5c6e..f951624 100644 --- a/app/dashboard/src/pages/nodes/table/index.tsx +++ b/app/dashboard/src/pages/nodes/table/index.tsx @@ -35,7 +35,7 @@ import { handleSort, } from 'components/table'; import { fetchNodes, useNodes } from 'stores'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { queryIds } from 'constants/query-ids'; type ExpandedIndex = number | number[]; @@ -49,7 +49,7 @@ export const NodesTable: FC = (props) => { onAddingNode, onFilterChange, } = useNodes(); - const { data: nodes } = useQuery(queryIds.nodes, () => { return fetchNodes() }) + const { data: nodes } = useQuery({ queryKey: [queryIds.nodes], queryFn: fetchNodes }); const total = nodes?.length || 0; const { t } = useTranslation(); diff --git a/app/dashboard/src/pages/services/dialog/index.tsx b/app/dashboard/src/pages/services/dialog/index.tsx index e5e37fc..4f31a3d 100644 --- a/app/dashboard/src/pages/services/dialog/index.tsx +++ b/app/dashboard/src/pages/services/dialog/index.tsx @@ -33,7 +33,7 @@ import { InboundsField } from './inbounds-field'; import { NameField } from './name-field'; import { InboundType, Service, ServiceCreate } from 'types'; import { fetchInbounds, useInbounds, useServices } from 'stores'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { queryIds } from 'constants/query-ids'; const formatService = (service: Service): FormType => { @@ -61,7 +61,7 @@ export const ServiceDialog: FC = () => { const { refetchInbounds } = useInbounds(); const { data: inbounds, - } = useQuery(queryIds.inbounds, () => fetchInbounds()); + } = useQuery({ queryKey: [queryIds.inbounds], queryFn: () => fetchInbounds() }); const isEditing = !!editingService; const isOpen = isCreatingNewService || isEditing; const [loading, setLoading] = useState(false); diff --git a/app/dashboard/src/pages/services/table.tsx b/app/dashboard/src/pages/services/table.tsx index ba31756..281e6b4 100644 --- a/app/dashboard/src/pages/services/table.tsx +++ b/app/dashboard/src/pages/services/table.tsx @@ -1,6 +1,5 @@ import { - Accordion, Box, HStack, Table, @@ -10,11 +9,10 @@ import { Th, Thead, Tr, - useBreakpointValue, } from '@chakra-ui/react'; import classNames from 'classnames'; -import { FC, useState, } from 'react'; +import { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { EmptySection, @@ -24,10 +22,9 @@ import { } from 'components/table'; import { fetchServices, useServices } from 'stores'; import { pageSizeManagers } from 'utils/userPreferenceStorage'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { queryIds } from 'constants/query-ids'; -type ExpandedIndex = number | number[]; type ServicesTableProps = {} & TableProps; export const ServicesTable: FC = (props) => { @@ -37,94 +34,14 @@ export const ServicesTable: FC = (props) => { onCreateService, onFilterChange, } = useServices(); - const { data: services } = useQuery(queryIds.services, () => { return fetchServices(filters) }); - const useTable = useBreakpointValue({ base: false, md: true }); + const { data: services } = useQuery({ + queryKey: [queryIds.services], + queryFn: () => { return fetchServices(filters) } + }); const { t } = useTranslation(); - const [selectedRow,] = useState( - undefined - ); return ( - -
- - - - - - - - - - - {!useTable && - services?.map((service, i) => { - return ( - { - e.stopPropagation(); - onEditingService(service); - }} - > - - - - - ); - })} - -
- - {t('services')} - - - - - {t('servicesTable.usersNumber')} - - - - - {t('servicesTable.inboundsNumber')} - - -
- {service.name} - - {service.users.length} - - {service.inbounds.length} -
- @@ -168,32 +85,31 @@ export const ServicesTable: FC = (props) => { - {useTable && - services?.map((service, i) => { - return ( - { - e.stopPropagation(); - onEditingService(service); - }} - > - - - - - ); - })} + {services?.map((service, i) => { + return ( + { + e.stopPropagation(); + onEditingService(service); + }} + > + + + + + ); + })} {services?.length == 0 && (
- {service.name} - - {service.users.length} - - {service.inbounds.length} -
+ {service.name} + + {service.users.length} + + {service.inbounds.length} +
diff --git a/app/dashboard/src/pages/users/dialog/index.tsx b/app/dashboard/src/pages/users/dialog/index.tsx index e9022a0..d2ac165 100644 --- a/app/dashboard/src/pages/users/dialog/index.tsx +++ b/app/dashboard/src/pages/users/dialog/index.tsx @@ -51,7 +51,7 @@ import { ExpireDateField } from './expire-date-field'; import { NoteField } from './note-field'; import { useUsers, useServices, fetchServices } from 'stores'; import { queryIds } from 'constants/query-ids'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; const formatUser = (user: User): FormType => { const services: number[] = user.services.map((service: number | Service): number => { @@ -81,7 +81,7 @@ export const UserDialog: FC = () => { } = useUsers(); const { refetchServices, servicesFilters: filters } = useServices(); const { data: services } = useQuery({ - queryKey: queryIds.services, + queryKey: [queryIds.services], initialData: [], queryFn: () => { return fetchServices(filters); diff --git a/app/dashboard/src/pages/users/table/index.tsx b/app/dashboard/src/pages/users/table/index.tsx index d19e863..123ada5 100644 --- a/app/dashboard/src/pages/users/table/index.tsx +++ b/app/dashboard/src/pages/users/table/index.tsx @@ -39,7 +39,7 @@ import { UsageSlider, UsageSliderCompact } from './usage-slider'; import { fetchUsers, useUsers } from 'stores'; import { ActionButtons } from './action-buttons'; import { pageSizeManagers } from 'utils/userPreferenceStorage'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { User } from 'types'; import { queryIds } from 'constants/query-ids'; @@ -55,7 +55,7 @@ export const UsersTable: FC = (props) => { onFilterChange, } = useUsers(); const { data } = useQuery({ - queryKey: queryIds.users, + queryKey: [queryIds.users], queryFn: () => { return fetchUsers(filters) }, initialData: { total: 0, users: [] }, }); diff --git a/app/dashboard/src/service/react-query.ts b/app/dashboard/src/service/react-query.ts index 0fd037d..6d46de5 100644 --- a/app/dashboard/src/service/react-query.ts +++ b/app/dashboard/src/service/react-query.ts @@ -1,3 +1,3 @@ -import { QueryClient } from 'react-query'; +import { QueryClient } from '@tanstack/react-query'; export const queryClient = new QueryClient(); diff --git a/app/dashboard/src/stores/inbounds.store.ts b/app/dashboard/src/stores/inbounds.store.ts index b8645d9..4f9ce72 100644 --- a/app/dashboard/src/stores/inbounds.store.ts +++ b/app/dashboard/src/stores/inbounds.store.ts @@ -44,10 +44,12 @@ export const fetchInbounds = async () => { }); }; -export const fetchInboundHosts = async (id: number): Promise => { +export const fetchInboundHosts = async (id: number | undefined): Promise => { useDashboard.setState({ loading: true }); return fetch(`/inbounds/${id}/hosts`) - .then((hosts: Hosts) => hosts) + .then((hosts: Hosts) => { + return hosts + }) .finally(() => { useDashboard.setState({ loading: false }); }); @@ -58,7 +60,7 @@ type InboundsStateType = { loading: boolean; setLoading: (value: boolean) => void; // Inbounds - selectedInbound: InboundType | null; + selectedInbound: InboundType | undefined; selectInbound: (inbound: InboundType) => void; refetchInbounds: () => void; // Hosts @@ -83,7 +85,7 @@ type InboundsStateType = { export const useInbounds = create( subscribeWithSelector((set, get) => ({ selectedHost: null, - selectedInbound: null, + selectedInbound: undefined, loading: false, isDeletingHost: false, isCreatingHost: false, @@ -118,10 +120,10 @@ export const useInbounds = create( set({ loading: value }) }, refetchInbounds: () => { - queryClient.invalidateQueries(queryIds.inbounds); + queryClient.invalidateQueries({ queryKey: [queryIds.inbounds] }); }, - refetchHosts: () => { - queryClient.invalidateQueries(queryIds.hosts); + refetchHosts: async () => { + queryClient.invalidateQueries({ queryKey: [queryIds.hosts] }); }, selectInbound: (host): void => { set({ selectedInbound: host }) @@ -149,7 +151,7 @@ export const useInbounds = create( createHost: async (inboundId: number | undefined, body: HostSchema): Promise => { if (inboundId !== undefined) { useDashboard.setState({ loading: true }); - return fetch(`/inbounds/${inboundId}/hosts/${body}`, { method: 'POST', body }) + return fetch(`/inbounds/${inboundId}/hosts`, { method: 'POST', body }) .then(() => true) .catch(() => false) .finally(() => { diff --git a/app/dashboard/src/stores/nodes.store.ts b/app/dashboard/src/stores/nodes.store.ts index 9cecb45..91b747e 100644 --- a/app/dashboard/src/stores/nodes.store.ts +++ b/app/dashboard/src/stores/nodes.store.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { fetch } from 'service/http'; import { create } from 'zustand'; import { z } from 'zod'; @@ -95,9 +95,11 @@ export type NodeStore = { onShowingNodesUsage: (isShowingNodesUsage: boolean) => void; }; +// TODO: Refactor all useQuery for inbounds, hosts, +// services and uses to be a custom hook like this. export const useNodesQuery = () => { return useQuery({ - queryKey: FetchNodesQueryKey, + queryKey: [FetchNodesQueryKey], queryFn: fetchNodes, refetchInterval: useNodes.getState().editingNode ? 3000 : undefined, refetchOnWindowFocus: false, @@ -130,7 +132,7 @@ export const useNodes = create((set, get) => ({ return fetch('/nodes', { method: 'POST', body }).then(() => { get().refetchCertificate() }); }, refetchNodes: () => { - queryClient.invalidateQueries(queryIds.nodes); + queryClient.invalidateQueries({ queryKey: [queryIds.nodes] }); }, refetchCertificate: () => { fetch('/nodes/settings').then((res) => { diff --git a/app/dashboard/src/stores/services.store.ts b/app/dashboard/src/stores/services.store.ts index a4a088e..b76f795 100644 --- a/app/dashboard/src/stores/services.store.ts +++ b/app/dashboard/src/stores/services.store.ts @@ -1,5 +1,4 @@ import { queryClient } from 'service/react-query'; -import { StatisticsQueryKey } from 'components/statistics-card'; import { Service, ServiceCreate } from 'types/service'; import { pageSizeManagers } from 'utils/userPreferenceStorage'; import { create } from 'zustand'; @@ -60,7 +59,7 @@ export const useServices = create( get().refetchServices(); }, refetchServices: () => { - queryClient.invalidateQueries(queryIds.services); + queryClient.invalidateQueries({ queryKey: [queryIds.services] }); }, onCreateService: (isCreatingNewService) => set({ isCreatingNewService }), onEditingService: (editingService) => { @@ -75,14 +74,12 @@ export const useServices = create( set({ deletingService: null }); get().refetchServices(); useUsers.getState().refetchUsers(); - queryClient.invalidateQueries(StatisticsQueryKey); }); }, createService: async (body: ServiceCreate) => { return fetch('/services', { method: 'POST', body }).then(() => { set({ editingService: null }); get().refetchServices(); - queryClient.invalidateQueries(StatisticsQueryKey); }); }, editService: async (body: ServiceCreate) => { diff --git a/app/dashboard/src/stores/users.store.ts b/app/dashboard/src/stores/users.store.ts index 8a4c3df..e8c2238 100644 --- a/app/dashboard/src/stores/users.store.ts +++ b/app/dashboard/src/stores/users.store.ts @@ -79,7 +79,7 @@ export const useUsers = create(subscribeWithSelector((set, get) set({ subscribeUrl }); }, refetchUsers: () => { - queryClient.invalidateQueries(queryIds.users); + queryClient.invalidateQueries({ queryKey: [queryIds.users] }); }, resetAllUsage: async () => { return fetch('/users/reset', { method: 'POST' }).then(() => { @@ -109,7 +109,7 @@ export const useUsers = create(subscribeWithSelector((set, get) return fetch(`/users/${user.username}`, { method: 'DELETE' }).then(() => { set({ deletingUser: null }); get().refetchUsers(); - queryClient.invalidateQueries(StatisticsQueryKey); + queryClient.invalidateQueries({ queryKey: [StatisticsQueryKey] }); }); }, createUser: async (body: UserCreate) => { @@ -117,7 +117,7 @@ export const useUsers = create(subscribeWithSelector((set, get) set({ editingUser: null }); get().refetchUsers(); useServices.getState().refetchServices(); - queryClient.invalidateQueries(StatisticsQueryKey); + queryClient.invalidateQueries({ queryKey: [StatisticsQueryKey] }); }); }, editUser: async (body: UserCreate) => { diff --git a/makefile b/makefile index 4b63f02..053e7a4 100644 --- a/makefile +++ b/makefile @@ -3,11 +3,11 @@ start: alembic upgrade head python main.py -dashboard-build: - cd app/dashboard/ +install-deps: npm install --prefix './app/dashboard' + +dashboard-build: install-deps VITE_BASE_API=/api/ npm run build --prefix './app/dashboard' --if-present -- --outDir dist --base '/dashboard/' - ls cp ./app/dashboard/dist/index.html ./app/dashboard/dist/404.html dashboard-dev: @@ -17,5 +17,13 @@ dashboard-dev: --base ./app/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/ \ + --clearScreen false + + dashboard-cleanup: rm -rf app/dashboard/node_modules/