Skip to content

Commit

Permalink
fix: overview network selection (#244)
Browse files Browse the repository at this point in the history
  • Loading branch information
filipslezaklab committed Jul 13, 2023
1 parent 01612c3 commit 7412620
Show file tree
Hide file tree
Showing 20 changed files with 197 additions and 107 deletions.
19 changes: 17 additions & 2 deletions web/src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './style.scss';

import { useMutation } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useLocation } from 'react-router';
import { useBreakpoint } from 'use-breakpoint';
Expand All @@ -17,7 +17,9 @@ import SvgIconNavWebhooks from '../../shared/components/svg/IconNavWebhooks';
import { deviceBreakpoints } from '../../shared/constants';
import { useAppStore } from '../../shared/hooks/store/useAppStore';
import { useAuthStore } from '../../shared/hooks/store/useAuthStore';
import { useUserProfileStore } from '../../shared/hooks/store/useUserProfileStore';
import useApi from '../../shared/hooks/useApi';
import { QueryKeys } from '../../shared/queries';
import { User } from '../../shared/types';
import { NavigationDesktop } from './components/NavigationDesktop/NavigationDesktop';
import { NavigationMobile } from './components/NavigationMobile/NavigationMobile';
Expand All @@ -33,6 +35,9 @@ export const Navigation = () => {
shallow
);
const setStore = useNavigationStore((state) => state.setState);
const networksPresent = useAppStore((state) => state.appInfo?.network_present);
const resetUserProfile = useUserProfileStore((state) => state.reset);
const queryClient = useQueryClient();

const {
auth: { logout },
Expand All @@ -56,6 +61,8 @@ export const Navigation = () => {
};
}

const overviewLink = networksPresent ? '/admin/overview' : '/admin/wizard';

