Skip to content

Commit

Permalink
Merge pull request #87 from DefGuard/disable-manual-config
Browse files Browse the repository at this point in the history
  • Loading branch information
teon authored Sep 3, 2024
2 parents 931be7b + 94af2b6 commit 8da92de
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ import { TimeLeft } from '../TimeLeft/TimeLeft';
export const EnrollmentSideBar = () => {
const { LL } = useI18nContext();

const vpnOptional = useEnrollmentStore((state) => state.vpnOptional);
const vpnOptional = useEnrollmentStore(
(state) => state.enrollmentSettings?.vpn_setup_optional,
);
const [currentStep, stepsMax] = useEnrollmentStore((state) => [
state.step,
state.stepsMax,
]);
const enrollmentSettings = useEnrollmentStore((state) => state.enrollmentSettings);

// fetch app version
const { getAppInfo } = useApi();
Expand All @@ -37,16 +40,20 @@ export const EnrollmentSideBar = () => {
}, []);

const steps = useMemo((): LocalizedString[] => {
const steps = LL.pages.enrollment.sideBar.steps;
const vpnStep = vpnOptional ? `${steps.vpn()}*` : steps.vpn();
return [
steps.welcome(),
steps.verification(),
steps.password(),
vpnStep as LocalizedString,
steps.finish(),
const stepsLL = LL.pages.enrollment.sideBar.steps;
const vpnStep = (
vpnOptional ? `${stepsLL.vpn()}*` : stepsLL.vpn()
) as LocalizedString;
const steps = [
stepsLL.welcome(),
stepsLL.verification(),
stepsLL.password(),
...(!enrollmentSettings?.only_client_activation
? [vpnStep, stepsLL.finish()]
: [stepsLL.finish()]),
];
}, [LL.pages.enrollment.sideBar.steps, vpnOptional]);
return steps;
}, [LL.pages.enrollment.sideBar.steps, vpnOptional, enrollmentSettings]);

return (
<div id="enrollment-side-bar">
Expand Down
5 changes: 3 additions & 2 deletions web/src/pages/enrollment/hooks/store/useEnrollmentStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AdminInfo,
Device,
DeviceConfig,
EnrollmentSettings,
UserInfo,
} from '../../../../shared/hooks/api/types';

Expand All @@ -30,7 +31,7 @@ const persistKeys: Array<keyof StoreValues> = [
'adminInfo',
'deviceState',
'endContent',
'vpnOptional',
'enrollmentSettings',
];

