From e4fcb252d16ba2f03a08f66893541790d799eb30 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Mon, 2 Sep 2024 15:09:00 +0300 Subject: [PATCH] feat: welcome to your project component (#8039) Currently displaying always when flag enabled. ![image](https://github.com/user-attachments/assets/e4c48595-b2d9-4093-af98-360d5856e7d5) --- .../ProjectFeatureToggles.tsx | 18 ++- .../ProjectFeatureTogglesHeader.tsx | 2 +- .../ProjectOnboarding/ProjectOnboarding.tsx | 28 +++++ .../ProjectOnboarding/WelcomeToProject.tsx | 104 ++++++++++++++++++ frontend/src/interfaces/uiConfig.ts | 1 + .../__snapshots__/create-config.test.ts.snap | 1 + src/lib/types/experimental.ts | 7 +- src/server-dev.ts | 1 + 8 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx create mode 100644 frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx index 18d40b3aee..359c2ea06b 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx @@ -39,6 +39,9 @@ import { useProjectFeatureSearchActions, } from './useProjectFeatureSearch'; import { AvatarCell } from './AvatarCell'; +import { ProjectOnboarding } from './ProjectOnboarding/ProjectOnboarding'; +import { useUiFlag } from 'hooks/useUiFlag'; +import { styled } from '@mui/material'; interface IPaginatedProjectFeatureTogglesProps { environments: string[]; @@ -50,9 +53,16 @@ const formatEnvironmentColumnId = (environment: string) => const columnHelper = createColumnHelper(); const getRowId = (row: { name: string }) => row.name; +const Container = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(2), +})); + export const ProjectFeatureToggles = ({ environments, }: IPaginatedProjectFeatureTogglesProps) => { + const onboardingUIEnabled = useUiFlag('onboardingUI'); const projectId = useRequiredPathParam('projectId'); const { @@ -383,7 +393,11 @@ export const ProjectFeatureToggles = ({ const selectedData = useSelectedData(features, rowSelection); return ( - <> + + } + /> - + ); }; diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx index 969c58a5d9..3796c37546 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader.tsx @@ -41,7 +41,7 @@ const StyledResponsiveButton = styled(ResponsiveButton)(() => ({ whiteSpace: 'nowrap', })); -const FlagCreationButton: FC = () => { +export const FlagCreationButton: FC = () => { const [searchParams] = useSearchParams(); const projectId = useRequiredPathParam('projectId'); const showCreateDialog = Boolean(searchParams.get('create')); diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx new file mode 100644 index 0000000000..1f73a70f54 --- /dev/null +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx @@ -0,0 +1,28 @@ +import { styled } from '@mui/material'; +import { WelcomeToProject } from './WelcomeToProject'; + +interface IProjectOnboardingProps { + projectId: string; +} + +const Container = styled('div')(({ theme }) => ({ + display: 'flex', + width: '100%', + gap: theme.spacing(2), +})); + +const SdkExample = styled('div')(({ theme }) => ({ + flexBasis: '30%', + padding: theme.spacing(2), + backgroundColor: theme.palette.background.paper, + borderRadius: theme.shape.borderRadiusLarge, +})); + +export const ProjectOnboarding = ({ projectId }: IProjectOnboardingProps) => { + return ( + + + View SDK example + + ); +}; diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx new file mode 100644 index 0000000000..38d0db02aa --- /dev/null +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx @@ -0,0 +1,104 @@ +import { styled, Typography } from '@mui/material'; +import Add from '@mui/icons-material/Add'; +import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; +import { FlagCreationButton } from '../ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader'; +import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton'; + +interface IWelcomeToProjectProps { + projectId: string; +} + +const Container = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + backgroundColor: theme.palette.background.paper, + flexBasis: '70%', + borderRadius: theme.shape.borderRadiusLarge, +})); + +const TitleBox = styled('div')(({ theme }) => ({ + padding: theme.spacing(2, 7, 2, 7), + borderBottom: '1px solid', + borderColor: theme.palette.divider, +})); + +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 CircleContainer = styled('span')(({ theme }) => ({ + width: '28px', + height: '28px', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.palette.neutral.border, + borderRadius: '50%', +})); + +export const WelcomeToProject = ({ projectId }: IWelcomeToProjectProps) => { + return ( + + + + Welcome to your project + + + Complete the steps below to start working with this project + + + + + + 1 + Create a feature flag + + +
+ The project currently holds no feature toggles. +
+
Create a feature flag to get started.
+
+ +
+ + + 2 + Connect an SDK + + + We have not detected any connected SDKs on this project. + + {}} + maxWidth='200px' + projectId={projectId} + Icon={Add} + disabled={true} + permission={CREATE_FEATURE} + > + Connect SDK + + +
+
+ ); +}; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 0f2e6b6b94..65070583ec 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -89,6 +89,7 @@ export type UiFlags = { newEventSearch?: boolean; archiveProjects?: boolean; projectListImprovements?: boolean; + onboardingUI?: boolean; }; export interface IVersionInfo { diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index ac019f1389..cff03e2432 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -134,6 +134,7 @@ exports[`should create default config 1`] = ` "navigationSidebar": true, "newEventSearch": false, "onboardingMetrics": false, + "onboardingUI": false, "originMiddleware": false, "outdatedSdksBanner": false, "personalAccessTokensKillSwitch": false, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 0bc15eb2d8..83b42a03df 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -61,7 +61,8 @@ export type IFlagKey = | 'projectListImprovements' | 'useProjectReadModel' | 'addonUsageMetrics' - | 'onboardingMetrics'; + | 'onboardingMetrics' + | 'onboardingUI'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -302,6 +303,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_ONBOARDING_METRICS, false, ), + onboardingUI: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_ONBOARDING_UI, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/src/server-dev.ts b/src/server-dev.ts index 11fefe8b6e..be7e586391 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -56,6 +56,7 @@ process.nextTick(async () => { useProjectReadModel: true, addonUsageMetrics: true, onboardingMetrics: true, + onboardingUI: true, }, }, authentication: {