Skip to content

Commit

Permalink
feat: display new completed dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
sjaanus committed Sep 25, 2024
1 parent 957ef12 commit 4728464
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 70 deletions.
60 changes: 33 additions & 27 deletions frontend/src/component/onboarding/ConnectSdkDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ import {
useTheme,
} from '@mui/material';
import { GenerateApiKey } from './GenerateApiKey';
import { lazy, Suspense, useEffect, useState } from 'react';
import { lazy, useEffect, useState } from 'react';
import { SelectSdk } from './SelectSdk';
import { GenerateApiKeyConcepts, SelectSdkConcepts } from './UnleashConcepts';

const TestSdkConnection = lazy(() => import('./TestSdkConnection'));

import type { Sdk } from './sharedTypes';
import { ConnectionInformation } from './ConnectionInformation';
import Loader from 'component/common/Loader/Loader';
import { SdkConnection } from './SdkConnection';
import useProjectOverview from '../../hooks/api/getters/useProjectOverview/useProjectOverview';

interface IConnectSDKDialogProps {
open: boolean;
onClose: () => void;
project: string;
environments: string[];
feature: string;
feature?: string;
}

const ConnectSdk = styled('main')(({ theme }) => ({
Expand Down Expand Up @@ -68,7 +69,7 @@ export const ConnectSdkDialog = ({
open,
onClose,
environments,
project,
project: projectId,
feature,
}: IConnectSDKDialogProps) => {
const theme = useTheme();
Expand All @@ -77,13 +78,18 @@ export const ConnectSdkDialog = ({
const [environment, setEnvironment] = useState<string | null>(null);
const [apiKey, setApiKey] = useState<string | null>(null);
const [stage, setStage] = useState<OnboardingStage>('select-sdk');
const { project } = useProjectOverview(projectId, {
refreshInterval: 1000,
});

const isSelectSdkStage = stage === 'select-sdk';
const isGenerateApiKeyStage =
stage === 'generate-api-key' && sdk && environment;
const isTestConnectionStage =
stage === 'test-connection' && sdk && environment && apiKey;

const onboarded = project.onboardingStatus.status === 'onboarded';

useEffect(() => {
if (environments.length > 0) {
setEnvironment(environments[0]);
Expand All @@ -106,23 +112,21 @@ export const ConnectSdkDialog = ({
<GenerateApiKey
environments={environments}
environment={environment}
project={project}
project={projectId}
sdkType={sdk.type}
onEnvSelect={setEnvironment}
onApiKey={setApiKey}
/>
) : null}
{isTestConnectionStage ? (
<Suspense fallback={<Loader />}>
<TestSdkConnection
sdk={sdk}
apiKey={apiKey}
feature={feature}
onSdkChange={() => {
setStage('select-sdk');
}}
/>
</Suspense>
<SdkConnection
apiKey={apiKey}
sdk={sdk}
feature={feature}
onSdkChange={() => {
setStage('select-sdk');
}}
/>
) : null}

{stage === 'generate-api-key' ? (
Expand Down Expand Up @@ -152,22 +156,25 @@ export const ConnectSdkDialog = ({
{isTestConnectionStage ? (
<Navigation>
<NextStepSectionSpacedContainer>
<Button
variant='text'
color='inherit'
onClick={() => {
setStage('generate-api-key');
}}
>
Back
</Button>
{!onboarded ? (
<Button
variant='text'
color='inherit'
onClick={() => {
setStage('generate-api-key');
}}
>
Back
</Button>
) : null}

<Button
variant='contained'
onClick={() => {
onClose();
}}
>
Finish
Next
</Button>
</NextStepSectionSpacedContainer>
</Navigation>
Expand All @@ -182,10 +189,9 @@ export const ConnectSdkDialog = ({
) : null}
{isLargeScreen && isTestConnectionStage ? (
<ConnectionInformation
projectId={project}
projectId={projectId}
sdk={sdk.name}
environment={environment}
onConnection={onClose}
/>
) : null}
</Box>
Expand Down
74 changes: 42 additions & 32 deletions frontend/src/component/onboarding/ConnectionInformation.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { styled, Typography, useTheme } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { WhitePulsingAvatar } from 'component/common/PulsingAvatar/PulsingAvatar';
import Pending from '@mui/icons-material/Pending';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { useEffect } from 'react';
import Check from '@mui/icons-material/Check';

interface IConnectionInformationProps {
onConnection: () => void;
projectId: string;
sdk: string;
environment: string;
Expand Down Expand Up @@ -50,8 +48,16 @@ export const ConnectionStatus = styled('div')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
}));

export const StyledCheck = styled(Check)(({ theme }) => ({
color: theme.palette.primary.main,
backgroundColor: theme.palette.background.paper,
borderRadius: '50%',
padding: theme.spacing(1),
width: '80px',
height: '80px',
}));

export const ConnectionInformation = ({
onConnection,
projectId,
sdk,
environment,
Expand All @@ -63,12 +69,6 @@ export const ConnectionInformation = ({

const onboarded = project.onboardingStatus.status === 'onboarded';

useEffect(() => {
if (onboarded) {
onConnection();
}
}, [onboarded]);

return (
<Container>
<Title>Connection information</Title>
Expand All @@ -86,28 +86,38 @@ export const ConnectionInformation = ({
<Typography variant='body2'>{sdk}</Typography>
</Info>
</SdkInfo>
<ConnectionStatus>
<Typography fontWeight='bold' variant='body2'>
Connection status
</Typography>
<Typography sx={{ mb: theme.spacing(4) }} variant='body2'>
Waiting for SDK data...
</Typography>
<ConditionallyRender
condition={true}
show={
<WhitePulsingAvatar
sx={{
width: 80,
height: 80,
}}
active={true}
>
<Pending fontSize='large' />
</WhitePulsingAvatar>
}
/>
</ConnectionStatus>
{onboarded ? (
<ConnectionStatus>
<Typography fontWeight='bold' variant='body2'>
Connection status
</Typography>
<Typography sx={{ mb: theme.spacing(4) }} variant='body2'>
Connected
</Typography>
<StyledCheck />
<Typography sx={{ mb: theme.spacing(4) }} variant='body2'>
We received metrics from your application!
</Typography>
</ConnectionStatus>
) : (
<ConnectionStatus>
<Typography fontWeight='bold' variant='body2'>
Connection status
</Typography>
<Typography sx={{ mb: theme.spacing(4) }} variant='body2'>
Waiting for SDK data...
</Typography>
<WhitePulsingAvatar
sx={{
width: 80,
height: 80,
}}
active={true}
>
<Pending fontSize='large' />
</WhitePulsingAvatar>
</ConnectionStatus>
)}
</Container>
);
};
150 changes: 150 additions & 0 deletions frontend/src/component/onboarding/SdkConnected.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import type { FC } from 'react';
import { Box, IconButton, styled, Tooltip, Typography } from '@mui/material';
import { SectionHeader, StepperBox } from './SharedComponents';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import type { SdkName, Sdk } from './sharedTypes';
import copy from 'copy-to-clipboard';
import useToast from 'hooks/useToast';
import CopyIcon from '@mui/icons-material/FileCopy';
import { Stepper } from './Stepper';
import { Badge } from '../common/Badge/Badge';
import { Markdown } from 'component/common/Markdown/Markdown';
import type { CodeComponent } from 'react-markdown/lib/ast-to-react';
import android from './snippets/android.md?raw';
import go from './snippets/go.md?raw';
import javascript from './snippets/javascript.md?raw';
import nodejs from './snippets/nodejs.md?raw';
import python from './snippets/python.md?raw';
import ruby from './snippets/ruby.md?raw';
import svelte from './snippets/svelte.md?raw';
import vue from './snippets/vue.md?raw';
import flutter from './snippets/flutter.md?raw';
import java from './snippets/java.md?raw';
import dotnet from './snippets/dotnet.md?raw';
import php from './snippets/php.md?raw';
import react from './snippets/react.md?raw';
import rust from './snippets/rust.md?raw';
import swift from './snippets/swift.md?raw';

const snippets: Record<SdkName, string> = {
Android: android,
Go: go,
JavaScript: javascript,
'Node.js': nodejs,
Python: python,
Ruby: ruby,
Svelte: svelte,
Vue: vue,
Flutter: flutter,
Java: java,
'.NET': dotnet,
PHP: php,
React: react,
Rust: rust,
Swift: swift,
};

const SpacedContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(5, 8, 2, 8),
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(3),
}));

const StyledCodeBlock = styled('pre')(({ theme }) => ({
backgroundColor: theme.palette.background.elevation1,
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
overflow: 'auto',
fontSize: theme.typography.body2.fontSize,
wordBreak: 'break-all',
whiteSpace: 'pre-wrap',
position: 'relative',
maxHeight: theme.spacing(34),
}));

const CopyToClipboard = styled(Tooltip)(({ theme }) => ({
position: 'absolute',
top: theme.spacing(1),
right: theme.spacing(1),
}));

const CopyBlock: FC<{ title: string; code: string }> = ({ title, code }) => {
const onCopyToClipboard = (data: string) => () => {
copy(data);
setToastData({
type: 'success',
title: 'Copied to clipboard',
});
};
const { setToastData } = useToast();

return (
<StyledCodeBlock>
{code}
<CopyToClipboard title={title} arrow>
<IconButton onClick={onCopyToClipboard(code)} size='small'>
<CopyIcon />
</IconButton>
</CopyToClipboard>
</StyledCodeBlock>
);
};

const ChangeSdk = styled('div')(({ theme }) => ({
display: 'inline-flex',
gap: theme.spacing(3),
padding: theme.spacing(1, 2),
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadius,
marginBottom: theme.spacing(3),
}));

const CodeRenderer: CodeComponent = ({ inline = false, children }) => {
if (!inline && typeof children?.[0] === 'string') {
return <CopyBlock code={children[0]} title='Copy code' />;
}

return <code>{children}</code>;
};

interface ISdkConnectedProps {
sdk: Sdk;
}

export const SdkConnected: FC<ISdkConnectedProps> = ({ sdk }) => {
const { uiConfig } = useUiConfig();

const clientApiUrl = `${uiConfig.unleashUrl}/api/`;
const frontendApiUrl = `${uiConfig.unleashUrl}/api/frontend/`;
const apiUrl = sdk.type === 'client' ? clientApiUrl : frontendApiUrl;

const snippet = (snippets[sdk.name] || '').replace(
'<YOUR_API_URL>',
apiUrl,
);

return (
<SpacedContainer>
<Typography variant='h2'>Connect an SDK to Unleash</Typography>
<StepperBox>
<Stepper active={2} steps={3} />
<Badge color='secondary'>3/3 - Test connection</Badge>
</StepperBox>
<Box sx={{ mt: 2 }}>
<SectionHeader>Production settings</SectionHeader>
<Typography variant='body2'>
In order to validate the connection, we changed some
settings that you might want to revert. We recommend the
following default settings.
</Typography>
<Markdown components={{ code: CodeRenderer }}>
{snippet}
</Markdown>
</Box>
</SpacedContainer>
);
};

// Use a default export for lazy-loading
export default SdkConnected;
Loading

0 comments on commit 4728464

Please sign in to comment.