export const useEnrollmentStore = createWithEqualityFn<Store>()(
Expand Down Expand Up @@ -82,7 +83,7 @@ type StoreValues = {
userInfo?: UserInfo;
userPassword?: string;
adminInfo?: AdminInfo;
vpnOptional?: boolean;
enrollmentSettings?: EnrollmentSettings;
// Markdown content for final step card
endContent?: string;
deviceState?: {
Expand Down
58 changes: 44 additions & 14 deletions web/src/pages/enrollment/steps/DeviceStep/DeviceStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { useEffect } from 'react';
import { shallow } from 'zustand/shallow';

import { useI18nContext } from '../../../../i18n/i18n-react';
import { LoaderSpinner } from '../../../../shared/components/layout/LoaderSpinner/LoaderSpinner';
import { MessageBox } from '../../../../shared/components/layout/MessageBox/MessageBox';
import { MessageBoxType } from '../../../../shared/components/layout/MessageBox/types';
import { useApi } from '../../../../shared/hooks/api/useApi';
import useEffectOnce from '../../../../shared/hooks/api/utils';
import { useEnrollmentStore } from '../../hooks/store/useEnrollmentStore';
import { ConfigureDeviceCard } from './components/ConfigureDeviceCard/ConfigureDeviceCard';
import { QuickGuideCard } from './components/QuickGuideCard/QuickGuideCard';
Expand All @@ -21,7 +23,7 @@ export const DeviceStep = () => {
const { LL } = useI18nContext();
const setStore = useEnrollmentStore((state) => state.setState);
const deviceState = useEnrollmentStore((state) => state.deviceState);
const vpnOptional = useEnrollmentStore((state) => state.vpnOptional);
const settings = useEnrollmentStore((state) => state.enrollmentSettings);
const [userPhone, userPassword] = useEnrollmentStore(
(state) => [state.userInfo?.phone_number, state.userPassword],
shallow,
Expand All @@ -32,8 +34,8 @@ export const DeviceStep = () => {
);

const cn = classNames({
required: !vpnOptional,
optional: vpnOptional,
required: !settings?.vpn_setup_optional,
optional: settings?.vpn_setup_optional,
});

const { mutate } = useMutation({
Expand All @@ -51,7 +53,11 @@ export const DeviceStep = () => {
useEffect(() => {
if (userPassword) {
const sub = nextSubject.subscribe(() => {
if ((deviceState && deviceState.device && deviceState.configs) || vpnOptional) {
if (
(deviceState && deviceState.device && deviceState.configs) ||
settings?.vpn_setup_optional ||
settings?.only_client_activation
) {
setStore({
loading: true,
});
Expand All @@ -66,20 +72,44 @@ export const DeviceStep = () => {
sub.unsubscribe();
};
}
}, [deviceState, nextSubject, vpnOptional, setStore, userPhone, userPassword, mutate]);
}, [
deviceState,
nextSubject,
settings?.vpn_setup_optional,
setStore,
userPhone,
userPassword,
mutate,
settings?.only_client_activation,
]);

// If only client activation is enabled, skip manual wireguard setup
useEffectOnce(() => {
if (settings?.only_client_activation) {
nextSubject.next();
}
});

return (
<div id="enrollment-device-step" className={cn}>
{vpnOptional && (
<MessageBox
type={MessageBoxType.WARNING}
message={LL.pages.enrollment.steps.deviceSetup.optionalMessage()}
/>
{!settings?.only_client_activation ? (
<>
{settings?.vpn_setup_optional && (
<MessageBox
type={MessageBoxType.WARNING}
message={LL.pages.enrollment.steps.deviceSetup.optionalMessage()}
/>
)}
<div className="cards">
<ConfigureDeviceCard />
<QuickGuideCard />
</div>
</>
) : (
<div id="loader">
<LoaderSpinner size={80} />
</div>
)}
<div className="cards">
<ConfigureDeviceCard />
<QuickGuideCard />
</div>
</div>
);
};
7 changes: 7 additions & 0 deletions web/src/pages/enrollment/steps/DeviceStep/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@
}
}
}

#loader {
display: flex;
justify-content: center;
align-items: center;
height: 500px;
}
}
2 changes: 1 addition & 1 deletion web/src/pages/main/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export const MainPage = () => {
adminInfo: res.admin,
sessionStart,
sessionEnd,
vpnOptional: res.vpn_setup_optional,
endContent: res.final_page_content,
enrollmentSettings: res.settings,
});
navigate(routes.enrollment, { replace: true });
})
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/token/components/TokenCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const TokenCard = () => {
adminInfo: res.admin,
sessionStart,
sessionEnd,
vpnOptional: res.vpn_setup_optional,
enrollmentSettings: res.settings,
endContent: res.final_page_content,
});
navigate(routes.enrollment, { replace: true });
Expand Down
7 changes: 6 additions & 1 deletion web/src/shared/hooks/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ export type EnrollmentStartRequest = {
token: string;
};

export type EnrollmentSettings = {
vpn_setup_optional: boolean;
only_client_activation: boolean;
};

export type EnrollmentStartResponse = {
admin: AdminInfo;
user: UserInfo;
deadline_timestamp: number;
final_page_content: string;
vpn_setup_optional: boolean;
settings: EnrollmentSettings;
};

export type ActivateUserRequest = {
Expand Down
20 changes: 20 additions & 0 deletions web/src/shared/hooks/api/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
import { useEffect, useRef } from 'react';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const removeNulls = (obj: any) => {
return JSON.parse(JSON.stringify(obj), (_, value) => {
if (value == null) return undefined;
return value;
});
};

/**
Under normal circumstances, useEffect should run only once when passed an empty dependency array.
However, in dev mode with react strict mode enabled, everything is rendered twice for debugging purposes.
This also causes useEffect to run twice, which is not always desirable.
This custom hook ensures that the effect runs only once in dev mode as well.
*/
export default function useEffectOnce(fn: () => void) {
const isMounted = useRef(false);
useEffect(() => {
if (isMounted.current) {
return;
}

fn();
isMounted.current = true;
}, [fn]);
}
2 changes: 1 addition & 1 deletion web/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import autoprefixer from 'autoprefixer';
import * as path from 'path';
import { defineConfig } from 'vite';

// https://vitejs.dev/config/
export default defineConfig({
Expand Down

0 comments on commit 8da92de

Please sign in to comment.