github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/hooks/useContainer.tsx (about)

     1  import {
     2    createContext,
     3    ReactNode,
     4    useCallback,
     5    useContext,
     6    useEffect,
     7    useState,
     8  } from "react";
     9  import { noop } from "../utils/func";
    10  import { PanelDefinition } from "../types";
    11  
    12  export type ContainerChildVisibility = "visible" | "hidden";
    13  
    14  type ContainerChildrenVisibility = {
    15    [key in ContainerChildVisibility]: PanelDefinition[];
    16  };
    17  
    18  type IContainerContext = {
    19    childVisibility?: ContainerChildrenVisibility;
    20    showTitle: boolean;
    21    updateChildStatus: (
    22      panel: PanelDefinition,
    23      visibility: ContainerChildVisibility
    24    ) => void;
    25  };
    26  
    27  type ContainerProviderProps = {
    28    children: ReactNode;
    29  };
    30  
    31  const ContainerContext = createContext<IContainerContext | null>({
    32    showTitle: true,
    33    updateChildStatus: noop,
    34  });
    35  
    36  const ContainerProvider = ({ children }: ContainerProviderProps) => {
    37    const [childVisibility, setChildVisibility] =
    38      useState<ContainerChildrenVisibility>({
    39        visible: [],
    40        hidden: [],
    41      });
    42    const [showTitle, setShowTitle] = useState(false);
    43  
    44    const updateChildStatus = useCallback(
    45      (child: PanelDefinition, visibility: ContainerChildVisibility) => {
    46        // Determine if the child is already marked as visible or hidden and update
    47        // state if required to force a re-render of the container's title
    48  
    49        const visibleIndex = childVisibility.visible.findIndex(
    50          (p) => p.name === child.name
    51        );
    52        const hiddenIndex = childVisibility.hidden.findIndex(
    53          (p) => p.name === child.name
    54        );
    55        if (visibility === "visible") {
    56          // If it's already marked as visible, nothing to do
    57          if (visibleIndex > -1 && hiddenIndex === -1) {
    58            return;
    59          }
    60          // Add to visible list if required
    61          const newVisible =
    62            visibleIndex > -1
    63              ? childVisibility.visible
    64              : [...childVisibility.visible, child];
    65          // Remove from hidden list if required
    66          const newHidden =
    67            hiddenIndex > -1
    68              ? [
    69                  ...childVisibility.hidden.slice(0, hiddenIndex),
    70                  ...childVisibility.hidden.slice(
    71                    hiddenIndex + 1,
    72                    childVisibility.hidden.length - 1
    73                  ),
    74                ]
    75              : childVisibility.hidden;
    76          setChildVisibility({
    77            visible: newVisible,
    78            hidden: newHidden,
    79          });
    80        } else if (visibility === "hidden") {
    81          // If it's already marked as hidden, nothing to do
    82          if (hiddenIndex > -1 && visibleIndex === -1) {
    83            return;
    84          }
    85          // Remove from visible list if required
    86          const newVisible =
    87            visibleIndex > -1
    88              ? [
    89                  ...childVisibility.visible.slice(0, visibleIndex),
    90                  ...childVisibility.visible.slice(
    91                    visibleIndex + 1,
    92                    childVisibility.visible.length - 1
    93                  ),
    94                ]
    95              : childVisibility.visible;
    96          // Add to hidden list if required
    97          const newHidden =
    98            hiddenIndex > -1
    99              ? childVisibility.hidden
   100              : [...childVisibility.hidden, child];
   101          setChildVisibility({
   102            visible: newVisible,
   103            hidden: newHidden,
   104          });
   105        }
   106      },
   107      [childVisibility, setChildVisibility]
   108    );
   109  
   110    useEffect(() => {
   111      if (
   112        showTitle &&
   113        childVisibility.hidden.length > 0 &&
   114        childVisibility.visible.length === 0
   115      ) {
   116        setShowTitle(false);
   117      } else if (!showTitle && childVisibility.visible.length > 0) {
   118        setShowTitle(true);
   119      }
   120    }, [childVisibility, showTitle, setShowTitle]);
   121  
   122    return (
   123      <ContainerContext.Provider
   124        value={{
   125          childVisibility,
   126          showTitle,
   127          updateChildStatus,
   128        }}
   129      >
   130        {children}
   131      </ContainerContext.Provider>
   132    );
   133  };
   134  
   135  const useContainer = () => {
   136    const context = useContext(ContainerContext);
   137    if (context === undefined) {
   138      // Normally we'd throw an error here, but we may not be in the context of
   139      // a container, so I'll just send some sensible defaults
   140      return {
   141        showTitle: true,
   142        updateChildStatus: noop,
   143      };
   144    }
   145    return context as IContainerContext;
   146  };
   147  
   148  export { ContainerContext, ContainerProvider, useContainer };