Skip to content

Commit

Permalink
Move LLD's FeatureFlagEdit to own component
Browse files Browse the repository at this point in the history
  • Loading branch information
ofreyssinet-ledger committed Sep 28, 2022
1 parent 2343208 commit cf73c10
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -1,112 +1,13 @@
import React, { useState, useMemo, useCallback } from "react";
import React, { useCallback } from "react";
import ButtonV2 from "~/renderer/components/Button";
import Button from "~/renderer/components/ButtonV3";
import { useTranslation } from "react-i18next";
import { useFeatureFlags } from "@ledgerhq/live-common/featureFlags/index";
import { Text, Input, Flex, Tag } from "@ledgerhq/react-ui";
import { Feature, FeatureId } from "@ledgerhq/types-live";
import { InputRenderRightContainer } from "@ledgerhq/react-ui/components/form/BaseInput/index";
import { Text, Flex, Tag } from "@ledgerhq/react-ui";
import { FeatureId } from "@ledgerhq/types-live";
import { withV2StyleProvider } from "~/renderer/styles/StyleProvider";
import Box from "~/renderer/components/Box";
import SwitchV2 from "~/renderer/components/Switch";
import Alert from "~/renderer/components/Alert";
import FeatureFlagEdit from "./FeatureFlagEdit";

const OldButton = withV2StyleProvider(ButtonV2);
const Switch = withV2StyleProvider(SwitchV2);

const tryParse = (jsonString: string, fallback: any) => {
try {
return JSON.parse(jsonString);
} catch (e) {
return fallback;
}
};

const FeatureFlagEdit: React.FC<{ flagName: FeatureId; flagValue: Feature }> = props => {
const { flagName, flagValue } = props;
const [error, setError] = useState<Error | unknown | undefined>();
const [inputValue, setInputValue] = useState<string | undefined>(undefined);

const stringifiedFlagValue = useMemo(() => (flagValue ? JSON.stringify(flagValue) : undefined), [
flagValue,
]);
const inputValueDefaulted = inputValue || stringifiedFlagValue;

const { overriddenByEnv, overridesRemote, enabledOverriddenForCurrentLanguage, ...pureValue } = // eslint-disable-line
flagValue || {};

const featureFlagsProvider = useFeatureFlags();

const { t } = useTranslation();

const handleInputChange = useCallback(value => {
setError(undefined);
setInputValue(value);
}, []);

const handleRestoreFeature = useCallback(() => {
setError(undefined);
setInputValue(undefined);
featureFlagsProvider.resetFeature(flagName);
}, [featureFlagsProvider, flagName]);

const handleOverrideFeature = useCallback(() => {
setError(undefined);
try {
// Nb if value is invalid or missing, JSON parse will fail
const newValue = inputValue ? JSON.parse(inputValue) : undefined;
featureFlagsProvider.overrideFeature(flagName, newValue);
} catch (e) {
setError(e);
}
}, [inputValue, flagName, featureFlagsProvider]);

const parsedInput = useMemo(() => {
return inputValueDefaulted ? tryParse(inputValueDefaulted, false) : {};
}, [inputValueDefaulted]);

const isChecked = parsedInput.enabled;

const handleSwitchChange = useCallback(
enabled => {
handleInputChange(JSON.stringify({ ...parsedInput, enabled }));
},
[parsedInput, handleInputChange],
);

return (
<Flex flexDirection="column" pl={6} rowGap={3}>
<Flex flex={1} flexDirection="row" alignItems={"center"} columnGap={2}>
{error ? (
<Alert mb={3} type="warning">
{error.toString()}
</Alert>
) : null}
<Flex flex={1} flexDirection="column">
<Input
value={inputValueDefaulted}
onChange={handleInputChange}
renderRight={() => (
<InputRenderRightContainer>
<Switch isChecked={isChecked} onChange={handleSwitchChange} />
</InputRenderRightContainer>
)}
/>
</Flex>
<Button variant="main" outline onClick={handleRestoreFeature}>
{t("settings.developer.featureFlagsRestore")}
</Button>
<Button disabled={!inputValue} variant="main" onClick={handleOverrideFeature}>
{t("settings.developer.featureFlagsOverride")}
</Button>
</Flex>

<Flex p={3} backgroundColor="neutral.c30">
<Text whiteSpace="pre">{JSON.stringify(pureValue, null, 2)}</Text>
</Flex>
</Flex>
);
};

