Skip to content

Commit

Permalink
Support feature flags in Custom Views (#3421)
Browse files Browse the repository at this point in the history
* refactor: support feature flags inside custom views

* chore: add changeset

* fix(application-shell): fix types issue

* refactor(application-shell): clean custom view flop-flip provider

* chore: update changeset

Co-authored-by: Nicola Molinari <nicola.molinari@commercetools.com>

---------

Co-authored-by: Nicola Molinari <nicola.molinari@commercetools.com>
  • Loading branch information
CarlosCortizasCT and emmenko committed Feb 28, 2024
1 parent d1f1103 commit 325224e
Show file tree
Hide file tree
Showing 13 changed files with 327 additions and 237 deletions.
7 changes: 7 additions & 0 deletions .changeset/tame-ears-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@commercetools-frontend/application-components': minor
'@commercetools-frontend/application-shell': minor
'@commercetools-frontend/constants': minor
---

Custom Views can consume feature flags (internal usage only).
2 changes: 1 addition & 1 deletion packages/application-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"@commercetools-uikit/utils": "^18.1.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@flopflip/react-broadcast": "13.1.7",
"@flopflip/react-broadcast": "13.2.1",
"@react-hook/latest": "1.0.3",
"@react-hook/resize-observer": "1.2.6",
"@types/history": "^4.7.11",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef } from 'react';
import styled from '@emotion/styled';
import { useAllFeatureToggles } from '@flopflip/react-broadcast';
import { useIntl } from 'react-intl';
import { useShowNotification } from '@commercetools-frontend/actions-global';
import { useApplicationContext } from '@commercetools-frontend/application-shell-connectors';
Expand Down Expand Up @@ -52,6 +53,7 @@ function CustomViewLoader(props: TCustomViewLoaderProps) {
const iFrameElementRef = useRef<HTMLIFrameElement>(null);
const dataLocale = useApplicationContext((context) => context.dataLocale);
const projectKey = useApplicationContext((context) => context.project?.key);
const featureFlags = useAllFeatureToggles();
const iFrameCommunicationChannel = useRef(new MessageChannel());
const showNotification = useShowNotification();
const intl = useIntl();
Expand Down Expand Up @@ -103,6 +105,7 @@ function CustomViewLoader(props: TCustomViewLoaderProps) {
context: {
dataLocale,
projectKey,
featureFlags,
customViewConfig: props.customView,
hostUrl: props.hostUrl || window.location.href,
},
Expand Down
11 changes: 6 additions & 5 deletions packages/application-shell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@
"@commercetools-uikit/text": "^18.1.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@flopflip/combine-adapters": "13.1.7",
"@flopflip/http-adapter": "13.1.7",
"@flopflip/launchdarkly-adapter": "13.1.7",
"@flopflip/react-broadcast": "13.1.7",
"@flopflip/types": "13.1.7",
"@flopflip/combine-adapters": "13.2.1",
"@flopflip/http-adapter": "13.2.1",
"@flopflip/launchdarkly-adapter": "13.2.1",
"@flopflip/memory-adapter": "13.2.1",
"@flopflip/react-broadcast": "13.2.1",
"@flopflip/types": "13.2.1",
"@reduxjs/toolkit": "1.9.5",
"@types/common-tags": "^1.8.2",
"@types/history": "^4.7.11",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ReactNode, useMemo } from 'react';
import memoryAdapter from '@flopflip/memory-adapter';
import { ConfigureFlopFlip } from '@flopflip/react-broadcast';
import { TFlags } from '@flopflip/types';
import { TFetchLoggedInUserQuery } from '../../types/generated/mc';

type TCustomViewFlopFlipProviderProps = {
user?: TFetchLoggedInUserQuery['user'];
flags?: TFlags;
children: ReactNode;
};

function CustomViewFlopFlipProvider(props: TCustomViewFlopFlipProviderProps) {
const adapterArgs = useMemo(
() => ({
user: {
key: props.user?.id,
},
}),
[props.user?.id]
);

return (
<ConfigureFlopFlip
adapter={memoryAdapter}
defaultFlags={props.flags}
adapterArgs={adapterArgs}
>
{props.children}
</ConfigureFlopFlip>
);
}

export default CustomViewFlopFlipProvider;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './custom-view-flop-flip-provider';
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type ReactNode } from 'react';
import { TFlags } from '@flopflip/types';
import { PageUnauthorized } from '@commercetools-frontend/application-components';
import { entryPointUriPathToPermissionKeys } from '@commercetools-frontend/application-config/ssr';
import { ApplicationContextProvider } from '@commercetools-frontend/application-shell-connectors';
Expand All @@ -15,6 +16,7 @@ import { useIsAuthorized } from '@commercetools-frontend/permissions';
import ApplicationLoader from '../application-loader';
import { getBrowserLocale } from '../application-shell-provider/utils';
import ConfigureIntlProvider from '../configure-intl-provider';
import CustomViewFlopFlipProvider from '../custom-view-flop-flip-provider';
import FetchProject from '../fetch-project';
import FetchUser from '../fetch-user';

Expand Down Expand Up @@ -45,6 +47,7 @@ type TCustomViewShellAuthenticatedProps = {
environment: ApplicationWindow['app'];
messages: TAsyncLocaleDataProps['applicationMessages'];
projectKey?: string;
flags?: TFlags;
customViewConfig: CustomViewData;
children: ReactNode;
};
Expand Down Expand Up @@ -95,9 +98,14 @@ function CustomViewShellAuthenticated(
projectDataLocale={props.dataLocale}
environment={props.environment}
>
<CustomViewWithPermissionCheck>
{props.children}
</CustomViewWithPermissionCheck>
<CustomViewFlopFlipProvider
flags={props.flags}
user={user}
>
<CustomViewWithPermissionCheck>
{props.children}
</CustomViewWithPermissionCheck>
</CustomViewFlopFlipProvider>
</ApplicationContextProvider>
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,11 @@ export const customViewsThemesOverrides = {
paddingForMainPageHeader: '0',
paddingForTabularPageHeader: '0',
},
recolouring: {
marginForCustomViewsSelectorAsTabular: '0',
marginForPageContent: `${uiKitDesignTokens.spacing50} 0`,
paddingForDetailPageHeader: `0 0 ${uiKitDesignTokens.spacing40} 0`,
paddingForMainPageHeader: '0',
paddingForTabularPageHeader: '0',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from 'react';
import styled from '@emotion/styled';
import { ApolloClient, type NormalizedCacheObject } from '@apollo/client';
import { useFeatureToggle } from '@flopflip/react-broadcast';
import { TFlags } from '@flopflip/types';
import { Route } from 'react-router-dom';
import {
ModalPageTopBar,
Expand Down Expand Up @@ -48,6 +50,7 @@ declare let window: ApplicationWindow;
type THostContext = {
hostUrl: string;
dataLocale: string;
featureFlags?: TFlags;
customViewConfig: CustomViewData;
projectKey?: string;
};
Expand All @@ -71,11 +74,6 @@ type TCustomViewShellProps = {

const browserLocale = getBrowserLocale(window);

type TStrictModeEnablementProps = {
enableReactStrictMode?: boolean;
children?: ReactNode;
};

type TNotificationsContainerProps = {
notificationsGlobalRef: RefObject<HTMLDivElement>;
notificationsPageRef: RefObject<HTMLDivElement>;
Expand Down Expand Up @@ -108,6 +106,10 @@ const ContentWrapper = styled.div`
padding: ${designTokens.spacing40} 40px;
`;

type TStrictModeEnablementProps = {
enableReactStrictMode?: boolean;
children?: ReactNode;
};
function StrictModeEnablement(props: TStrictModeEnablementProps) {
if (props.enableReactStrictMode) {
return <StrictMode>{props.children}</StrictMode>;
Expand All @@ -116,6 +118,20 @@ function StrictModeEnablement(props: TStrictModeEnablementProps) {
}
}

function CustomViewThemeProvider() {
const theme = useFeatureToggle('mcRecolouring') ? 'recolouring' : 'default';

const customViewThemeOverrides = {
// @ts-ignore
...themesOverrides[theme],
...customViewsThemesOverrides[theme],
};

return (
<ThemeProvider theme={theme} themeOverrides={customViewThemeOverrides} />
);
}

/*
During e2e tests, the Custom View template is built in production mode but still runs on localhost.
Checking for local production mode is necessary for applying the development host URL,
Expand All @@ -124,11 +140,6 @@ function StrictModeEnablement(props: TStrictModeEnablementProps) {
const isLocalProdMode =
process.env.NODE_ENV === 'production' && window.app.env === 'development';

const customViewThemeOverrides = {
...themesOverrides.default,
...customViewsThemesOverrides.default,
};

function CustomViewShell(props: TCustomViewShellProps) {
const [hostContext, setHostContext] = useState<THostContext>();
const iFrameCommunicationPort = useRef<MessagePort>();
Expand Down Expand Up @@ -216,10 +227,6 @@ function CustomViewShell(props: TCustomViewShellProps) {
return (
<>
<GlobalStyles />
<ThemeProvider
theme="default"
themeOverrides={customViewThemeOverrides}
/>
<ApplicationShellProvider
environment={window.app}
applicationMessages={props.applicationMessages}
Expand All @@ -237,8 +244,10 @@ function CustomViewShell(props: TCustomViewShellProps) {
environment={window.app}
messages={props.applicationMessages}
projectKey={hostContext.projectKey}
flags={hostContext.featureFlags}
customViewConfig={hostContext.customViewConfig}
>
<CustomViewThemeProvider />
<PortalsContainer
// @ts-ignore
ref={layoutRefs}
Expand Down
2 changes: 2 additions & 0 deletions packages/constants/src/feature-toggles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
*/

export const CUSTOM_VIEWS = 'enableCustomViews';
export const RECOLOURING = 'mcRecolouring';

export const FLAGS = {
[CUSTOM_VIEWS]: false,
[RECOLOURING]: false,
};
2 changes: 1 addition & 1 deletion playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@commercetools-uikit/spacings": "18.1.0",
"@commercetools-uikit/text": "18.1.0",
"@emotion/react": "^11.11.1",
"@flopflip/react-broadcast": "13.1.7",
"@flopflip/react-broadcast": "13.2.1",
"apollo-link-rest": "^0.9.0",
"graphql": "16.8.1",
"graphql-anywhere": "^4.2.8",
Expand Down
Loading

1 comment on commit 325224e

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for application-kit-custom-views ready!

✅ Preview
https://application-kit-custom-views-32sjst3h6-commercetools.vercel.app

Built with commit 325224e.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.