-
Notifications
You must be signed in to change notification settings - Fork 285
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: feature flags context * feature-flags hot key * fix imports
- Loading branch information
1 parent
d6aa76e
commit a2732cd
Showing
5 changed files
with
135 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import React, { createContext, PropsWithChildren, useState } from "react"; | ||
import { useHotkeys } from "react-hotkeys-hook"; | ||
|
||
import { Dialog, DialogContainer, Switch, View } from "@arizeai/components"; | ||
|
||
type FeatureFlag = "evals"; | ||
export type FeatureFlagsContextType = { | ||
featureFlags: Record<FeatureFlag, boolean>; | ||
setFeatureFlags: (featureFlags: Record<FeatureFlag, boolean>) => void; | ||
}; | ||
|
||
export const LOCAL_STORAGE_FEATURE_FLAGS_KEY = "arize-phoenix-feature-flags"; | ||
|
||
const DEFAULT_FEATURE_FLAGS: Record<FeatureFlag, boolean> = { | ||
evals: false, | ||
}; | ||
|
||
function getFeatureFlags(): Record<FeatureFlag, boolean> { | ||
const featureFlagsFromLocalStorage = localStorage.getItem( | ||
LOCAL_STORAGE_FEATURE_FLAGS_KEY | ||
); | ||
if (!featureFlagsFromLocalStorage) { | ||
return DEFAULT_FEATURE_FLAGS; | ||
} | ||
|
||
try { | ||
const parsedFeatureFlags = JSON.parse(featureFlagsFromLocalStorage); | ||
return Object.assign({}, DEFAULT_FEATURE_FLAGS, parsedFeatureFlags); | ||
} catch (e) { | ||
return DEFAULT_FEATURE_FLAGS; | ||
} | ||
} | ||
|
||
export const FeatureFlagsContext = | ||
createContext<FeatureFlagsContextType | null>(null); | ||
|
||
export function useFeatureFlags() { | ||
const context = React.useContext(FeatureFlagsContext); | ||
if (context === null) { | ||
throw new Error( | ||
"useFeatureFlags must be used within a FeatureFlagsProvider" | ||
); | ||
} | ||
return context; | ||
} | ||
|
||
export function useFeatureFlag(featureFlag: FeatureFlag) { | ||
const { featureFlags } = useFeatureFlags(); | ||
return featureFlags[featureFlag]; | ||
} | ||
|
||
export function FeatureFlagsProvider(props: React.PropsWithChildren) { | ||
const [featureFlags, _setFeatureFlags] = useState< | ||
Record<FeatureFlag, boolean> | ||
>(getFeatureFlags()); | ||
const setFeatureFlags = (featureFlags: Record<FeatureFlag, boolean>) => { | ||
localStorage.setItem( | ||
LOCAL_STORAGE_FEATURE_FLAGS_KEY, | ||
JSON.stringify(featureFlags) | ||
); | ||
_setFeatureFlags(featureFlags); | ||
}; | ||
|
||
return ( | ||
<FeatureFlagsContext.Provider value={{ featureFlags, setFeatureFlags }}> | ||
<FeatureFlagsControls>{props.children}</FeatureFlagsControls> | ||
</FeatureFlagsContext.Provider> | ||
); | ||
} | ||
|
||
function FeatureFlagsControls(props: PropsWithChildren) { | ||
const { children } = props; | ||
const { featureFlags, setFeatureFlags } = useFeatureFlags(); | ||
const [showControls, setShowControls] = useState(false); | ||
useHotkeys("ctrl+shift+f", () => setShowControls(true)); | ||
return ( | ||
<> | ||
{children} | ||
<DialogContainer | ||
type="modal" | ||
isDismissable | ||
onDismiss={() => setShowControls(false)} | ||
> | ||
{showControls && ( | ||
<Dialog title="Feature Flags"> | ||
<View height="size-1000" padding="size-100"> | ||
{Object.keys(featureFlags).map((featureFlag) => ( | ||
<Switch | ||
key={featureFlag} | ||
isSelected={featureFlags[featureFlag as FeatureFlag]} | ||
onChange={(isSelected) => | ||
setFeatureFlags({ | ||
...featureFlags, | ||
[featureFlag]: isSelected, | ||
}) | ||
} | ||
> | ||
{featureFlag} | ||
</Switch> | ||
))} | ||
</View> | ||
</Dialog> | ||
)} | ||
</DialogContainer> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters