Skip to content

Commit

Permalink
feat: onboarding flow will not break (#8198)
Browse files Browse the repository at this point in the history
1. Now onboarding flow will not break when feature is created
2. Now the bottom table will appear as soon as first feature appears
3. ExistingFlag component was reworked to match the new UX


![image](https://github.com/user-attachments/assets/2022f4ad-246c-47f9-927f-726f72da5e97)
  • Loading branch information
sjaanus authored Sep 20, 2024
1 parent 87b9976 commit ebcdd67
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,12 @@ export const ProjectFeatureToggles = ({

const isPlaceholder = Boolean(initialLoad || (loading && total));

const onboardingStarted =
const isOnboarded =
onboardingUIEnabled && project.onboardingStatus.status === 'onboarded';
const isNotOnboarded =
onboardingUIEnabled && project.onboardingStatus.status !== 'onboarded';
const hasMultipleFeaturesOrNotOnboarding =
(total !== undefined && total > 1) || !onboardingStarted;
const hasFeaturesOrOnboarded =
(total !== undefined && total > 0) || isOnboarded;

const columns = useMemo(
() => [
Expand Down Expand Up @@ -404,7 +406,7 @@ export const ProjectFeatureToggles = ({
return (
<Container>
<ConditionallyRender
condition={onboardingStarted}
condition={isNotOnboarded}
show={
<ProjectOnboarding
projectId={projectId}
Expand All @@ -413,7 +415,7 @@ export const ProjectFeatureToggles = ({
}
/>
<ConditionallyRender
condition={hasMultipleFeaturesOrNotOnboarding}
condition={hasFeaturesOrOnboarded}
show={
<PageContent
disableLoading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { useFlagLimits } from './useFlagLimits';
interface ICreateFeatureDialogProps {
open: boolean;
onClose: () => void;
skipNavigationOnComplete?: boolean;
onSuccess?: () => void;
}

const StyledDialog = styled(Dialog)(({ theme }) => ({
Expand Down Expand Up @@ -78,17 +80,28 @@ const configButtonData = {
export const CreateFeatureDialog = ({
open,
onClose,
onSuccess,
skipNavigationOnComplete,
}: ICreateFeatureDialogProps) => {
if (open) {
// wrap the inner component so that we only fetch data etc
// when the dialog is actually open.
return <CreateFeatureDialogContent open={open} onClose={onClose} />;
return (
<CreateFeatureDialogContent
open={open}
onClose={onClose}
skipNavigationOnComplete={skipNavigationOnComplete}
onSuccess={onSuccess}
/>
);
}
};

const CreateFeatureDialogContent = ({
open,
onClose,
skipNavigationOnComplete,
onSuccess,
}: ICreateFeatureDialogProps) => {
const { setToastData, setToastApiError } = useToast();
const { setShowFeedback } = useContext(UIContext);
Expand Down Expand Up @@ -153,13 +166,17 @@ const CreateFeatureDialogContent = ({
const payload = getTogglePayload();
try {
await createFeatureToggle(project, payload);
navigate(`/projects/${project}/features/${name}`);
if (!skipNavigationOnComplete) {
navigate(`/projects/${project}/features/${name}`);
}
setToastData({
title: 'Flag created successfully',
text: 'Now you can start using your flag.',
confetti: true,
type: 'success',
});
onClose();
onSuccess?.();
setShowFeedback(true);
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ interface IFlagCreationButtonProps {
'text' | 'outlined' | 'contained',
ButtonPropsVariantOverrides
>;
skipNavigationOnComplete?: boolean;
onSuccess?: () => void;
}

const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
Expand All @@ -54,6 +56,8 @@ const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
export const FlagCreationButton = ({
variant,
text = 'New feature flag',
skipNavigationOnComplete,
onSuccess,
}: IFlagCreationButtonProps) => {
const [searchParams] = useSearchParams();
const projectId = useRequiredPathParam('projectId');
Expand All @@ -78,6 +82,8 @@ export const FlagCreationButton = ({
<CreateFeatureDialog
open={openCreateDialog}
onClose={() => setOpenCreateDialog(false)}
skipNavigationOnComplete={skipNavigationOnComplete}
onSuccess={onSuccess}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@ import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { FlagCreationButton } from '../ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader';
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import { Link } from 'react-router-dom';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import useFeatureTypes from 'hooks/api/getters/useFeatureTypes/useFeatureTypes';

interface IWelcomeToProjectProps {
projectId: string;
setConnectSdkOpen: (open: boolean) => void;
}

interface IExistingFlagsProps {
featureId: string;
interface ICreateFlagProps {
projectId: string;
}

Expand Down Expand Up @@ -72,33 +66,29 @@ const MainCircleContainer = styled(NeutralCircleContainer)(({ theme }) => ({
color: theme.palette.background.paper,
}));

const TypeCircleContainer = styled(MainCircleContainer)(({ theme }) => ({
borderRadius: '20%',
}));

const FlagLink = styled(Link)({
fontWeight: 'bold',
textDecoration: 'none',
display: 'flex',
justifyContent: 'center',
});

const ExistingFlagContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(3),
height: '100%',
}));

const FlagCreationContainer = styled('div')(({ theme }) => ({
marginTop: 'auto',
const SuccessContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',

fontSize: theme.spacing(1.75),
fontWeight: 'bold',
backgroundColor: theme.palette.success.light,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(2, 2, 2, 2),
}));

export const WelcomeToProject = ({
projectId,
setConnectSdkOpen,
}: IWelcomeToProjectProps) => {
const { project } = useProjectOverview(projectId);
const { project, refetch } = useProjectOverview(projectId);
const isFirstFlagCreated =
project.onboardingStatus.status === 'first-flag-created';

Expand All @@ -116,12 +106,9 @@ export const WelcomeToProject = ({
<ActionBox>
{project.onboardingStatus.status ===
'first-flag-created' ? (
<ExistingFlag
projectId={projectId}
featureId={project.onboardingStatus.feature}
/>
<ExistingFlag />
) : (
<CreateFlag />
<CreateFlag projectId={projectId} />
)}
</ActionBox>
<ActionBox>
Expand Down Expand Up @@ -151,7 +138,8 @@ export const WelcomeToProject = ({
);
};

const CreateFlag = () => {
const CreateFlag = ({ projectId }: ICreateFlagProps) => {
const { refetch } = useProjectOverview(projectId);
return (
<>
<TitleContainer>
Expand All @@ -162,47 +150,30 @@ const CreateFlag = () => {
<div>The project currently holds no feature flags.</div>
<div>Create one to get started.</div>
</Typography>
<FlagCreationButton text='Create flag' />
<FlagCreationButton
text='Create flag'
skipNavigationOnComplete={true}
onSuccess={refetch}
/>
</>
);
};

const ExistingFlag = ({ featureId, projectId }: IExistingFlagsProps) => {
const { feature } = useFeature(projectId, featureId);
const { featureTypes } = useFeatureTypes();
const IconComponent = getFeatureTypeIcons(feature.type);
const typeName = featureTypes.find(
(featureType) => featureType.id === feature.type,
)?.name;
const typeTitle = `${typeName || feature.type} flag`;

const ExistingFlag = () => {
return (
<ExistingFlagContainer>
<TitleContainer>
<MainCircleContainer></MainCircleContainer>
Create a feature flag
</TitleContainer>
<TitleContainer>
<HtmlTooltip arrow title={typeTitle} describeChild>
<TypeCircleContainer>
<IconComponent />
</TypeCircleContainer>
</HtmlTooltip>
<FlagLink
to={`/projects/${projectId}/features/${feature.name}`}
>
{feature.name}
</FlagLink>
<Link to={`/projects/${projectId}/features/${feature.name}`}>
view flag
</Link>
</TitleContainer>
<FlagCreationContainer>
<FlagCreationButton
variant='outlined'
text='Create a new flag'
/>
</FlagCreationContainer>
<SuccessContainer>
<Typography fontWeight='bold' variant='body2'>
Congratulations! You have created your first flag
</Typography>
<Typography variant='body2'>
Click into the flag below to customize the flag further
</Typography>
</SuccessContainer>
</ExistingFlagContainer>
);
};

0 comments on commit ebcdd67

Please sign in to comment.