Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions web/messages/en/initial_wizard.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"initial_setup_step_certificate_authority_description": "Securing component communication",
"initial_setup_step_certificate_authority_summary_label": "Certificate Authority Summary",
"initial_setup_step_certificate_authority_summary_description": "Securing component communication",
"initial_setup_step_edge_deploy_label": "Deploy Edge Component",
"initial_setup_step_edge_deploy_description": "Before we can adopt an Edge, this component needs to be launched.",
"initial_setup_step_edge_component_label": "Edge Component",
"initial_setup_step_edge_component_description": "Set up your VPN proxy quickly and ensure secure, optimized traffic flow for your users.",
"initial_setup_step_edge_adoption_label": "Edge Component Adoption",
Expand Down
14 changes: 11 additions & 3 deletions web/src/pages/SetupPage/initial/SetupPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SetupCertificateAuthoritySummaryStep } from './steps/SetupCertificateAu
import { SetupConfirmationStep } from './steps/SetupConfirmationStep';
import { SetupEdgeAdoptionStep } from './steps/SetupEdgeAdoptionStep';
import { SetupEdgeComponentStep } from './steps/SetupEdgeComponentStep';
import { SetupEdgeDeployStep } from './steps/SetupEdgeDeployStep';
import { SetupGeneralConfigStep } from './steps/SetupGeneralConfigStep';
import { SetupPageStep, type SetupPageStepValue } from './types';
import { useSetupWizardStore } from './useSetupWizardStore';
Expand Down Expand Up @@ -52,21 +53,27 @@ export const SetupPage = () => {
label: m.initial_setup_step_certificate_authority_summary_label(),
description: m.initial_setup_step_certificate_authority_summary_description(),
},
edgeDeploy: {
id: SetupPageStep.EdgeDeploy,
order: 5,
label: m.initial_setup_step_edge_deploy_label(),
description: m.initial_setup_step_edge_deploy_description(),
},
edgeComponent: {
id: SetupPageStep.EdgeComponent,
order: 5,
order: 6,
label: m.initial_setup_step_edge_component_label(),
description: m.initial_setup_step_edge_component_description(),
},
edgeAdoption: {
id: SetupPageStep.EdgeAdoption,
order: 6,
order: 7,
label: m.initial_setup_step_edge_adoption_label(),
description: m.initial_setup_step_edge_adoption_description(),
},
confirmation: {
id: SetupPageStep.Confirmation,
order: 7,
order: 8,
label: m.initial_setup_step_confirmation_label(),
description: m.initial_setup_step_confirmation_description(),
},
Expand All @@ -80,6 +87,7 @@ export const SetupPage = () => {
generalConfig: <SetupGeneralConfigStep />,
certificateAuthority: <SetupCertificateAuthorityStep />,
certificateAuthoritySummary: <SetupCertificateAuthoritySummaryStep />,
edgeDeploy: <SetupEdgeDeployStep />,
edgeComponent: <SetupEdgeComponentStep />,
edgeAdoption: <SetupEdgeAdoptionStep />,
confirmation: <SetupConfirmationStep />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const SetupCertificateAuthoritySummaryStep = () => {
};

const handleNext = () => {
setActiveStep(SetupPageStep.EdgeComponent);
setActiveStep(SetupPageStep.EdgeDeploy);
};

const downloadCA = () => {
Expand Down
279 changes: 279 additions & 0 deletions web/src/pages/SetupPage/initial/steps/SetupEdgeDeployStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
import { type ReactNode, useMemo, useState } from 'react';
import { m } from '../../../../paraglide/messages';
import { Card } from '../../../../shared/components/Card/Card';
import { CodeSnippet } from '../../../../shared/components/CodeSnippet/CodeSnippet';
import { Controls } from '../../../../shared/components/Controls/Controls';
import { WizardCard } from '../../../../shared/components/wizard/WizardCard/WizardCard';
import { AppText } from '../../../../shared/defguard-ui/components/AppText/AppText';
import { Button } from '../../../../shared/defguard-ui/components/Button/Button';
import { Checkbox } from '../../../../shared/defguard-ui/components/Checkbox/Checkbox';
import { Icon, IconKind } from '../../../../shared/defguard-ui/components/Icon';
import { RenderMarkdown } from '../../../../shared/defguard-ui/components/RenderMarkdown/RenderMarkdown';
import { SizedBox } from '../../../../shared/defguard-ui/components/SizedBox/SizedBox';
import { Tabs } from '../../../../shared/defguard-ui/components/Tabs/Tabs';
import type { TabsItem } from '../../../../shared/defguard-ui/components/Tabs/types';
import {
TextStyle,
ThemeSpacing,
ThemeVariable,
} from '../../../../shared/defguard-ui/types';
import '../../../EdgeSetupPage/steps/style.scss';
import amazonImage from '../../../EdgeSetupPage/assets/amazon.png';
import kubernetesImage from '../../../EdgeSetupPage/assets/kub.png';
import teraImage from '../../../EdgeSetupPage/assets/terra.png';
import { SetupPageStep } from '../types';
import { useSetupWizardStore } from '../useSetupWizardStore';

type TabItem = 'docker' | 'compose' | 'package' | 'virtualImage' | 'other';

export const SetupEdgeDeployStep = () => {
const [confirmed, setConfirmed] = useState(false);
const [activeTab, setActiveTab] = useState<TabItem>('docker');

const tabsConfig = useMemo(
(): TabsItem[] => [
{
title: m.edge_setup_step_deploy_tabs_docker(),
onClick: () => setActiveTab('docker'),
active: activeTab === 'docker',
hidden: false,
},
{
title: m.edge_setup_step_deploy_tabs_compose(),
onClick: () => setActiveTab('compose'),
active: activeTab === 'compose',
hidden: false,
},
{
title: m.edge_setup_step_deploy_tabs_package(),
onClick: () => setActiveTab('package'),
active: activeTab === 'package',
hidden: false,
},
{
title: m.edge_setup_step_deploy_tabs_virtual_image(),
onClick: () => setActiveTab('virtualImage'),
active: activeTab === 'virtualImage',
hidden: false,
},
{
title: m.edge_setup_step_deploy_tabs_other(),
onClick: () => setActiveTab('other'),
active: activeTab === 'other',
hidden: false,
},
],
[activeTab],
);

return (
<WizardCard id="edge-deploy-step">
<Tabs items={tabsConfig} disablePadding />
<SizedBox height={ThemeSpacing.Xl2} />
{tabsContent[activeTab]}
<SizedBox height={ThemeSpacing.Xl2} />
<Checkbox
active={confirmed}
onClick={() => {
setConfirmed((s) => !s);
}}
text={m.edge_setup_step_deploy_confirm()}
/>
<SizedBox height={ThemeSpacing.Xl3} />
<Controls>
<Button
variant={'outlined'}
text={m.controls_back()}
onClick={() => {
useSetupWizardStore.getState().setActiveStep(SetupPageStep.CASummary);
}}
/>
<div className="right">
<Button
text={m.controls_continue()}
disabled={!confirmed}
onClick={() => {
useSetupWizardStore.getState().setActiveStep(SetupPageStep.EdgeComponent);
}}
/>
</div>
</Controls>
</WizardCard>
);
};

const TabContentHeader = ({ subtitle, title }: { title: string; subtitle: string }) => {
return (
<div className="tab-content-header">
<AppText font={TextStyle.TBodyPrimary500}>{title}</AppText>
<SizedBox height={ThemeSpacing.Sm} />
<RenderMarkdown content={subtitle} />
<SizedBox height={ThemeSpacing.Md} />
</div>
);
};

const DockerComposeTab = () => {
return (
<>
<TabContentHeader
title={m.edge_setup_step_deploy_tabs_compose_title()}
subtitle={m.edge_setup_step_deploy_tabs_compose_subtitle({
filename: `docker-compose.yaml`,
})}
/>
<CodeSnippet
value={`services:
proxy:
image: ghcr.io/defguard/defguard-proxy:latest
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
- "50051:50051"`}
/>
<SizedBox height={ThemeSpacing.Xl2} />
<AppText font={TextStyle.TBodySm400}>
{m.edge_setup_step_deploy_tabs_compose_then()}
</AppText>
<SizedBox height={ThemeSpacing.Md} />
<CodeSnippet value={`docker compose up -d`} />
</>
);
};

const DockerTab = () => {
return (
<>
<TabContentHeader
title={m.edge_setup_step_deploy_tabs_docker_title()}
subtitle={m.edge_setup_step_deploy_tabs_docker_subtitle()}
/>
<CodeSnippet
value={`docker run --restart unless-stopped ghcr.io/defguard/defguard-proxy:latest`}
/>
</>
);
};

const PackageTab = () => {
return (
<>
<TabContentHeader
title={m.edge_setup_step_deploy_tabs_package_title()}
subtitle={m.edge_setup_step_deploy_tabs_package_subtitle()}
/>
<CodeSnippet
value={`sudo apt update
sudo apt install -y ca-certificates curl
#Add official Defguard public GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://apt.defguard.net/defguard.asc -o /etc/apt/keyrings/defguard.asc
sudo chmod a+r /etc/apt/keyrings/defguard.asc

#Add APT repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/defguard.asc] https://apt.defguard.net/ trixie release " | \
sudo tee /etc/apt/sources.list.d/defguard.list > /dev/null

sudo apt update
sudo apt install defguard-proxy`}
/>
</>
);
};

const VirtualImageTab = () => {
return (
<>
<TabContentHeader
title={m.edge_setup_step_deploy_tabs_virtual_title()}
subtitle={m.edge_setup_step_deploy_tabs_virtual_subtitle({
url: `https://defguard.net/download/defguard-2x-latest.ovf`,
filename: `cloud-init-yaml`,
})}
/>
<CodeSnippet
value={`launch: gateway

runcmd:
- |
LAUNCH=$(jq -r '.["user-data"].launch' /run/cloud-init/instance-data.json)

echo "Launch option = $LAUNCH"

if [ "$LAUNCH" = "gateway" ]; then
systemctl enable defguard-gateway
systemctl start defguard-gateway
else
echo "Unknown launch: $LAUNCH"
fi`}
/>
</>
);
};

const OtherDeploymentMethod = ({
image,
link,
name,
}: {
image: string;
name: string;
link: string;
}) => {
return (
<Card>
<div className="inner-track">
<div className="image-tack">
<img src={image} width={44} height={44} />
</div>
<div className="content">
<p className="title">{name}</p>
<a target="_blank" rel="noopener noreferrer" href={link}>
<span>{link}</span>
<Icon icon={IconKind.OpenInNewWindow} size={16} />
</a>
</div>
</div>
</Card>
);
};

const OthersTab = () => {
return (
<>
<TabContentHeader
title={m.edge_setup_step_deploy_tabs_other_title()}
subtitle={m.edge_setup_step_deploy_tabs_other_subtitle()}
/>
<div id="other-deployment-methods">
<OtherDeploymentMethod
name={`Kubernetes`}
link={`https://docs.defguard.net/deployment-strategies/kubernetes#deployment`}
image={kubernetesImage}
/>
<OtherDeploymentMethod
name={`Amazon Machine Image`}
link={`https://docs.defguard.net/deployment-strategies/amis-and-aws-cloudformation`}
image={amazonImage}
/>
<OtherDeploymentMethod
name={`Terraform`}
link={`https://docs.defguard.net/deployment-strategies/terraform`}
image={teraImage}
/>
</div>
<SizedBox height={ThemeSpacing.Lg} />
<AppText font={TextStyle.TBodySm400} color={ThemeVariable.FgFaded}>
{m.edge_setup_step_deploy_tabs_other_launch()}
</AppText>
</>
);
};

const tabsContent: Record<TabItem, ReactNode> = {
docker: <DockerTab />,
compose: <DockerComposeTab />,
package: <PackageTab />,
virtualImage: <VirtualImageTab />,
other: <OthersTab />,
};
1 change: 1 addition & 0 deletions web/src/pages/SetupPage/initial/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const SetupPageStep = {
GeneralConfig: 'generalConfig',
CertificateAuthority: 'certificateAuthority',
CASummary: 'certificateAuthoritySummary',
EdgeDeploy: 'edgeDeploy',
EdgeComponent: 'edgeComponent',
EdgeAdoption: 'edgeAdoption',
Confirmation: 'confirmation',
Expand Down
Loading