Skip to content

Commit

Permalink
Migrated env feature flags to openfeature
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtisassad committed Feb 12, 2024
1 parent fedae9e commit fbe982b
Show file tree
Hide file tree
Showing 34 changed files with 197 additions and 85 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
"@babel/register": "^7.4.0",
"@canvas-js/core": "0.5.0-alpha4",
"@istanbuljs/nyc-config-typescript": "^0.1.3",
"@openfeature/react-sdk": "^0.1.1-experimental",
"@openfeature/web-sdk": "^0.4.12",
"@openzeppelin/contracts": "^2.4.0",
"@openzeppelin/contracts-governance": "npm:@openzeppelin/contracts@^4.3.2",
"@osmonauts/lcd": "^0.10.0",
Expand Down
9 changes: 8 additions & 1 deletion packages/commonwealth/client/scripts/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { OpenFeatureProvider } from '@openfeature/react-sdk';
import { InMemoryProvider, OpenFeature } from '@openfeature/web-sdk';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import useInitApp from 'hooks/useInitApp';
Expand All @@ -6,6 +8,7 @@ import React, { StrictMode } from 'react';
import { RouterProvider } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import { queryClient } from 'state/api/config';
import { featureFlags } from './helpers/feature-flags';
import { CWIcon } from './views/components/component_kit/cw_icons/cw_icon';

const Splash = () => {
Expand All @@ -17,6 +20,8 @@ const Splash = () => {
);
};

OpenFeature.setProvider(new InMemoryProvider(featureFlags));

