All files / react-app/src/components/Opensearch/main/Settings Visibility.tsx

100% Statements 9/9
100% Branches 7/7
100% Functions 6/6
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92                        79x                                                 79x 736x                   28x 28x                                               79x 91x           738x     28x                
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { EyeIcon, EyeOffIcon } from "lucide-react";
 
import * as UI from "@/components";
import { cn } from "@/utils";
 
type Props<T extends UI.OsTableColumn> = {
  list: T[];
  onItemClick: (field: string) => void;
  hiddenColumns: T[];
};
 
export const VisibilityPopover = ({
  list,
  onItemClick,
  hiddenColumns,
}: Props<UI.OsTableColumn>) => {
  return (
    <DropdownMenu.Root>
      <DropdownMenu.Trigger asChild>
        <UI.Button
          variant="outline"
          className="w-full xs:w-fit whitespace-nowrap hover:bg-transparent self-center h-10 flex gap-2"
          data-testid="columns-menu-btn"
        >
          <span className="prose-sm">
            {hiddenColumns.length ? `Columns (${hiddenColumns.length} hidden)` : "Columns"}
          </span>
        </UI.Button>
      </DropdownMenu.Trigger>
      <DropdownMenu.Portal>
        <VisibilityMenu list={list} onItemClick={onItemClick} hiddenColumns={hiddenColumns} />
      </DropdownMenu.Portal>
    </DropdownMenu.Root>
  );
};
 
export const VisiblityItem = <T extends UI.OsTableColumn>(props: T & { onClick: () => void }) => {
  const eyeStyles = cn("flex gap-2", {
    "text-gray-800": !props.hidden,
    "text-gray-500": props.hidden,
  });
 
  return (
    <li>
      <DropdownMenu.Item
        asChild
        onSelect={(e) => {
          e.preventDefault(); // necessary to prevent closing the menu when selecting an item
          props.onClick();
        }}
      >
        <button
          className={cn("flex items-center gap-2 w-full", {
            "text-gray-800": !props.hidden,
            "text-gray-500": props.hidden,
          })}
          type="button"
          aria-label={`${props.label}, toggle visibility, currently ${props.hidden ? "hidden" : "visible"}`}
          aria-live="polite"
        >
          {props.hidden ? (
            <EyeOffIcon className={eyeStyles} aria-hidden focusable={false} />
          ) : (
            <EyeIcon className={eyeStyles} aria-hidden focusable={false} />
          )}
          <span aria-hidden>{props.label}</span>
        </button>
      </DropdownMenu.Item>
    </li>
  );
};
 
export const VisibilityMenu = <T extends UI.OsTableColumn>(props: Props<T>) => (
  <DropdownMenu.Content asChild>
    <ul
      className="flex flex-col gap-2 bg-white p-4 shadow-md rounded-md w-72"
      data-testid="columns-menu"
    >
      {props.list.map((IT) =>
        IT.field ? (
          <VisiblityItem
            key={`vis-${IT.field}`}
            onClick={() => props.onItemClick(IT.field as string)}
            {...IT}
          />
        ) : null,
      )}
    </ul>
  </DropdownMenu.Content>
);