All files / src/views/Package/ChooseSubmodule ChooseSubmodule.tsx

84% Statements 21/25
50% Branches 6/12
66.66% Functions 4/6
84% Lines 21/25

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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                    1x 3x 3x 3x   3x 3x   3x 3x       3x   3x   3x                   3x   12x                   3x 3x   3x           3x         12x   12x             3x       3x                                                                              
import { ArrowBackIcon, ChevronDownIcon } from "@chakra-ui/icons";
import { Button, Divider, Stack, useDisclosure } from "@chakra-ui/react";
import { FunctionComponent, useCallback, useMemo, useState } from "react";
import { useHistory } from "react-router-dom";
import { SearchModal } from "./SearchModal";
import { QUERY_PARAMS } from "../../../constants/url";
import { useQueryParams } from "../../../hooks/useQueryParams";
import { getPackagePath } from "../../../util/url";
import { usePackageState } from "../PackageState";
 
export const ChooseSubmodule: FunctionComponent = () => {
  const { assembly, name, language, scope, version } = usePackageState();
  const { push } = useHistory();
  const query = useQueryParams();
 
  const allSubmodules = Object.keys(assembly?.data?.submodules ?? {});
  const { isOpen, onOpen, onClose } = useDisclosure();
 
  const currentSubmodule = query.get(QUERY_PARAMS.SUBMODULE);
  const submoduleText = currentSubmodule
    ? `Submodule: ${currentSubmodule}`
    : "Choose Submodule";
 
  const [filter, setFilter] = useState("");
 
  const packageName = scope ? `${scope}/${name}` : name;
 
  const onGoBack = () => {
    push(
      getPackagePath({
        name: packageName,
        version,
        language,
      })
    );
  };
 
  const getUrl = useCallback(
    (submoduleName: string) => {
      return getPackagePath({
        name: packageName,
        version,
        language,
        submodule: submoduleName,
      });
    },
    [language, packageName, version]
  );
 
  const submodules = useMemo(() => {
    let results = allSubmodules;
 
    Iif (filter) {
      results = results.filter((submodule) =>
        submodule.toLowerCase().includes(filter.toLowerCase())
      );
    }
 
    return results.map((submodule) => {
      // Extract submodule displayable name from the submodule by removing package prefix
      // Examples: "aws-cdk-lib.aws_s3" → "aws_s3"
      //           "aws-cdk-lib.interfaces.aws_s3" → "interfaces.aws_s3"
      // Regex /^[^.]+\./ matches package name + first dot, replace with empty string
      const submoduleDisplayName = submodule.replace(/^[^.]+\./, "");
 
      return {
        name: submoduleDisplayName,
        to: getUrl(submoduleDisplayName),
      };
    });
  }, [allSubmodules, filter, getUrl]);
 
  Iif (allSubmodules.length === 0) {
    return null;
  }
 
  return (
    <Stack spacing={4} w="100%">
      {currentSubmodule && (
        <>
          <Button
            borderRadius="none"
            data-testid="choose-submodule-go-back"
            leftIcon={<ArrowBackIcon aria-label="Back to construct root" />}
            onClick={onGoBack}
            title="Back to construct root"
            variant="link"
          >
            {assembly?.data?.name}
          </Button>
          <Divider />
        </>
      )}
      <Button
        borderRadius="none"
        color="blue.500"
        data-testid="choose-submodule-search-trigger"
        flexGrow={1}
        onClick={onOpen}
        rightIcon={<ChevronDownIcon />}
        title="Choose Submodule"
        variant="link"
      >
        {submoduleText}
      </Button>
      <SearchModal
        inputValue={filter}
        isOpen={isOpen}
        onClose={onClose}
        onInputChange={setFilter}
        submodules={submodules}
      />
    </Stack>
  );
};