const App = () => {
const { customDomain, isLoading } = useInitApp();

Expand All @@ -26,7 +31,9 @@ const App = () => {
{isLoading ? (
<Splash />
) : (
<RouterProvider router={router(customDomain)} />
<OpenFeatureProvider>
<RouterProvider router={router(customDomain)} />
</OpenFeatureProvider>
)}
<ToastContainer />
<ReactQueryDevtools />
Expand Down
29 changes: 21 additions & 8 deletions packages/commonwealth/client/scripts/helpers/feature-flags.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
// As of 240205, we are moving away from the use of env vars for feature flags,
// and towards the use of Unleash for all flag management.
// This is our in memory provider setup. It does not automatically ensure your
// feature flag is set on our Unleash instance (May not be available on prod).
//
// See knowledge_base/Feature-Flags.md for info.
// See knowledge_base/Feature-Flags.md for more info.

const buildFlag = (env: string) => {
return {
variants: {
on: true,
off: false,
},
disabled: false,
defaultVariant: env === 'true' ? 'on' : 'off',
};
};

export const featureFlags = {
proposalTemplates: process.env.FLAG_PROPOSAL_TEMPLATES === 'true',
communityHomepage: process.env.FLAG_COMMUNITY_HOMEPAGE === 'true',
newAdminOnboardingEnabled: process.env.FLAG_NEW_ADMIN_ONBOARDING === 'true',
communityStake: process.env.FLAG_COMMUNITY_STAKE === 'true',
newSignInModal: process.env.FLAG_NEW_SIGN_IN_MODAL === 'true',
proposalTemplates: buildFlag(process.env.FLAG_PROPOSAL_TEMPLATES),
communityHomepage: buildFlag(process.env.FLAG_COMMUNITY_HOMEPAGE),
newAdminOnboarding: buildFlag(process.env.FLAG_NEW_ADMIN_ONBOARDING),
communityStake: buildFlag(process.env.FLAG_COMMUNITY_STAKE),
newSignInModal: buildFlag(process.env.FLAG_NEW_SIGN_IN_MODAL),
};

export type AvailableFeatureFlag = keyof typeof featureFlags;
8 changes: 8 additions & 0 deletions packages/commonwealth/client/scripts/hooks/useFlag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useBooleanFlagValue } from '@openfeature/react-sdk';
import { AvailableFeatureFlag } from '../helpers/feature-flags';

export const useFlag = (name: AvailableFeatureFlag) => {
return useBooleanFlagValue(name, false, {
updateOnConfigurationChanged: false,
});
};
7 changes: 4 additions & 3 deletions packages/commonwealth/client/scripts/hooks/useWallets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
} from '../../../shared/analytics/types';
import NewProfilesController from '../controllers/server/newProfiles';
import { setDarkMode } from '../helpers/darkMode';
import { featureFlags } from '../helpers/feature-flags';
import {
getAddressFromWallet,
loginToAxie,
Expand All @@ -50,6 +49,7 @@ import type {
} from '../views/pages/login/types';
import { useBrowserAnalyticsTrack } from './useBrowserAnalyticsTrack';
import useBrowserWindow from './useBrowserWindow';
import { useFlag } from './useFlag';

type IuseWalletProps = {
initialBody?: LoginActiveStep;
Expand All @@ -62,13 +62,14 @@ type IuseWalletProps = {
};

const useWallets = (walletProps: IuseWalletProps) => {
const newSignInModalEnabled = useFlag('newSignInModal');
const [avatarUrl, setAvatarUrl] = useState<string>();
const [address, setAddress] = useState<string>();
const [activeStep, setActiveStep] = useState<LoginActiveStep>();
const [profiles, setProfiles] = useState<Array<ProfileRowProps>>();
const [sidebarType, setSidebarType] = useState<LoginSidebarType>();
const [username, setUsername] = useState<string>(
featureFlags.newSignInModal ? 'Anonymous' : '',
newSignInModalEnabled ? 'Anonymous' : '',
);
const [email, setEmail] = useState<string>();
const [wallets, setWallets] = useState<Array<IWebWallet<any>>>();
Expand Down Expand Up @@ -382,7 +383,7 @@ const useWallets = (walletProps: IuseWalletProps) => {
setSidebarType('newOrReturning');
setActiveStep('selectAccountType');

if (featureFlags.newSignInModal) {
if (newSignInModalEnabled) {
// Create the account with default values
await onCreateNewAccount(
walletToUse,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { featureFlags } from 'helpers/feature-flags';
import { Navigate } from 'navigation/helpers';
import React, { lazy } from 'react';
import { Route } from 'react-router-dom';
import { withLayout } from 'views/Layout';
import { RouteFeatureFlags } from './Router';

const LandingPage = lazy(() => import('views/pages/landing'));
const WhyCommonwealthPage = lazy(() => import('views/pages/why_commonwealth'));
Expand Down Expand Up @@ -102,7 +102,11 @@ const NewProfilePage = lazy(() => import('views/pages/new_profile'));
const EditNewProfilePage = lazy(() => import('views/pages/edit_new_profile'));
const ProfilePageRedirect = lazy(() => import('views/pages/profile_redirect'));

const CommonDomainRoutes = () => [
const CommonDomainRoutes = ({
proposalTemplatesEnabled,
newAdminOnboardingEnabled,
communityHomepageEnabled,
}: RouteFeatureFlags) => [
<Route
key="/"
path="/"
Expand Down Expand Up @@ -342,7 +346,7 @@ const CommonDomainRoutes = () => [
scoped: true,
})}
/>,
...(featureFlags.communityHomepage
...(communityHomepageEnabled
? [
<Route
key="/:scope/feed"
Expand All @@ -363,7 +367,7 @@ const CommonDomainRoutes = () => [
// DISCUSSIONS END

// CONTRACTS
...(featureFlags.proposalTemplates
...(proposalTemplatesEnabled
? [
<Route
key="/:scope/contracts"
Expand Down Expand Up @@ -412,7 +416,7 @@ const CommonDomainRoutes = () => [
/>,

// ADMIN
...(featureFlags.newAdminOnboardingEnabled
...(newAdminOnboardingEnabled
? [
<Route
key="/:scope/manage/profile"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { featureFlags } from 'helpers/feature-flags';
import { Navigate } from 'navigation/helpers';
import React, { lazy } from 'react';
import { Route } from 'react-router-dom';
import { withLayout } from 'views/Layout';
import { RouteFeatureFlags } from './Router';

const SearchPage = lazy(() => import('views/pages/search'));

Expand Down Expand Up @@ -94,7 +94,10 @@ const NewProfilePage = lazy(() => import('views/pages/new_profile'));
const EditNewProfilePage = lazy(() => import('views/pages/edit_new_profile'));
const ProfilePageRedirect = lazy(() => import('views/pages/profile_redirect'));

const CustomDomainRoutes = () => {
const CustomDomainRoutes = ({
proposalTemplatesEnabled,
newAdminOnboardingEnabled,
}: RouteFeatureFlags) => {
return [
<Route
key="/"
Expand Down Expand Up @@ -279,7 +282,7 @@ const CustomDomainRoutes = () => {
// DISCUSSIONS END

// CONTRACTS
...(featureFlags.proposalTemplates
...(proposalTemplatesEnabled
? [
<Route
key="/contracts"
Expand Down Expand Up @@ -321,7 +324,7 @@ const CustomDomainRoutes = () => {
// CONTRACTS END

// ADMIN
...(featureFlags.newAdminOnboardingEnabled
...(newAdminOnboardingEnabled
? [
<Route
key="/manage/profile"
Expand Down
35 changes: 31 additions & 4 deletions packages/commonwealth/client/scripts/navigation/Router.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OpenFeature } from '@openfeature/web-sdk';
import CustomDomainRoutes from 'navigation/CustomDomainRoutes';
import React from 'react';
import {
Expand All @@ -10,12 +11,38 @@ import { PageNotFound } from 'views/pages/404';
import CommonDomainRoutes from './CommonDomainRoutes';
import GeneralRoutes from './GeneralRoutes';

const Router = (customDomain: string) =>
createBrowserRouter(
export type RouteFeatureFlags = {
proposalTemplatesEnabled: boolean;
newAdminOnboardingEnabled: boolean;
communityHomepageEnabled: boolean;
};

const Router = (customDomain: string) => {
const client = OpenFeature.getClient();
const proposalTemplatesEnabled = client.getBooleanValue(
'proposalTemplates',
false,
);
const newAdminOnboardingEnabled = client.getBooleanValue(
'newAdminOnboarding',
false,
);
const communityHomepageEnabled = client.getBooleanValue(
'communityHomepageEnabled',
false,
);
const flags = {
proposalTemplatesEnabled,
newAdminOnboardingEnabled,
communityHomepageEnabled,
};

return createBrowserRouter(
createRoutesFromElements([
...GeneralRoutes(),
...(customDomain ? CustomDomainRoutes() : CommonDomainRoutes()),
...(customDomain ? CustomDomainRoutes(flags) : CommonDomainRoutes(flags)),
<Route path="*" element={withLayout(PageNotFound, {})} />,
])
]),
);
};
export default Router;
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { HelpMenuPopover } from 'views/menus/help_menu';
import { AuthModal } from 'views/modals/AuthModal';
import { FeedbackModal } from 'views/modals/feedback_modal';
import { LoginModal } from 'views/modals/login_modal';
import { featureFlags } from '../helpers/feature-flags';
import { useFlag } from '../hooks/useFlag';
import app from '../state';
import { CWDivider } from './components/component_kit/cw_divider';
import { CWIconButton } from './components/component_kit/cw_icon_button';
Expand All @@ -30,6 +30,7 @@ type SublayoutHeaderProps = {
};

export const SublayoutHeader = ({ onMobile }: SublayoutHeaderProps) => {
const newSignInModalEnabled = useFlag('newSignInModal');
const [isFeedbackModalOpen, setIsFeedbackModalOpen] = useState(false);
const navigate = useCommonNavigate();
const {
Expand Down Expand Up @@ -149,7 +150,7 @@ export const SublayoutHeader = ({ onMobile }: SublayoutHeaderProps) => {
onClose={() => setIsFeedbackModalOpen(false)}
open={isFeedbackModalOpen}
/>
{!featureFlags.newSignInModal ? (
{!newSignInModalEnabled ? (
<CWModal
content={
<LoginModal onModalClose={() => setIsAuthModalOpen(false)} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { featureFlags } from 'helpers/feature-flags';
import useUserActiveAccount from 'hooks/useUserActiveAccount';
import { useCommonNavigate } from 'navigation/helpers';
import React, { useState } from 'react';
Expand All @@ -8,6 +7,7 @@ import { useFetchThreadsQuery } from 'state/api/threads';
import { useFetchTopicsQuery } from 'state/api/topics';
import useAdminOnboardingSliderMutationStore from 'state/ui/adminOnboardingCards';
import Permissions from 'utils/Permissions';
import { useFlag } from '../../../hooks/useFlag';
import { CWText } from '../component_kit/cw_text';
import { CWModal } from '../component_kit/new_designs/CWModal';
import { CWButton } from '../component_kit/new_designs/cw_button';
Expand All @@ -16,6 +16,7 @@ import './AdminOnboardingSlider.scss';
import { DismissModal } from './DismissModal';

export const AdminOnboardingSlider = () => {
const newAdminOnboardingEnabled = useFlag('newAdminOnboarding');
useUserActiveAccount();

const community = app.config.chains.getById(app.activeChainId());
Expand Down Expand Up @@ -78,7 +79,7 @@ export const AdminOnboardingSlider = () => {
threads.length > 0 &&
hasAnyIntegration) ||
!(Permissions.isSiteAdmin() || Permissions.isCommunityAdmin()) ||
!featureFlags.newAdminOnboardingEnabled ||
!newAdminOnboardingEnabled ||
[
...shouldHideAdminCardsTemporary,
...shouldHideAdminCardsPermanently,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { commonProtocol } from '@hicommonwealth/core';
import { featureFlags } from 'helpers/feature-flags';
import useUserLoggedIn from 'hooks/useUserLoggedIn';
import app from 'state';
import {
useFetchCommunityStakeQuery,
useGetBuyPriceQuery,
useGetUserStakeBalanceQuery,
} from 'state/api/communityStake';
import { useFlag } from '../../../hooks/useFlag';

interface UseCommunityStakeProps {
communityId?: string;
Expand All @@ -15,6 +15,7 @@ interface UseCommunityStakeProps {
}

const useCommunityStake = (props: UseCommunityStakeProps = {}) => {
const communityStakeEnabled = useFlag('communityStake');
const {
communityId,
stakeId = commonProtocol.STAKE_ID,
Expand All @@ -31,13 +32,13 @@ const useCommunityStake = (props: UseCommunityStakeProps = {}) => {
useFetchCommunityStakeQuery({
communityId: communityId || activeCommunityId,
stakeId,
apiEnabled: featureFlags.communityStake && !!activeCommunityId,
apiEnabled: communityStakeEnabled && !!activeCommunityId,
});

const stakeData = stakeResponse?.data?.result;
const stakeEnabled = stakeData?.stake_enabled;
const apiEnabled = Boolean(
featureFlags.communityStake &&
communityStakeEnabled &&
stakeEnabled &&
(walletAddress || activeAccountAddress) &&
!!activeCommunityNamespace &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { isWindowMediumSmallInclusive } from 'views/components/component_kit/helpers';
import SessionRevalidationModal from 'views/modals/SessionRevalidationModal';
import { LoginModal } from 'views/modals/login_modal';
import { useFlag } from '../../../../hooks/useFlag';
import { CWModal } from '../../component_kit/new_designs/CWModal';
import './UserDropdown.scss';
import { UserDropdownItem } from './UserDropdownItem';
Expand All @@ -29,7 +30,6 @@ import axios from 'axios';
import { notifyError, notifySuccess } from 'controllers/app/notifications';
import WebWalletController from 'controllers/app/web_wallets';
import { setDarkMode } from 'helpers/darkMode';
import { featureFlags } from 'helpers/feature-flags';
import useAdminOnboardingSliderMutationStore from 'state/ui/adminOnboardingCards';
import useGroupMutationBannerStore from 'state/ui/group';
import { AuthModal } from 'views/modals/AuthModal';
Expand Down Expand Up @@ -58,6 +58,7 @@ const handleLogout = async () => {
};

const UserDropdown = () => {
const newSignInModalEnabled = useFlag('newSignInModal');
const navigate = useCommonNavigate();
const [isOpen, setIsOpen] = useState(false);
const [isDarkModeOn, setIsDarkModeOn] = useState<boolean>(
Expand Down Expand Up @@ -194,7 +195,7 @@ const UserDropdown = () => {
</button>
)}
/>
{!featureFlags.newSignInModal ? (
{!newSignInModalEnabled ? (
<CWModal
content={
<LoginModal onModalClose={() => setIsAuthModalOpen(false)} />
Expand Down
Loading

0 comments on commit fbe982b

Please sign in to comment.