diff --git a/src/App.tsx b/src/App.tsx index e18e7dc8..e5b4d488 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -29,30 +29,12 @@ import PageRouter from './Router'; import AstarteProvider, { useAstarte } from './AstarteManager'; import type { DashboardConfig } from './types'; import Snackbar from './ui/Snackbar'; -import useFetch from './hooks/useFetch'; -import useInterval from './hooks/useInterval'; import createReduxStore from './store'; const DashboardSidebar = () => { const config = useConfig(); const astarte = useAstarte(); - const healthFetcher = useFetch(() => { - const apiChecks = [ - astarte.client.getAppengineHealth(), - astarte.client.getRealmManagementHealth(), - astarte.client.getPairingHealth(), - ]; - if (config.features.flow) { - apiChecks.push(astarte.client.getFlowHealth()); - } - return Promise.all(apiChecks); - }); - - useInterval(healthFetcher.refresh, 30000); - - const isApiHealthy = healthFetcher.status !== 'err'; - if (!astarte.isAuthenticated) { return null; } @@ -80,7 +62,7 @@ const DashboardSidebar = () => { )} - + diff --git a/src/HomePage.tsx b/src/HomePage.tsx index 8b0ffd02..fff41a04 100644 --- a/src/HomePage.tsx +++ b/src/HomePage.tsx @@ -108,12 +108,14 @@ const ApiStatusCard = ({ interface DevicesCardProps { connectedDevices: number; totalDevices: number; + deviceRegistrationLimit: number | null; connectedDevicesProvider: ChartProvider<'Object', ConnectedDevices>; } const DevicesCard = ({ connectedDevices, totalDevices, + deviceRegistrationLimit, connectedDevicesProvider, }: DevicesCardProps): React.ReactElement => ( @@ -123,9 +125,15 @@ const DevicesCard = ({ Connected devices - {connectedDevices} + + {connectedDevices} / {totalDevices} + Registered devices - {totalDevices} + + {deviceRegistrationLimit != null + ? `${totalDevices} / ${deviceRegistrationLimit}` + : totalDevices} + {totalDevices > 0 && } @@ -319,6 +327,7 @@ const HomePage = (): React.ReactElement => { const realmManagementHealth = useFetch(astarte.client.getRealmManagementHealth); const pairingHealth = useFetch(astarte.client.getPairingHealth); const flowHealth = useFetch(config.features.flow ? astarte.client.getFlowHealth : async () => {}); + const deviceRegistrationLimitFetcher = useFetch(astarte.client.getDeviceRegistrationLimit); const navigate = useNavigate(); const connectedDevicesProvider = useMemo( @@ -379,6 +388,7 @@ const HomePage = (): React.ReactElement => { diff --git a/src/RealmSettingsPage.tsx b/src/RealmSettingsPage.tsx index 8df82c42..f907835a 100644 --- a/src/RealmSettingsPage.tsx +++ b/src/RealmSettingsPage.tsx @@ -82,6 +82,7 @@ export default (): React.ReactElement => { const navigate = useNavigate(); const authConfigFetcher = useFetch(astarte.client.getConfigAuth); + const deviceRegistrationLimitFetcher = useFetch(astarte.client.getDeviceRegistrationLimit); const showModal = useCallback(() => setIsModalVisible(true), [setIsModalVisible]); @@ -122,6 +123,10 @@ export default (): React.ReactElement => { return ( + + Device registration limit + + { ); }; -export default (): React.ReactElement => { +function RegisterDevicePage(): React.ReactElement { const searchQuery = new URLSearchParams(useLocation().search); const initialDeviceId = searchQuery.get('deviceId') || ''; const [deviceId, setDeviceId] = useState(initialDeviceId); @@ -268,6 +269,15 @@ export default (): React.ReactElement => { const [registrationAlerts, registrationAlertsController] = useAlerts(); const astarte = useAstarte(); const navigate = useNavigate(); + const deviceRegistrationLimitFetcher = useFetch(astarte.client.getDeviceRegistrationLimit); + const devicesStatsFetcher = useFetch(astarte.client.getDevicesStats); + + const isFetchingRegistrationStats = + devicesStatsFetcher.status === 'loading' || deviceRegistrationLimitFetcher.status === 'loading'; + const deviceRegistrationLimitReached = + devicesStatsFetcher.value != null && + deviceRegistrationLimitFetcher.value != null && + devicesStatsFetcher.value.totalDevices >= deviceRegistrationLimitFetcher.value; const byteArray = urlSafeBase64ToByteArray(deviceId); const isValidDeviceId = byteArray.length === 17 && byteArray[16] === 0; @@ -295,8 +305,11 @@ export default (): React.ReactElement => { setShowCredentialSecretModal(true); }) .catch((err) => { + const errorMessage = deviceRegistrationLimitReached + ? `The device registration limit is set to ${deviceRegistrationLimitFetcher.value} and there are too many registered devices already.` + : err.message; setRegisteringDevice(false); - registrationAlertsController.showError(`Couldn't register device: ${err.message}`); + registrationAlertsController.showError(`Could not register the device. ${errorMessage}`); }); }; @@ -371,7 +384,7 @@ export default (): React.ReactElement => {