github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/feature.tsx (about)

     1  // This Features wrapper behaves differently than the one in Go.
     2  // Checking for features that don't exist is *not* an error here.
     3  // This is important because when the React app starts,
     4  // it starts with an empty state and there won't be _any_ feature flags
     5  // until the first engine state comes in over the Websocket.
     6  import { createContext, PropsWithChildren, useContext, useMemo } from "react"
     7  
     8  type featureFlags = { [featureFlag in Flag]?: boolean }
     9  
    10  // Flag names are defined in internal/feature/flags.go
    11  export enum Flag {
    12    Events = "events",
    13    Snapshots = "snapshots",
    14    Labels = "labels",
    15  }
    16  
    17  export default class Features {
    18    private readonly flags: featureFlags
    19  
    20    constructor(flags: object | null | undefined) {
    21      if (flags) {
    22        this.flags = flags as featureFlags
    23      } else {
    24        this.flags = {}
    25      }
    26    }
    27  
    28    public isEnabled(flag: Flag): boolean {
    29      if (this.flags.hasOwnProperty(flag)) {
    30        return this.flags[flag] as boolean
    31      }
    32      return false
    33    }
    34  }
    35  
    36  export const FeaturesContext = createContext<Features>(new Features({}))
    37  FeaturesContext.displayName = "Features"
    38  
    39  export function useFeatures(): Features {
    40    return useContext(FeaturesContext)
    41  }
    42  
    43  // Server-side flags are formatted as a list.
    44  // Many tests uses the {key: value} format.
    45  export function FeaturesProvider(
    46    props: PropsWithChildren<{
    47      featureFlags: Proto.v1alpha1UIFeatureFlag[] | null
    48    }>
    49  ) {
    50    let flagList = props.featureFlags || []
    51    let features = useMemo(() => {
    52      let featureFlags = {} as { [key: string]: boolean }
    53      flagList.forEach((flag) => {
    54        featureFlags[flag.name || ""] = !!flag.value
    55      })
    56      return new Features(featureFlags)
    57    }, [flagList])
    58  
    59    return (
    60      <FeaturesContext.Provider value={features}>
    61        {props.children}
    62      </FeaturesContext.Provider>
    63    )
    64  }
    65  
    66  export let FeaturesTestProvider = FeaturesContext.Provider