1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: after onboarding show success box with resources (#8278)

![image](https://github.com/user-attachments/assets/7e60ad54-c750-4e8a-8556-a1735a99a43e)
This commit is contained in:
Jaanus Sellin 2024-09-26 15:40:14 +03:00 committed by GitHub
parent 547e41e566
commit 86e7bbc85d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 183 additions and 12 deletions

View File

@ -19,6 +19,7 @@ import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectO
interface IConnectSDKDialogProps { interface IConnectSDKDialogProps {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
onFinish: () => void;
project: string; project: string;
environments: string[]; environments: string[];
feature?: string; feature?: string;
@ -66,6 +67,7 @@ type OnboardingStage = 'select-sdk' | 'generate-api-key' | 'test-connection';
export const ConnectSdkDialog = ({ export const ConnectSdkDialog = ({
open, open,
onClose, onClose,
onFinish,
environments, environments,
project: projectId, project: projectId,
feature, feature,
@ -76,6 +78,7 @@ export const ConnectSdkDialog = ({
const [environment, setEnvironment] = useState<string | null>(null); const [environment, setEnvironment] = useState<string | null>(null);
const [apiKey, setApiKey] = useState<string | null>(null); const [apiKey, setApiKey] = useState<string | null>(null);
const [stage, setStage] = useState<OnboardingStage>('select-sdk'); const [stage, setStage] = useState<OnboardingStage>('select-sdk');
const { project } = useProjectOverview(projectId, { const { project } = useProjectOverview(projectId, {
refreshInterval: 1000, refreshInterval: 1000,
}); });
@ -166,12 +169,7 @@ export const ConnectSdkDialog = ({
</Button> </Button>
) : null} ) : null}
<Button <Button variant='contained' onClick={onFinish}>
variant='contained'
onClick={() => {
onClose();
}}
>
Next Next
</Button> </Button>
</NextStepSectionSpacedContainer> </NextStepSectionSpacedContainer>

View File

@ -9,7 +9,7 @@ interface IConnectionInformationProps {
sdk: string; sdk: string;
environment: string; environment: string;
} }
export const Container = styled('div')(({ theme }) => ({ const Container = styled('div')(({ theme }) => ({
backgroundColor: theme.palette.background.sidebar, backgroundColor: theme.palette.background.sidebar,
padding: theme.spacing(6, 9, 6, 9), padding: theme.spacing(6, 9, 6, 9),
minWidth: '400px', minWidth: '400px',
@ -18,14 +18,14 @@ export const Container = styled('div')(({ theme }) => ({
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
})); }));
export const Title = styled(Typography)(({ theme }) => ({ const Title = styled(Typography)(({ theme }) => ({
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
fontWeight: theme.typography.fontWeightBold, fontWeight: theme.typography.fontWeightBold,
})); }));
export const SdkInfo = styled('div')(({ theme }) => ({ const SdkInfo = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
padding: theme.spacing(4, 0, 12, 0), padding: theme.spacing(4, 0, 12, 0),
@ -33,13 +33,13 @@ export const SdkInfo = styled('div')(({ theme }) => ({
fontSize: theme.spacing(1), fontSize: theme.spacing(1),
})); }));
export const Info = styled('div')(({ theme }) => ({ const Info = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
gap: theme.spacing(1), gap: theme.spacing(1),
flexDirection: 'column', flexDirection: 'column',
})); }));
export const ConnectionStatus = styled('div')(({ theme }) => ({ const ConnectionStatus = styled('div')(({ theme }) => ({
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
display: 'flex', display: 'flex',
@ -48,7 +48,7 @@ export const ConnectionStatus = styled('div')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody, fontSize: theme.fontSizes.smallBody,
})); }));
export const StyledCheck = styled(Check)(({ theme }) => ({ const StyledCheck = styled(Check)(({ theme }) => ({
color: theme.palette.primary.main, color: theme.palette.primary.main,
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
borderRadius: '50%', borderRadius: '50%',

View File

@ -36,6 +36,7 @@ test('Onboarding for SDK', async () => {
open={true} open={true}
environments={['development', 'production']} environments={['development', 'production']}
feature='featureA' feature='featureA'
onFinish={() => {}}
/>, />,
); );

View File

@ -0,0 +1,153 @@
import { IconButton, styled, Tooltip, Typography } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import Check from '@mui/icons-material/Check';
import People from '@mui/icons-material/People';
import MenuBook from '@mui/icons-material/MenuBook';
import { Link } from 'react-router-dom';
interface IProjectOnboardedProps {
projectId: string;
onClose: () => void;
}
const Container = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.background.paper,
flexBasis: '70%',
borderRadius: theme.shape.borderRadiusLarge,
}));
const TitleRow = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 4, 2, 7),
borderBottom: '1px solid',
borderColor: theme.palette.divider,
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
gap: theme.spacing(3),
alignItems: 'center',
}));
const Actions = styled('div')(({ theme }) => ({
display: 'flex',
flexGrow: 1,
}));
const ActionBox = styled('div')(({ theme }) => ({
flexBasis: '50%',
padding: theme.spacing(3, 2, 6, 8),
display: 'flex',
gap: theme.spacing(3),
flexDirection: 'column',
}));
const TitleContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
gap: theme.spacing(2),
alignItems: 'center',
fontSize: theme.spacing(1.75),
fontWeight: 'bold',
}));
const Title = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
}));
const StyledCheck = styled(Check)(({ theme }) => ({
backgroundColor: theme.palette.primary.main,
color: theme.palette.background.paper,
borderRadius: '50%',
padding: theme.spacing(0.5),
width: '28px',
height: '28px',
}));
const ColoredPeople = styled(People)(({ theme }) => ({
color: theme.palette.primary.main,
}));
const ColoredMenuBook = styled(MenuBook)(({ theme }) => ({
color: theme.palette.primary.main,
}));
export const ProjectOnboarded = ({
projectId,
onClose,
}: IProjectOnboardedProps) => {
return (
<Container>
<TitleRow>
<StyledCheck />
<Title>
<Typography fontWeight='bold'>Setup completed</Typography>
<Typography variant='body2'>Next steps</Typography>
</Title>
<Tooltip title='Close' arrow sx={{ ml: 'auto' }}>
<IconButton onClick={onClose} size='small'>
<CloseIcon />
</IconButton>
</Tooltip>
</TitleRow>
<Actions>
<ActionBox>
<TitleContainer>
Expose your feature flag to users
</TitleContainer>
<Typography>
You can have fine grained control over who is exposed to
your feature flag by leveraging{' '}
<Link
className='unleash-action-button'
to={`https://docs.getunleash.io/reference/activation-strategies`}
target='_blank'
rel='noopener noreferrer'
>
strategies
</Link>
. Visit the feature flag page to start adding strategies
to control exposure.
</Typography>
</ActionBox>
<ActionBox>
<TitleContainer>
<ColoredPeople />
Add members to your project
</TitleContainer>
<Typography>
Unleash is best when collaborating with your co-workers.{' '}
<Link
className='unleash-action-button'
to={`/projects/${projectId}/settings/access`}
>
Add your co-workers to the project
</Link>
.
</Typography>
</ActionBox>
<ActionBox>
<TitleContainer>
<ColoredMenuBook />
Learn about unleash
</TitleContainer>
<Typography>
Take a deep dive through our documentation,{' '}
<Link
className='unleash-action-button'
to={`https://docs.getunleash.io/unleash-academy/foundational`}
target='_blank'
rel='noopener noreferrer'
>
starting with the foundations of Unleash
</Link>
.
</Typography>
</ActionBox>
</Actions>
</Container>
);
};

View File

@ -45,6 +45,7 @@ import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectO
import { ConnectSdkDialog } from '../../../onboarding/dialog/ConnectSdkDialog'; import { ConnectSdkDialog } from '../../../onboarding/dialog/ConnectSdkDialog';
import { ProjectOnboarding } from '../../../onboarding/flow/ProjectOnboarding'; import { ProjectOnboarding } from '../../../onboarding/flow/ProjectOnboarding';
import { useLocalStorageState } from 'hooks/useLocalStorageState'; import { useLocalStorageState } from 'hooks/useLocalStorageState';
import { ProjectOnboarded } from 'component/onboarding/flow/ProjectOnboarded';
interface IPaginatedProjectFeatureTogglesProps { interface IPaginatedProjectFeatureTogglesProps {
environments: string[]; environments: string[];
@ -118,6 +119,9 @@ export const ProjectFeatureToggles = ({
const [onboardingFlow, setOnboardingFlow] = useLocalStorageState< const [onboardingFlow, setOnboardingFlow] = useLocalStorageState<
'visible' | 'closed' 'visible' | 'closed'
>(`onboarding-flow:v1-${projectId}`, 'visible'); >(`onboarding-flow:v1-${projectId}`, 'visible');
const [setupCompletedState, setSetupCompletedState] = useLocalStorageState<
'hide-setup' | 'show-setup'
>(`onboarding-state:v1-${projectId}`, 'hide-setup');
const notOnboarding = const notOnboarding =
!onboardingUIEnabled || !onboardingUIEnabled ||
@ -425,6 +429,17 @@ export const ProjectFeatureToggles = ({
/> />
} }
/> />
<ConditionallyRender
condition={setupCompletedState === 'show-setup'}
show={
<ProjectOnboarded
projectId={projectId}
onClose={() => {
setSetupCompletedState('hide-setup');
}}
/>
}
/>
<ConditionallyRender <ConditionallyRender
condition={showFeaturesTable} condition={showFeaturesTable}
show={ show={
@ -539,6 +554,10 @@ export const ProjectFeatureToggles = ({
onClose={() => { onClose={() => {
setConnectSdkOpen(false); setConnectSdkOpen(false);
}} }}
onFinish={() => {
setConnectSdkOpen(false);
setSetupCompletedState('show-setup');
}}
project={projectId} project={projectId}
environments={environments} environments={environments}
feature={ feature={