let bottom: NavigationItem[] = [
{
title: LL.navigation.bar.settings(),
Expand All @@ -68,7 +75,7 @@ export const Navigation = () => {
let middle: NavigationItem[] = [
{
title: LL.navigation.bar.overview(),
linkPath: '/admin/overview',
linkPath: overviewLink,
icon: <SvgIconNavVpn />,
allowedToView: ['admin'],
enabled: settings?.wireguard_enabled,
Expand Down Expand Up @@ -107,6 +114,11 @@ export const Navigation = () => {
icon: <SvgIconNavProfile />,
allowedToView: [],
enabled: true,
onClick: () => {
resetUserProfile();
queryClient.invalidateQueries([QueryKeys.FETCH_ME]);
queryClient.invalidateQueries([QueryKeys.FETCH_USER_PROFILE]);
},
},
];
middle = filterNavItems(middle, currentUser);
Expand All @@ -118,6 +130,9 @@ export const Navigation = () => {
}, [
LL.navigation.bar,
currentUser,
networksPresent,
queryClient,
resetUserProfile,
settings?.openid_enabled,
settings?.webhooks_enabled,
settings?.wireguard_enabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ export const NavigationLink = ({ item, callback }: NavigationLinkProps) => {
const match = useMatch(item.linkPath);
return (
<Link
replace
to={item.linkPath}
onClick={() => callback}
className={match ? 'active' : undefined}
replace
onClick={() => {
if (callback) {
callback();
}
if (item.onClick) {
item.onClick();
}
}}
>
{item.icon}
<span>{item.title}</span>
Expand Down
1 change: 1 addition & 0 deletions web/src/components/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface NavigationItem {
icon?: React.ReactNode;
allowedToView?: string[];
enabled: boolean | undefined;
onClick?: () => void;
}

export type NavigationTitleMapItem = {
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/overview/OverviewHeader/OverviewHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const OverviewHeader = ({ loading = false }: Props) => {
{breakpoint !== 'desktop' && (
<div className="mobile-options">
<div className="top-row">
<GatewaysStatus networkId={selectedNetworkId} />
{selectedNetworkId && <GatewaysStatus networkId={selectedNetworkId} />}
{renderEditNetworks()}
</div>
<OverViewNetworkSelect />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isUndefined } from 'lodash-es';
import { useMemo } from 'react';
import { shallow } from 'zustand/shallow';

Expand Down Expand Up @@ -39,7 +40,7 @@ export const OverViewNetworkSelect = () => {
return (
<Select
placeholder={LL.networkOverview.controls.selectNetwork.placeholder()}
loading={networks?.length === 0 || !selected}
loading={isUndefined(networks) || networks.length === 0}
selected={selected}
options={options}
onChange={(option) => {
Expand Down
52 changes: 30 additions & 22 deletions web/src/pages/overview/OverviewPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './style.scss';

import { useQuery } from '@tanstack/react-query';
import { isUndefined } from 'lodash-es';
import { isUndefined, orderBy } from 'lodash-es';
import { useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router';
import { useBreakpoint } from 'use-breakpoint';
Expand Down Expand Up @@ -47,6 +47,14 @@ export const OverviewPage = () => {
navigate('/admin/wizard', { replace: true });
} else {
setOverViewStore({ networks: res });
const ids = res.map((n) => n.id);
if (
isUndefined(selectedNetworkId) ||
(!isUndefined(selectedNetworkId) && !ids.includes(selectedNetworkId))
) {
const oldestNetwork = orderBy(res, ['id'], ['asc'])[0];
setOverViewStore({ selectedNetworkId: oldestNetwork.id });
}
}
},
}
Expand All @@ -57,7 +65,7 @@ export const OverviewPage = () => {
() =>
getNetworkStats({
from: getNetworkStatsFilterValue(statsFilter),
id: selectedNetworkId,
id: selectedNetworkId as number,
}),
{
refetchOnWindowFocus: false,
Expand All @@ -71,7 +79,7 @@ export const OverviewPage = () => {
() =>
getUsersStats({
from: getNetworkStatsFilterValue(statsFilter),
id: selectedNetworkId,
id: selectedNetworkId as number,
}),
{
enabled: !isUndefined(statsFilter) && !isUndefined(selectedNetworkId),
Expand Down Expand Up @@ -103,25 +111,25 @@ export const OverviewPage = () => {
}, [setOverViewStore, viewMode]);

return (
<>
<PageContainer id="network-overview-page">
<OverviewHeader loading={networksLoading} />
{breakpoint === 'desktop' && <GatewaysStatus networkId={selectedNetworkId} />}
{networkStats && networkUsersStats && (
<OverviewStats usersStats={networkUsersStats} networkStats={networkStats} />
<PageContainer id="network-overview-page">
<OverviewHeader loading={networksLoading} />
{breakpoint === 'desktop' && !isUndefined(selectedNetworkId) && (
<GatewaysStatus networkId={selectedNetworkId} />
)}
{networkStats && networkUsersStats && (
<OverviewStats usersStats={networkUsersStats} networkStats={networkStats} />
)}
<div className="bottom-row">
{userStatsLoading ? (
<div className="stats-loader">
<LoaderSpinner size={180} />
</div>
) : getNetworkUsers.length > 0 ? (
<OverviewConnectedUsers stats={getNetworkUsers} />
) : (
<NoData />
)}
<div className="bottom-row">
{userStatsLoading ? (
<div className="stats-loader">
<LoaderSpinner size={180} />
</div>
) : getNetworkUsers.length > 0 ? (
<OverviewConnectedUsers stats={getNetworkUsers} />
) : (
<NoData />
)}
</div>
</PageContainer>
</>
</div>
</PageContainer>
);
};
2 changes: 1 addition & 1 deletion web/src/pages/overview/hooks/store/useOverviewStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const useOverviewStore = create<
setState: (newValues) => set((state) => ({ ...state, ...newValues })),
}),
{
version: 0.2,
version: 0.21,
name: 'overview-store',
storage: createJSONStorage(() => sessionStorage),
partialize: (store) => omit(store, ['setState', 'networks']),
Expand Down
16 changes: 12 additions & 4 deletions web/src/pages/users/UserProfile/ProfileDetails/ProfileDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import './style.scss';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import classNames from 'classnames';
import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { Card } from '../../../../shared/components/layout/Card/Card';
Expand All @@ -19,15 +21,21 @@ import { ProfileDetailsForm } from './ProfileDetailsForm/ProfileDetailsForm';

export const ProfileDetails = () => {
const { LL } = useI18nContext();
const editMode = useUserProfileStore((state) => state.editMode);
const [editMode, userProfile] = useUserProfileStore(
(state) => [state.editMode, state.userProfile],
shallow
);
return (
<section id="profile-details">
<header>
<h2>{LL.userPage.userDetails.header()}</h2>
</header>
<Card className={classNames({ edit: editMode })}>
{editMode ? <ProfileDetailsForm /> : <ViewMode />}
</Card>
{userProfile && (
<Card className={classNames({ edit: editMode })}>
{editMode ? <ProfileDetailsForm /> : <ViewMode />}
</Card>
)}
{!userProfile && <Skeleton className="profile-details" />}
</section>
);
};
Expand Down
5 changes: 5 additions & 0 deletions web/src/pages/users/UserProfile/ProfileDetails/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
@use '../../../../shared/scss/helpers' as *;

#profile-details {
//skeleton
.react-loading-skeleton {
height: 550px;
}

& > .card {
padding: 2rem 1.5rem 3rem;

Expand Down
15 changes: 11 additions & 4 deletions web/src/pages/users/UserProfile/UserAuthInfo/UserAuthInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import './style.scss';

import Skeleton from 'react-loading-skeleton';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { Card } from '../../../../shared/components/layout/Card/Card';
import { useUserProfileStore } from '../../../../shared/hooks/store/useUserProfileStore';
import { ManageWebAuthNKeysModal } from './modals/ManageWebAuthNModal/ManageWebAuthNModal';
import { RecoveryCodesModal } from './modals/RecoveryCodesModal/RecoveryCodesModal';
import { RegisterTOTPModal } from './modals/RegisterTOTPModal/RegisterTOTPModal';
Expand All @@ -10,15 +13,19 @@ import { UserAuthInfoPassword } from './UserAuthInfoPassword';

export const UserAuthInfo = () => {
const { LL } = useI18nContext();
const userProfile = useUserProfileStore((state) => state.userProfile);
return (
<section id="user-auth-info">
<header>
<h2>{LL.userPage.userAuthInfo.header()}</h2>
</header>
<Card>
<UserAuthInfoPassword />
<UserAuthInfoMFA />
</Card>
{userProfile && (
<Card>
<UserAuthInfoPassword />
<UserAuthInfoMFA />
</Card>
)}
{!userProfile && <Skeleton />}
<ManageWebAuthNKeysModal />
<RegisterTOTPModal />
<RecoveryCodesModal />
Expand Down
5 changes: 5 additions & 0 deletions web/src/pages/users/UserProfile/UserAuthInfo/style.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
@use '../../../../shared/scss/helpers' as *;

#user-auth-info {

.react-loading-skeleton {
height: 180px;
}

& > h2 {
@include card-header;
}
Expand Down
32 changes: 21 additions & 11 deletions web/src/pages/users/UserProfile/UserDevices/UserDevices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './style.scss';
import { fs } from '@tauri-apps/api';
import { isUndefined } from 'lodash-es';
import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { useAppStore } from '../../../../shared/hooks/store/useAppStore';
Expand Down Expand Up @@ -36,6 +37,13 @@ export const UserDevices = () => {
<header>
<h2>{LL.userPage.devices.header()}</h2>
</header>
{!userProfile && (
<div className="skeletons">
<Skeleton />
<Skeleton />
<Skeleton />
</div>
)}
{userProfile && (
<>
{userProfile.devices && userProfile.devices.length > 0 && (
Expand All @@ -45,17 +53,19 @@ export const UserDevices = () => {
))}
</div>
)}
<AddComponentBox
data-testid="add-device"
text={LL.userPage.devices.addDevice.web()}
disabled={!appInfo?.network_present}
callback={() =>
openDeviceModal({
visible: true,
})
}
/>
{isDesktopApp && !isDeviceConfigPresent && (
{userProfile && !isDesktopApp && (
<AddComponentBox
data-testid="add-device"
text={LL.userPage.devices.addDevice.web()}
disabled={!appInfo?.network_present}
callback={() =>
openDeviceModal({
visible: true,
})
}
/>
)}
{userProfile && isDesktopApp && !isDeviceConfigPresent && (
<AddComponentBox
disabled={!appInfo?.network_present}
text={LL.userPage.devices.addDevice.desktop()}
Expand Down
10 changes: 10 additions & 0 deletions web/src/pages/users/UserProfile/UserDevices/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
width: 100%;
min-width: 100%;

& > .skeletons {
width: 100%;
display: flex;
flex-flow: column;
row-gap: 20px;
.react-loading-skeleton {
height: 70px;
}
}

& > header {
margin-bottom: 2rem;

Expand Down
Loading

0 comments on commit 7412620

Please sign in to comment.