type Props = {
flagName: FeatureId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React, { useState, useMemo, useCallback } from "react";
import Button from "~/renderer/components/ButtonV3";
import { useTranslation } from "react-i18next";
import { useFeatureFlags } from "@ledgerhq/live-common/featureFlags/index";
import { Text, Input, Flex } from "@ledgerhq/react-ui";
import { Feature, FeatureId } from "@ledgerhq/types-live";
import { InputRenderRightContainer } from "@ledgerhq/react-ui/components/form/BaseInput/index";
import { withV2StyleProvider } from "~/renderer/styles/StyleProvider";
import SwitchV2 from "~/renderer/components/Switch";
import Alert from "~/renderer/components/Alert";

const Switch = withV2StyleProvider(SwitchV2);

const tryParse = (jsonString: string, fallback: any) => {
try {
return JSON.parse(jsonString);
} catch (e) {
return fallback;
}
};

const FeatureFlagEdit: React.FC<{ flagName: FeatureId; flagValue: Feature }> = props => {
const { flagName, flagValue } = props;
const [error, setError] = useState<Error | unknown | undefined>();
const [inputValue, setInputValue] = useState<string | undefined>(undefined);

const stringifiedFlagValue = useMemo(() => (flagValue ? JSON.stringify(flagValue) : undefined), [
flagValue,
]);
const inputValueDefaulted = inputValue || stringifiedFlagValue;

const { overriddenByEnv, overridesRemote, enabledOverriddenForCurrentLanguage, ...pureValue } = // eslint-disable-line
flagValue || {};

const featureFlagsProvider = useFeatureFlags();

const { t } = useTranslation();

const handleInputChange = useCallback(value => {
setError(undefined);
setInputValue(value);
}, []);

const handleRestoreFeature = useCallback(() => {
setError(undefined);
setInputValue(undefined);
featureFlagsProvider.resetFeature(flagName);
}, [featureFlagsProvider, flagName]);

const handleOverrideFeature = useCallback(() => {
setError(undefined);
try {
// Nb if value is invalid or missing, JSON parse will fail
const newValue = inputValue ? JSON.parse(inputValue) : undefined;
featureFlagsProvider.overrideFeature(flagName, newValue);
} catch (e) {
setError(e);
}
}, [inputValue, flagName, featureFlagsProvider]);

const parsedInput = useMemo(() => {
return inputValueDefaulted ? tryParse(inputValueDefaulted, false) : {};
}, [inputValueDefaulted]);

const isChecked = parsedInput.enabled;

const handleSwitchChange = useCallback(
enabled => {
handleInputChange(JSON.stringify({ ...parsedInput, enabled }));
},
[parsedInput, handleInputChange],
);

return (
<Flex flexDirection="column" pl={6} rowGap={3}>
<Flex flex={1} flexDirection="row" alignItems={"center"} columnGap={2}>
{error ? (
<Alert mb={3} type="warning">
{error.toString()}
</Alert>
) : null}
<Flex flex={1} flexDirection="column">
<Input
value={inputValueDefaulted}
onChange={handleInputChange}
renderRight={() => (
<InputRenderRightContainer>
<Switch isChecked={isChecked} onChange={handleSwitchChange} />
</InputRenderRightContainer>
)}
/>
</Flex>
<Button variant="main" outline onClick={handleRestoreFeature}>
{t("settings.developer.featureFlagsRestore")}
</Button>
<Button disabled={!inputValue} variant="main" onClick={handleOverrideFeature}>
{t("settings.developer.featureFlagsOverride")}
</Button>
</Flex>

<Flex p={3} backgroundColor="neutral.c30">
<Text whiteSpace="pre">{JSON.stringify(pureValue, null, 2)}</Text>
</Flex>
</Flex>
);
};

export default FeatureFlagEdit;
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ const OldButton = withV2StyleProvider(ButtonV2);
const FeatureFlagsSettings = () => {
const { t } = useTranslation();
const [visible, setVisible] = useState(false);
const [focusedName, setFocusedName] = useState<string | undefined>("");
const [focusedName, setFocusedName] = useState<string | undefined>();
const [hiddenFlagName, setHiddenFlagName] = useState<string | null>(null);
const [searchInput, setSearchInput] = useState("");

const featureFlags = useMemo(() => {
console.log("recreating FF object");
const featureKeys = Object.keys(defaultFeatures);
if (hiddenFlagName && !featureKeys.includes(hiddenFlagName)) featureKeys.push(hiddenFlagName);
return featureKeys;
Expand Down

0 comments on commit cf73c10

Please sign in to comment.