@fortawesome/free-solid-svg-icons#fas JavaScript Examples

The following examples show how to use @fortawesome/free-solid-svg-icons#fas. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.js    From lrc-staking-dapp with MIT License 6 votes vote down vote up
library.add(
  far,
  fas,
  faBookReader,
  faArrowLeft,
  faArrowRight,
  faQuestionCircle,
  faCopy,
  faSignOutAlt,
  faEdit,
  faAngleDown,
  faExternalLinkAlt,
  fab,
  faEthereum,
  faTwitter,
  faDiscord,
  faUnlink,
  faSearch,
  faFortAwesome,
  faExchangeAlt,
  faChartPie,
  faGlobe,
  faDonate,
  faDollarSign,
);
Example #2
Source File: CommitLogCardComponent.js    From gitconvex with Apache License 2.0 6 votes vote down vote up
export default function CommitLogCardComponent(props) {
  library.add(fas);
  const { item, setCommitType } = props;

  return (
    <div
      className="flex p-3 justify-between items-center mx-auto border-b w-full cursor-pointer hover:bg-gray-100"
      key={item.hash}
      onClick={() => {
        setCommitType(item.hash);
      }}
    >
      <div className="block p-2 font-sans font-light text-gray-800">
        <div className="my-2 font-sans text-xl font-light text-blue-600 border-b border-dashed">
          {item.commitTime.split(" ")[0]}
        </div>
        <div className="w-3/4">{item.commitMessage}</div>
        <div className="flex items-center gap-4 my-2 align-middle">
          <div>
            <FontAwesomeIcon
              icon={["fas", "user-alt"]}
              className="text-indigo-500"
            ></FontAwesomeIcon>
          </div>
          <div className="font-semibold font-sans">{item.author}</div>
        </div>
      </div>
      <div className="block">
        <div className="shadow border rounded text-sm p-2 bg-indigo-100 font-mono font-semibold text-indigo-800">
          #{item.hash.substring(0, 7)}
        </div>
        <div className="my-2 shadow border rounded text-sm p-2 bg-yellow-50 font-sans font-semibold">
          {relativeCommitTimeCalculator(item.commitTime)}
        </div>
      </div>
    </div>
  );
}
Example #3
Source File: layout.js    From blog with Apache License 2.0 5 votes vote down vote up
library.add(fab, fas);
Example #4
Source File: FontAwesomeIcon.jsx    From tonic-ui with MIT License 5 votes vote down vote up
library.add(fas);
Example #5
Source File: App.js    From littlelink-server with MIT License 5 votes vote down vote up
library.add(fab, fas, far);
Example #6
Source File: Fontawesome.js    From gatsby-personal-site-template with MIT License 5 votes vote down vote up
library.add(fab, fas)
Example #7
Source File: welcome.test.js    From portal with GNU General Public License v3.0 5 votes vote down vote up
library.add(fas);
Example #8
Source File: provider-item.test.js    From portal with GNU General Public License v3.0 5 votes vote down vote up
library.add(fas);
Example #9
Source File: App.js    From portal with GNU General Public License v3.0 5 votes vote down vote up
library.add(fas);
Example #10
Source File: main.js    From minimal-portfolio with GNU General Public License v3.0 5 votes vote down vote up
library.add(fas)
Example #11
Source File: CompareSelectionHint.js    From gitconvex with Apache License 2.0 5 votes vote down vote up
export default function CompareSelectionHint() {
  library.add(fas);

  const selectionHints = [
    {
      message: (
        <div className="my-10 font-sans text-xl font-semibold">
          Select
          <span className="mx-2 p-1 rounded-lg text-center text-white bg-gray-400">
            Branch Compare
          </span>
          for comparing two branches
        </div>
      ),
      icon: "code-branch",
    },
    {
      message: "",
      icon: "",
    },
    {
      message: (
        <div className="my-10 font-sans text-xl font-semibold">
          Select
          <span className="mx-2 p-1 rounded-lg text-center text-white bg-gray-400">
            Commit Compare
          </span>
          for comparing two selected commits
        </div>
      ),
      icon: "hashtag",
    },
  ];

  return (
    <div className="flex justify-around my-6 mx-auto text-gray-300 gap-10 w-11/12">
      {selectionHints.map((hint, index) => {
        if (hint.message) {
          return (
            <div className="w-1/3 block text-center" key={`hint-${index}`}>
              <div>
                <FontAwesomeIcon
                  icon={["fas", hint.icon]}
                  size="10x"
                ></FontAwesomeIcon>
              </div>
              {hint.message}
            </div>
          );
        } else {
          return (
            <div
              className="block p-1 border-r-4 boreder-dashed"
              key={`hint-${index}`}
            ></div>
          );
        }
      })}
    </div>
  );
}
Example #12
Source File: index.js    From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 5 votes vote down vote up
library.add(fas);
Example #13
Source File: App.js    From viade_es2a with BSD 2-Clause "Simplified" License 5 votes vote down vote up
library.add(fas);
Example #14
Source File: provider-item.test.js    From viade_es2a with BSD 2-Clause "Simplified" License 5 votes vote down vote up
library.add(fas);
Example #15
Source File: welcome.test.js    From viade_es2a with BSD 2-Clause "Simplified" License 5 votes vote down vote up
library.add(fas);
Example #16
Source File: app.jsx    From jitsi-party with MIT License 5 votes vote down vote up
// Allow arbitrary icons to be used without importing them
library.add(fas)
Example #17
Source File: Icon.js    From beautiful-react-ui with MIT License 5 votes vote down vote up
// adding fa dependencies
library.add(fas, fab);
Example #18
Source File: icon.js    From React-Messenger-App with MIT License 5 votes vote down vote up
library.add(fas, fab);
Example #19
Source File: main.js    From FreeTube-Vue with GNU Affero General Public License v3.0 5 votes vote down vote up
library.add(fas)
Example #20
Source File: main.js    From CursedChrome with MIT License 5 votes vote down vote up
library.add(fas)
Example #21
Source File: CommitLogComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function RepositoryCommitLogComponent(props) {
  library.add(fab, fas, far);

  const [commitLogs, setCommitLogs] = useState([]);
  const [isCommitEmpty, setIsCommitEmpty] = useState(false);
  const [skipLimit, setSkipLimit] = useState(0);
  const [totalCommitCount, setTotalCommitCount] = useState(0);
  const [isLoading, setIsLoading] = useState(false);
  const [excessCommit, setExcessCommit] = useState(false);
  const [searchKey, setSearchKey] = useState("");
  const [viewReload, setViewReload] = useState(0);
  const [searchWarning, setSearchWarning] = useState(false);
  const [referenceCommitHash, setReferenceCommitHash] = useState("");

  const searchRef = useRef();
  const searchOptionRef = useRef();

  const debouncedSearch = useRef(
    debounce(commitSearchHandler, 1500, { maxWait: 2000 })
  ).current;

  const searchOptions = ["Commit Hash", "Commit Message", "User"];

  useEffect(() => {
    setIsLoading(true);
    setSearchWarning(false);

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: `
            query {
              gitCommitLogs(repoId: "${props.repoId}", referenceCommit: "") {
                  totalCommits
                  commits{
                      commitTime
                      hash
                      author
                      commitMessage
                      commitFilesCount
                  }  
              }
          }
          `,
      },
    })
      .then((res) => {
        setIsLoading(false);

        if (res.data.data) {
          const { commits, totalCommits } = res.data.data.gitCommitLogs;

          if (totalCommits <= 10) {
            setExcessCommit(false);
          } else {
            setExcessCommit(true);
          }

          setTotalCommitCount(totalCommits);
          if (commits && commits.length > 0) {
            setCommitLogs([...commits]);
            const len = commits.length;
            setReferenceCommitHash(commits[len - 1].hash);
          } else {
            setIsCommitEmpty(true);
          }
        }
      })
      .catch((err) => {
        setIsLoading(false);

        if (err) {
          setIsCommitEmpty(true);
          console.log(err);
        }
      });
  }, [props, viewReload]);

  function fetchCommitLogs() {
    setIsLoading(true);
    setSearchWarning(false);

    let localLimit = 0;
    localLimit = skipLimit + 10;

    setSkipLimit(localLimit);

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: `
          query{
            gitCommitLogs(repoId:"${props.repoId}", referenceCommit: "${referenceCommitHash}"){
                totalCommits
                commits{
                    commitTime
                    hash
                    author
                    commitMessage
                    commitFilesCount
                }  
            }
        }
          `,
      },
    })
      .then((res) => {
        setIsLoading(false);

        if (totalCommitCount - localLimit <= 10) {
          setExcessCommit(false);
        }

        if (res.data.data) {
          const { commits, totalCommits } = res.data.data.gitCommitLogs;
          setTotalCommitCount(totalCommits);
          if (commits && commits.length > 0) {
            setCommitLogs([...commitLogs, ...commits]);

            const len = commits.length;
            setReferenceCommitHash(commits[len - 1].hash);
          } else {
            setIsCommitEmpty(true);
          }
        }
      })
      .catch((err) => {
        setIsLoading(false);

        if (err) {
          setIsCommitEmpty(true);
          console.log(err);
        }
      });
  }

  function fetchCommitFiles(commitHash, arrowTarget) {
    const parentDivId = `commitLogCard-${commitHash}`;
    const targetDivId = `commitFile-${commitHash}`;

    const targetDiv = document.createElement("div");
    targetDiv.id = targetDivId;

    const parentDiv = document.getElementById(parentDivId);
    parentDiv.append(targetDiv);

    const unmountHandler = () => {
      ReactDOM.unmountComponentAtNode(
        document.getElementById("closeBtn-" + commitHash)
      );
      ReactDOM.unmountComponentAtNode(document.getElementById(targetDivId));
      arrowTarget.classList.remove("hidden");
    };

    ReactDOM.render(
      <CommitLogFileCard
        repoId={props.repoId}
        commitHash={commitHash}
        unmountHandler={unmountHandler}
      ></CommitLogFileCard>,
      document.getElementById(targetDivId)
    );

    const closeArrow = (
      <div
        className="text-center mx-auto text-3xl font-sans font-light text-gray-600 items-center align-middle cursor-pointer"
        onClick={(event) => {
          unmountHandler();
        }}
      >
        <FontAwesomeIcon icon={["fas", "angle-up"]}></FontAwesomeIcon>
      </div>
    );

    const closeBtn = document.createElement("div");
    const closeBtnId = "closeBtn-" + commitHash;
    closeBtn.id = closeBtnId;
    parentDiv.append(closeBtn);

    ReactDOM.render(closeArrow, document.getElementById(closeBtnId));
  }

  function commitSearchHandler() {
    setIsLoading(true);
    setTotalCommitCount(0);
    setCommitLogs([]);
    const searchQuery = searchRef.current.value;
    let searchOption = "";

    switch (searchOptionRef.current.value) {
      case "Commit Hash":
        searchOption = "hash";
        break;
      case "Commit Message":
        searchOption = "message";
        break;
      case "User":
        searchOption = "user";
        break;
      default:
        searchOption = "message";
        break;
    }

    if (searchQuery) {
      axios({
        url: globalAPIEndpoint,
        method: "POST",
        data: {
          query: `
            query{
              searchCommitLogs(repoId:"${props.repoId}",searchType:"${searchOption}",searchKey:"${searchQuery}"){
                hash
                author
                commitTime
                commitMessage
                commitFilesCount
              }
            }
          `,
        },
      })
        .then((res) => {
          if (res.data.data) {
            const { searchCommitLogs } = res.data.data;
            if (searchCommitLogs && searchCommitLogs.length > 0) {
              setIsCommitEmpty(false);
              setExcessCommit(false);
              setCommitLogs([...searchCommitLogs]);
              setTotalCommitCount(searchCommitLogs.length);
              setIsLoading(false);
            } else {
              setIsCommitEmpty(true);
              setCommitLogs([]);
              setTotalCommitCount(0);
              setIsLoading(false);
              setSearchWarning(true);
            }
          }
        })
        .catch((err) => {
          console.log(err);
          setIsLoading(false);
          setCommitLogs([]);
        });
    } else {
      setViewReload(viewReload + 1);
      setIsLoading(false);
    }
  }

  function fallBackComponent(message) {
    return (
      <div className="p-6 rounded-md shadow-sm block justify-center mx-auto my-auto w-3/4 h-full text-center text-2xl text-indigo-500">
        <div className="flex w-full h-full mx-auto my-auto">
          <div className="block my-auto mx-auto bg-white w-full p-6 rounded-lg shadow">
            <div className="text-2xl text-center font-sans font-semibold text-indigo-800 border-b-2 border-dashed border-indigo-500 p-1">
              {message}
            </div>
            {searchWarning ? (
              <div className="my-4 mx-auto rounded shadow p-4 text-center font-sans text-yellow-800 font-light bg-yellow-50 border-b-4  border-dashed border-yellow-200 text-md">
                Make sure if you are searching with the right category and the
                right search query
              </div>
            ) : null}
            {isLoading ? (
              <div className="flex mx-auto my-6 text-center justify-center">
                <InfiniteLoader loadAnimation={isLoading}></InfiniteLoader>
              </div>
            ) : null}
          </div>
        </div>
      </div>
    );
  }

  function searchbarComponent() {
    return (
      <div className="my-4 w-full rounded-lg bg-white shadow-inner flex gap-4 justify-between items-center">
        <select
          defaultValue="default-search"
          id="searchOption"
          ref={searchOptionRef}
          className="w-1/4 flex p-4 items-center bg-indigo-400 text-white cursor-pointer rounded-l-md text-lg font-sans font-semibold outline-none"
        >
          <option value="default-search" hidden disabled>
            Search for...
          </option>
          {searchOptions.map((item) => {
            return (
              <option key={item} value={item}>
                {item}
              </option>
            );
          })}
        </select>

        <div className="w-3/4 rounded-r-md">
          <input
            ref={searchRef}
            type="text"
            className="w-5/6 outline-none text-lg font-light font-sans"
            placeholder="What are you looking for?"
            value={searchKey}
            onChange={(event) => {
              setSearchKey(event.target.value);
              debouncedSearch();
            }}
          />
        </div>
        <div
          className="w-20 bg-gray-200 p-3 mx-auto my-auto text-center rounded-r-lg hover:bg-gray-400 cursor-pointer"
          onClick={() => {
            commitSearchHandler();
          }}
        >
          <FontAwesomeIcon
            icon={["fas", "search"]}
            className="text-3xl text-gray-600"
          ></FontAwesomeIcon>
        </div>
      </div>
    );
  }

  return (
    <>
      {searchbarComponent()}
      {(isCommitEmpty || !commitLogs || !totalCommitCount) && !isLoading
        ? fallBackComponent("No Commit Logs found")
        : null}
      {commitLogs &&
        commitLogs.map((commit) => {
          const {
            hash,
            author,
            commitTime,
            commitMessage,
            commitFilesCount,
          } = commit;

          let commitRelativeTime = relativeCommitTimeCalculator(commitTime);
          const formattedCommitTime = format(
            new Date(commitTime),
            "MMMM dd, yyyy"
          );

          return (
            <div
              id={`commitLogCard-${hash}`}
              className="p-6 rounded-lg block shadow-md justify-center mx-auto my-4 bg-white w-full border-b-8 border-indigo-400"
              key={hash}
            >
              <div className="flex justify-between text-indigo-400">
                <div className="text-2xl font-sans mx-auto">
                  <FontAwesomeIcon
                    icon={["fas", "calendar-alt"]}
                  ></FontAwesomeIcon>
                  <span className="border-b-2 border-dashed mx-2">
                    {formattedCommitTime}
                  </span>
                </div>
                <div className="h-auto p-1 border-r"></div>
                <div className="text-2xl font-sans mx-auto">
                  <FontAwesomeIcon
                    icon={["fab", "slack-hash"]}
                  ></FontAwesomeIcon>
                  <span className="border-b-2 border-dashed mx-2">
                    {hash.substring(0, 7)}
                  </span>
                </div>
                <div className="h-auto p-1 border-r"></div>
                <div className="text-2xl font-sans mx-auto">
                  <FontAwesomeIcon
                    icon={["fas", "user-ninja"]}
                  ></FontAwesomeIcon>
                  <span className="border-b-2 border-dashed mx-2 truncate">
                    {author}
                  </span>
                </div>
              </div>

              <div className="font-sans font-semibold text-2xl my-4 text-gray-500 p-3 flex justify-evenly items-center">
                <div className="w-1/8">
                  <FontAwesomeIcon
                    icon={["fas", "code"]}
                    className="text-3xl"
                  ></FontAwesomeIcon>
                </div>
                <div className="w-5/6 mx-3">{commitMessage}</div>
              </div>

              <div className="w-11/12 flex justify-between mx-auto mt-4 font-sans text-xl text-gray-500">
                <div className="w-1/3 flex justify-center my-auto items-center align-middle">
                  <div>
                    <FontAwesomeIcon icon={["far", "clock"]}></FontAwesomeIcon>
                  </div>
                  <div className="mx-2 border-dashed border-b-4">
                    {commitRelativeTime}
                  </div>
                </div>
                <div
                  className="w-1/3 flex justify-around my-auto font-sans text-3xl font-light pt-10 cursor-pointer text-gray-500"
                  onClick={(event) => {
                    if (commitFilesCount) {
                      event.currentTarget.classList.add("hidden");
                      fetchCommitFiles(hash, event.currentTarget);
                    }
                  }}
                >
                  {commitFilesCount ? (
                    <FontAwesomeIcon
                      icon={["fas", "angle-down"]}
                    ></FontAwesomeIcon>
                  ) : (
                    <FontAwesomeIcon
                      icon={["fas", "dot-circle"]}
                      className="text-xl text-gray-200"
                    ></FontAwesomeIcon>
                  )}
                </div>
                <div className="w-1/3 flex justify-center my-auto items-center align-middle">
                  <div>
                    <FontAwesomeIcon
                      icon={["far", "plus-square"]}
                    ></FontAwesomeIcon>
                  </div>
                  <div className="mx-2 border-dashed border-b-4">
                    {commitFilesCount ? (
                      `${commitFilesCount} Files`
                    ) : (
                      <span className="text-gray-500">No Changed Files</span>
                    )}
                  </div>
                </div>
              </div>
            </div>
          );
        })}
      {excessCommit ? (
        <div
          className="fixed flex bottom-0 right-0 w-16 h-16 mx-auto p-6 rounded-full shadow-md text-center bg-indigo-500 text-white text-2xl mb-6 mr-6 cursor-pointer"
          title="Click to load commits"
          onClick={() => {
            if (commitLogs.length > skipLimit) {
              fetchCommitLogs();
            }
          }}
        >
          <FontAwesomeIcon
            icon={["fas", "angle-double-down"]}
          ></FontAwesomeIcon>
        </div>
      ) : null}
      {isLoading && totalCommitCount ? (
        <div className="my-4 rounded-lg p-3 bg-gray-100 text-lg font-semibold font-sans text-gray-700 text-center mx-auto">
          Loading {totalCommitCount - skipLimit} more commits...
          <div className="flex mx-auto my-6 text-center justify-center">
            <InfiniteLoader loadAnimation={isLoading}></InfiniteLoader>
          </div>
        </div>
      ) : null}
      {!isCommitEmpty && commitLogs.length === 0 && isLoading
        ? fallBackComponent("Loading commits...")
        : null}
    </>
  );
}
Example #22
Source File: RepositoryAction.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function RepositoryAction() {
  library.add(fas);

  const { state, dispatch } = useContext(ContextProvider);
  const { presentRepo } = state;
  const [loading, setLoading] = useState(false);
  const [selectedFlag, setSelectedFlag] = useState(false);
  const [defaultRepo, setDefaultRepo] = useState({});
  const [availableRepos, setAvailableRepos] = useState([]);
  const [activeBranch, setActiveBranch] = useState("");
  const [selectedRepoDetails, setSelectedRepoDetails] = useState({
    gitBranchList: "",
    gitCurrentBranch: "",
    gitTotalCommits: 0,
    gitTotalTrackedFiles: 0,
  });
  const [branchError, setBranchError] = useState(false);
  const [toggleSearchSelect, setToggleSearchSelect] = useState(false);
  const [searchBranchValue, setSearchBranchValue] = useState("");
  const [filteredBranchList, setFilteredBranchList] = useState([]);
  const [viewReload, setViewReload] = useState(0);

  const memoizedGitTracker = useMemo(() => {
    if (defaultRepo && defaultRepo.id) {
      return (
        <GitTrackedComponent
          repoId={defaultRepo.id}
          resetBranchError={() => {
            setBranchError(false);
          }}
        ></GitTrackedComponent>
      );
    }
  }, [defaultRepo]);

  useEffect(() => {
    const token = axios.CancelToken;
    const source = token.source();

    function fetchSelectedRepoStatus() {
      const repoId = defaultRepo && defaultRepo.id;

      if (repoId) {
        setLoading(true);
        axios({
          url: globalAPIEndpoint,
          method: "POST",
          headers: {
            "Content-type": "application/json",
          },
          cancelToken: source.token,
          data: {
            query: `
              query 
              {
                  gitRepoStatus(repoId: "${repoId}") {
                    gitBranchList
                    gitCurrentBranch
                    gitTotalCommits
                    gitTotalTrackedFiles 
                  }
              }
            `,
          },
        })
          .then((res) => {
            setLoading(false);
            setSelectedRepoDetails(res.data.data.gitRepoStatus);
            setActiveBranch(res.data.data.gitRepoStatus.gitCurrentBranch);
          })
          .catch((err) => {
            setLoading(false);

            if (err) {
              console.log("API GitStatus error occurred : " + err);
            }
          });
      }
    }

    //Effect dep function
    async function invokeRepoFetchAPI() {
      setLoading(true);
      return await axios({
        url: globalAPIEndpoint,
        method: "POST",
        cancelToken: source.token,
        data: {
          query: `
              query {
                  fetchRepo{
                    repoId
                    repoName
                    repoPath
                  }
              }
          `,
        },
      }).then((res) => {
        setLoading(false);

        const apiResponse = res.data.data.fetchRepo;

        if (apiResponse) {
          const repoContent = apiResponse.repoId.map((entry, index) => {
            return {
              id: apiResponse.repoId[index],
              repoName: apiResponse.repoName[index],
              repoPath: apiResponse.repoPath[index],
            };
          });

          dispatch({
            type: PRESENT_REPO,
            payload: [...repoContent],
          });

          setDefaultRepo(repoContent[0]);
          setAvailableRepos(repoContent);
          return repoContent;
        }
      });
    }

    if (presentRepo && presentRepo[0]) {
      setAvailableRepos(presentRepo[0]);
      fetchSelectedRepoStatus();
    } else {
      invokeRepoFetchAPI();
      fetchSelectedRepoStatus();
    }

    return () => {
      source.cancel();
    };
  }, [defaultRepo, viewReload, presentRepo, dispatch, branchError]);

  function setTrackingBranch(branchName, event) {
    setLoading(true);
    setToggleSearchSelect(!toggleSearchSelect);

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: `
          mutation{
            checkoutBranch(repoId: "${defaultRepo.id}", branchName: "${branchName}")
          }
        `,
      },
    })
      .then((res) => {
        setLoading(false);
        if (res.data.data && !res.data.error) {
          setSearchBranchValue("");
          setFilteredBranchList([]);
          handleScreenEvents();
          setActiveBranch(branchName);
          setViewReload(viewReload + 1);
        }
      })
      .catch((err) => {
        setLoading(false);
        if (err) {
          setBranchError(true);
          event.target.innerText = activeBranch;
        }
      });
  }

  const handleScreenEvents = () => {
    if (!toggleSearchSelect) {
      document
        .getElementById("repository-action")
        .addEventListener("scroll", () => {
          setToggleSearchSelect(false);
        });
    } else {
      document
        .getElementById("repository-action")
        .removeEventListener("scroll", () => {});
    }
  };

  const searchBranchHandler = (e) => {
    const searchBranch = e.target.value;
    setSearchBranchValue(searchBranch);
    if (
      searchBranch !== "" &&
      selectedRepoDetails &&
      selectedRepoDetails.gitBranchList
    ) {
      const { gitBranchList } = selectedRepoDetails;
      const filteredBranches = gitBranchList.filter((branchName) =>
        branchName.toLowerCase().includes(searchBranch)
      );
      setFilteredBranchList(filteredBranches);
    } else {
      setFilteredBranchList([]);
    }
  };

  const cancelSearchBranch = () => {
    setSearchBranchValue("");
    setFilteredBranchList([]);
  };

  function activeRepoPane() {
    return (
      <div className="flex items-center justify-around my-4 mx-auto align-middle">
        <div className="flex items-center">
          <div className="font-sans font-semibold my-1 text-gray-900">
            Choose saved repository
          </div>
          <select
            className="cursor-pointer rounded-lg border-dashed border-b-2 font-sans font-light text-xl mx-4 outline-none p-2 shadow bg-green-50 text-green-700 border-green-400"
            defaultValue={"checked"}
            onClick={() => {
              setBranchError(false);
            }}
            onChange={(event) => {
              if (event.currentTarget.value !== defaultRepo.repoName) {
                setActiveBranch("...");
                setSelectedRepoDetails({
                  ...selectedRepoDetails,
                  gitCurrentBranch: "",
                  gitBranchList: ["..."],
                });
              }
              setSelectedFlag(true);
              availableRepos.length &&
                availableRepos.forEach((elm) => {
                  if (event.target.value === elm.repoName) {
                    setDefaultRepo(elm);
                    dispatch({ type: GIT_GLOBAL_REPOID, payload: elm.id });
                  }
                });
            }}
          >
            <option defaultChecked value="checked" hidden disabled>
              Select a repo
            </option>
            {availableRepos.length &&
              availableRepos.map((entry) => {
                return (
                  <option value={entry.repoName} key={entry.repoName}>
                    {entry.repoName}
                  </option>
                );
              })}
          </select>
        </div>
        {selectedFlag ? (
          <div className="flex items-center gap-4">
            <div className="font-sans font-semibold my-1 text-gray-900">
              Branch
            </div>
            <div className="flex-1 flex flex-col justify-center">
              <div
                className="flex-auto cursor-pointer inline-flex items-center justify-center px-4 py-2 shadow-md bg-indigo-50 border-indigo-400 text-indigo-700 border-dashed border-b-2 truncate"
                onClick={(e) => {
                  let target = e.currentTarget;
                  if (!toggleSearchSelect) {
                    target.style.width = "17.5rem";
                  } else {
                    target.style.width = "auto";
                  }
                  setToggleSearchSelect(!toggleSearchSelect);
                  handleScreenEvents();
                }}
              >
                <span className="mr-2">{activeBranch}</span>
                <FontAwesomeIcon
                  className="text-sm m-1"
                  icon={["fas", "chevron-down"]}
                ></FontAwesomeIcon>
              </div>
              {toggleSearchSelect ? (
                <div className="flex-auto flex flex-row justify-center">
                  <div className="bg-white border-indigo-300 text-indigo-700 px-4 py-4 shadow-md rounded-md z-20 absolute">
                    <div className="flex flex-row mt-1 mb-3">
                      <div className="b-1 text-center px-2 py-1 text-white bg-blue-400 rounded-l-md">
                        <FontAwesomeIcon
                          icon={["fas", "search"]}
                        ></FontAwesomeIcon>
                      </div>
                      <input
                        id="branchSearchInput"
                        type="text"
                        placeholder="Search..."
                        className="px-2 py-1 bg-indigo-100 text-indigo-700 shadow-sm rounded-sm focus:outline-none outline-none"
                        onChange={searchBranchHandler}
                        value={searchBranchValue}
                      ></input>
                      <div
                        className="b-1 text-center px-2 py-1 text-white cursor-pointer bg-red-400 rounded-r-md"
                        onClick={cancelSearchBranch}
                      >
                        <FontAwesomeIcon
                          icon={["fas", "times"]}
                        ></FontAwesomeIcon>
                      </div>
                    </div>
                    {availableBranch()}
                  </div>
                </div>
              ) : null}
            </div>
          </div>
        ) : null}
      </div>
    );
  }

  function getTopPaneComponent(icon, value) {
    return (
      <>
        <div className="border-indigo-400 border-dashed border-b-2 flex justify-between font-sans text-lg mx-2 p-2 text-gray-600">
          <div className="mx-2">
            <FontAwesomeIcon icon={["fas", icon]}></FontAwesomeIcon>
          </div>
          <div className="mx-2">{value}</div>
        </div>
      </>
    );
  }

  const branchCardComponent = (branch) => {
    return (
      <div
        key={branch}
        value={branch}
        className="cursor-pointer text-sm border-b border-dotted p-2 mt-1 mb-1"
        onClick={(event) => {
          event.persist();
          setActiveBranch("...");
          setTrackingBranch(event.target.innerText, event);
        }}
      >
        {branch}
      </div>
    );
  };

  function availableBranch() {
    if (selectedRepoDetails && selectedRepoDetails.gitBranchList) {
      const { gitBranchList } = selectedRepoDetails;
      if (searchBranchValue !== "") {
        if (filteredBranchList && filteredBranchList.length > 0) {
          return filteredBranchList.map((branch) => {
            if (branch !== "NO_BRANCH") {
              return branchCardComponent(branch);
            }
            return null;
          });
        } else {
          return (
            <div className="text-center font-sans font-light text-base my-2 text-indigo-800 border-b border-dotted">
              <span className="mx-1 font-semibold border-b border-dashed">
                {searchBranchValue}
              </span>
              branch is not available!
            </div>
          );
        }
      } else {
        return gitBranchList.map((branch) => {
          if (branch !== "NO_BRANCH") {
            return branchCardComponent(branch);
          }
          return null;
        });
      }
    }
  }

  return (
    <div
      className="block justify-center mx-auto overflow-x-hidden w-full"
      id="repository-action"
    >
      {availableRepos ? (
        <div>
          <div className="w-11/12 border-gray-200 rounded border my-6 mx-auto shadow">
            {activeRepoPane()}
            {selectedRepoDetails && selectedFlag ? (
              <div className="my-auto flex justify-around p-3 mx-auto">
                {loading ? (
                  <div className="text-center font-sans font-semibold text-gray-600 text-xl">
                    Loading repo details...
                  </div>
                ) : (
                  <>
                    {getTopPaneComponent(
                      "code-branch",
                      selectedRepoDetails.gitBranchList &&
                        selectedRepoDetails.gitBranchList.length > 0 &&
                        !selectedRepoDetails.gitBranchList[0].match(
                          /NO_BRANCH/gi
                        ) ? (
                        <>
                          {selectedRepoDetails.gitBranchList.length === 1
                            ? 1 + " branch"
                            : selectedRepoDetails.gitBranchList.length +
                              " branches"}
                        </>
                      ) : (
                        "No Branches"
                      )
                    )}
                    {getTopPaneComponent(
                      "sort-amount-up",
                      selectedRepoDetails.gitTotalCommits + " Commits"
                    )}
                    {getTopPaneComponent(
                      "archive",
                      selectedRepoDetails.gitTotalTrackedFiles +
                        " Tracked Files"
                    )}
                  </>
                )}
              </div>
            ) : null}
          </div>
          {!selectedFlag ? (
            <>
              <div className="text-center mx-auto font-sans p-10 text-2xl bg-yellow-100 w-11/12 font-light rounded-lg shadow border-dashed border-2 border-yellow-200">
                Select a configured repo from the dropdown to perform git
                related operations
              </div>
              <div className="w-3/4 border-gray-100 rounded-lg border-2 block my-20 mx-auto p-6">
                <div>
                  <FontAwesomeIcon
                    icon={["fas", "mouse-pointer"]}
                    className="flex font-bold h-full text-6xl m-auto text-center text-gray-300 w-full"
                  ></FontAwesomeIcon>
                </div>
                <div className="block my-4 mx-auto text-center text-gray-200 xl:text-6xl lg:text-3xl md:text-2xl">
                  No repositories selected
                </div>
              </div>
            </>
          ) : null}
          <div>
            {branchError ? (
              <div className="bg-red-100 rounded font-sans my-2 mx-auto p-2 text-center text-red-700">
                Branch switching failed.Commit your changes and try again
              </div>
            ) : null}
            {selectedRepoDetails && selectedFlag && defaultRepo.id
              ? memoizedGitTracker
              : null}
          </div>
        </div>
      ) : null}
    </div>
  );
}
Example #23
Source File: RepositoryDetails.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function RepositoryDetails(props) {
  library.add(fab, fas);
  const [gitRepoStatus, setGitRepoStatus] = useState({});
  const [repoFetchFailed, setRepoFetchFailed] = useState(false);
  const [repoIdState, setRepoIdState] = useState("");
  const [showCommitLogs, setShowCommitLogs] = useState(false);
  const [isMultiRemote, setIsMultiRemote] = useState(false);
  const [multiRemoteCount, setMultiRemoteCount] = useState(0);
  const [backdropToggle, setBackdropToggle] = useState(false);
  const [viewReload, setViewReload] = useState(false);
  const [codeViewToggle, setCodeViewToggle] = useState(false);
  const [selectedBranch, setSelectedBranch] = useState("");
  const [currentBranch, setCurrentBranch] = useState("");
  const [action, setAction] = useState("");
  const [loading, setLoading] = useState(false);

  const closeBackdrop = (toggle) => {
    setBackdropToggle(!toggle);
  };

  const showCommitLogsView = () => {
    setShowCommitLogs(true);
  };

  const actionTrigger = (actionType) => {
    setAction(actionType);
    setBackdropToggle(true);
  };

  const memoizedFolderExplorer = useMemo(() => {
    return (
      <FileExplorerComponent repoIdState={repoIdState}></FileExplorerComponent>
    );
  }, [repoIdState]);

  const memoizedCommitLogComponent = useMemo(() => {
    return (
      <>
        <CommitLogComponent repoId={repoIdState}></CommitLogComponent>
      </>
    );
  }, [repoIdState]);

  const memoizedFetchRemoteComponent = useMemo(() => {
    return (
      <FetchPullActionComponent
        repoId={repoIdState}
        actionType="fetch"
      ></FetchPullActionComponent>
    );
  }, [repoIdState]);

  const memoizedPullRemoteComponent = useMemo(() => {
    return (
      <FetchPullActionComponent
        repoId={repoIdState}
        actionType="pull"
      ></FetchPullActionComponent>
    );
  }, [repoIdState]);

  const memoizedSwitchBranchComponent = useMemo(() => {
    return (
      <SwitchBranchComponent
        repoId={repoIdState}
        branchName={selectedBranch}
        closeBackdrop={closeBackdrop}
        switchReloadView={() => {
          setViewReload(true);
        }}
      ></SwitchBranchComponent>
    );
  }, [repoIdState, selectedBranch]);

  const memoizedBranchListComponent = useMemo(() => {
    return (
      <BranchListComponent
        repoId={repoIdState}
        currentBranch={currentBranch}
      ></BranchListComponent>
    );
  }, [repoIdState, currentBranch]);

  const memoizedAddRemoteRepoComponent = useMemo(() => {
    return (
      <AddRemoteRepoComponent repoId={repoIdState}></AddRemoteRepoComponent>
    );
  }, [repoIdState]);

  useEffect(() => {
    setViewReload(false);
    setCodeViewToggle(false);
    setLoading(true);
    const endpointURL = globalAPIEndpoint;

    if (props.parentProps.location) {
      const repoId = props.parentProps.location.pathname.split(
        "/repository/"
      )[1];

      setRepoIdState(repoId);

      axios({
        url: endpointURL,
        method: "POST",
        headers: {
          "Content-type": "application/json",
        },
        data: {
          query: `
            query
            {
                gitRepoStatus(repoId:"${repoId}"){
                  gitRemoteData
                  gitRemoteHost
                  gitRepoName
                  gitBranchList
                  gitCurrentBranch
                  gitTotalCommits
                  gitLatestCommit
                  gitTotalTrackedFiles    
                }
            }
          `,
        },
      })
        .then((res) => {
          setLoading(false);
          if (res.data && res.data.data && !res.data.error) {
            const localRepoStatus = res.data.data.gitRepoStatus;
            let gitRemoteLocal = localRepoStatus.gitRemoteData;
            setCurrentBranch(localRepoStatus.gitCurrentBranch);
            if (gitRemoteLocal.includes("||")) {
              setIsMultiRemote(true);
              localRepoStatus.gitRemoteData = gitRemoteLocal.split("||")[0];
              setIsMultiRemote(true);
              setMultiRemoteCount(gitRemoteLocal.split("||").length);
            } else {
              setIsMultiRemote(false);
              setMultiRemoteCount(0);
            }
            setGitRepoStatus(localRepoStatus);
          } else {
            setRepoFetchFailed(true);
          }
        })
        .catch((err) => {
          setLoading(false);

          if (err) {
            console.log("API GitStatus error occurred : " + err);
            setRepoFetchFailed(true);
          }
        });
    }
  }, [props.parentProps, viewReload]);

  let {
    gitRemoteData,
    gitRepoName,
    gitBranchList,
    gitCurrentBranch,
    gitRemoteHost,
    gitTotalCommits,
    gitLatestCommit,
  } = gitRepoStatus;

  const switchBranchHandler = (branchName) => {
    setBackdropToggle(true);
    setAction("switchbranch");
    setSelectedBranch(branchName);
  };

  const actionComponentPicker = () => {
    switch (action) {
      case "fetch":
        return memoizedFetchRemoteComponent;
      case "pull":
        return memoizedPullRemoteComponent;
      case "addRemoteRepo":
        return memoizedAddRemoteRepoComponent;
      case "addBranch":
        return <AddBranchComponent repoId={repoIdState}></AddBranchComponent>;
      case "switchbranch":
        return memoizedSwitchBranchComponent;
      case "listBranch":
        return memoizedBranchListComponent;
      default:
        return null;
    }
  };

  return (
    <>
      {loading ? (
        <LoadingHOC
          message="Fetching repo details..."
          loading={loading}
        ></LoadingHOC>
      ) : null}
      {showCommitLogs ? (
        <>
          <div
            className="fixed w-full h-full top-0 left-0 right-0 flex overflow-auto"
            id="commit-log__backdrop"
            style={{ background: "rgba(0,0,0,0.5)", zIndex: 99 }}
            onClick={(event) => {
              if (event.target.id === "commit-log__backdrop") {
                setShowCommitLogs(false);
              }
            }}
          >
            <div
              id="commit-log__cards"
              className="w-full xl:w-3/4 lg:w-5/6 md:w-11/12 sm:w-11/12 h-full block mx-auto my-auto mt-10 mb-10"
            >
              {memoizedCommitLogComponent}
            </div>
            <div
              className="w-14 h-14 mr-5 mt-6 rounded-full bg-red-500 text-white flex justify-center items-center shadow cursor-pointer fixed right-0 top-0"
              onClick={() => {
                setShowCommitLogs(false);
              }}
            >
              <FontAwesomeIcon
                className="flex text-center text-3xl my-auto"
                icon={["fas", "times"]}
              ></FontAwesomeIcon>
            </div>
          </div>
        </>
      ) : null}
      {backdropToggle || codeViewToggle ? (
        <div
          className="flex h-full overflow-auto fixed inset-x-0 top-0 w-full z-40"
          id="repo-backdrop"
          style={{ background: "rgba(0,0,0,0.7)", zIndex: "99" }}
          onClick={(event) => {
            if (event.target.id === "repo-backdrop") {
              setBackdropToggle(false);
              setAction("");
            }
          }}
        >
          <>{action ? actionComponentPicker() : null}</>
          <div
            className="w-14 h-14 mr-5 mt-6 rounded-full bg-red-500 text-white flex justify-center items-center shadow cursor-pointer fixed top-0 right-0"
            onClick={() => {
              setBackdropToggle(false);
              setCodeViewToggle(false);
              setViewReload(true);
              setAction("");
            }}
          >
            <FontAwesomeIcon
              className="flex text-center text-3xl my-auto"
              icon={["fas", "times"]}
            ></FontAwesomeIcon>
          </div>
        </div>
      ) : null}
      <>
        {!loading && gitRepoStatus && !repoFetchFailed ? (
          <div className="overflow-auto rounded-lg justify-evenly h-full mx-auto p-6 w-full">
            <div className="flex px-3 py-2">
              {gitRepoStatus ? (
                <RepoInfoComponent
                  gitRepoName={gitRepoName}
                  gitCurrentBranch={gitCurrentBranch}
                ></RepoInfoComponent>
              ) : null}
            </div>
            <div className="w-full">
              <div className="xl:w-11/12 lg:w-full w-full xl:flex lg:block md:block sm:block my-4 mx-auto justify-around">
                {gitRepoStatus ? (
                  <>
                    <RepoLeftPaneComponent
                      received={true}
                      actionTrigger={actionTrigger}
                      showCommitLogsView={showCommitLogsView}
                      gitRemoteHost={gitRemoteHost}
                      gitRemoteData={gitRemoteData}
                      isMultiRemote={isMultiRemote}
                      multiRemoteCount={multiRemoteCount}
                    ></RepoLeftPaneComponent>
                    <RepoRightPaneComponent
                      received={true}
                      switchBranchHandler={switchBranchHandler}
                      actionTrigger={actionTrigger}
                      gitBranchList={gitBranchList}
                      gitCurrentBranch={gitCurrentBranch}
                      gitLatestCommit={gitLatestCommit}
                      gitTotalCommits={gitTotalCommits}
                    ></RepoRightPaneComponent>
                  </>
                ) : null}
              </div>
            </div>

            {!loading && gitRepoStatus && repoIdState
              ? memoizedFolderExplorer
              : null}
          </div>
        ) : !loading ? (
          <div className="w-full h-full mx-auto text-center flex justify-center items-center">
            <div className="block mx-auto w-11/12">
              <div className="rounded-lg shadow border-2 border-dashed border-pink-400 text-red-300 text-3xl font-sans font-semibold p-4">
                Unable to fetch repo details
              </div>
              <div className="font-sans font-light text-xl my-4 text-gray-600">
                Please check if the repo is a valid git repo. If it is not a git
                repo, delete the entry from "Settings" menu and add the repo
                again by checking "Initialize a new repo" option
              </div>
              <div className="my-10 text-gray-200">
                <FontAwesomeIcon
                  icon={["fas", "unlink"]}
                  size="10x"
                ></FontAwesomeIcon>
              </div>
            </div>
          </div>
        ) : null}
      </>
    </>
  );
}
Example #24
Source File: RepoLeftPaneComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function RepoLeftPaneComponent(props) {
  library.add(fab, fas);

  let {
    gitRemoteHost,
    gitRemoteData,
    isMultiRemote,
    multiRemoteCount,
    showCommitLogsView,
    actionTrigger,
  } = props;

  useEffect(() => {}, [props]);

  const getRemoteLogo = () => {
    let remoteLogo = "";
    if (gitRemoteHost.match(/github/i)) {
      remoteLogo = (
        <FontAwesomeIcon
          icon={["fab", "github"]}
          className="text-4xl text-center text-pink-500"
        ></FontAwesomeIcon>
      );
    } else if (gitRemoteHost.match(/gitlab/i)) {
      remoteLogo = (
        <FontAwesomeIcon
          icon={["fab", "gitlab"]}
          className="text-4xl text-center text-pink-400"
        ></FontAwesomeIcon>
      );
    } else if (gitRemoteHost.match(/bitbucket/i)) {
      remoteLogo = (
        <FontAwesomeIcon
          icon={["fab", "bitbucket"]}
          className="text-4xl text-center text-pink-400"
        ></FontAwesomeIcon>
      );
    } else if (gitRemoteHost.match(/codecommit/i)) {
      remoteLogo = (
        <FontAwesomeIcon
          icon={["fab", "aws"]}
          className="text-4xl text-center text-pink-400"
        ></FontAwesomeIcon>
      );
    } else {
      remoteLogo = (
        <FontAwesomeIcon
          icon={["fab", "git-square"]}
          className="text-4xl text-center text-pink-400"
        ></FontAwesomeIcon>
      );
    }

    return remoteLogo;
  };

  const remoteUrl = () => {
    let remoteData = "";
    if (gitRemoteData) {
      if (gitRemoteData.match(/(^https)/gi)) {
        remoteData = (
          <a href={gitRemoteData} target="_blank" rel="noopener noreferrer">
            {gitRemoteData}
          </a>
        );
      } else {
        remoteData = <>{gitRemoteData}</>;
      }
    } else {
      remoteData = " ";
    }
    return remoteData;
  };

  return (
    <>
      {props.received ? (
        <div className="border-gray-300 rounded-md border-dotted border-2 block my-6 mx-auto p-1 shadow-sm w-11/12 xl:w-1/2 lg:w-3/4 md:w-11/12 sm:w-11/12">
          <div className="block mx-auto my-6">
            <div className="flex items-center justify-evenly">
              <div className="text-lg text-gray-600 w-1/4">Remote Host</div>
              <div className="flex justify-around items-center align-middle w-1/2">
                <div className="w-3/4 shadow rounded-md border-dashed border cursor-pointer flex items-center justify-center my-auto p-4 align-middle">
                  {gitRemoteHost ? (
                    <div className="mx-2">{getRemoteLogo()}</div>
                  ) : null}
                  <div
                    className={`${
                      gitRemoteHost !== "No Remote Host Available"
                        ? "text-xl border-gray-300 border-dashed border-b text-center text-gray-800 w-3/4"
                        : "text-base font-sans font-light text-gray-600 text-center"
                    }`}
                  >
                    {gitRemoteHost}
                  </div>
                </div>
                <div className="w-1/4">
                  <div
                    id="addRemote"
                    className="rounded-full cursor-pointer items-center h-10 text-2xl mx-auto shadow text-center text-white align-middle w-10 bg-indigo-400 hover:bg-indigo-500"
                    onMouseEnter={(event) => {
                      let popUp = document.createElement("div");
                      popUp.className =
                        "text-gray-600 bg-white border-gray-300 p-2 rounded w-40 text-center border text-sm mt-2 mb-2 -ml-10 absolute";
                      popUp.innerHTML = `Click here to configure remote repo`;
                      event.currentTarget.insertAdjacentElement(
                        "afterend",
                        popUp
                      );
                    }}
                    onMouseLeave={(event) => {
                      if (event.currentTarget.parentNode.children[1]) {
                        event.currentTarget.parentNode.children[1].remove();
                      }
                    }}
                    onClick={() => {
                      actionTrigger(actionType.ADD_REMOTE_REPO);
                    }}
                  >
                    <FontAwesomeIcon
                      icon={faTools}
                      className="text-xl text-center text-white"
                    ></FontAwesomeIcon>
                  </div>
                </div>
              </div>
            </div>

            <div className="remote  flex justify-evenly my-4">
              <div className="text-lg text-gray-600 w-1/4">
                {`${gitRemoteHost} URL`}
              </div>
              <div className="cursor-pointer text-blue-400 break-words w-1/2 hover:text-blue-500">
                {remoteUrl()}
              </div>
            </div>

            {isMultiRemote ? (
              <div className=" flex justify-evenly my-2">
                <div className="font-sans text-gray-800 font-semibold w-1/4 border-dotted border-b-2 border-gray-200">
                  Entry truncated!
                </div>
                <div className="w-1/2 border-dotted border-b-2 border-gray-200">
                  {`Remote repos : ${multiRemoteCount}`}
                </div>
              </div>
            ) : null}
          </div>

          <div className="block my-6 mx-auto">
            <div
              className="p-3 text-gray-600 text-center w-3/4 mx-auto rounded-md shadow-md bg-yellow-200 text-whtie font-sans font-semibold text-xl hover:bg-yellow-100 hover:shadow-sm cursor-pointer transition"
              onClick={(event) => {
                showCommitLogsView();
              }}
            >
              SHOW COMMIT LOGS
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}
Example #25
Source File: FetchPullActionComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function FetchFromRemoteComponent(props) {
  library.add(fas);
  const { repoId, actionType } = props;

  const [remoteData, setRemoteData] = useState();
  const [isRemoteSet, setIsRemoteSet] = useState(false);
  const [isBranchSet, setIsBranchSet] = useState(false);
  const [result, setResult] = useState([]);
  const [loading, setLoading] = useState(false);

  const remoteRef = useRef();
  const branchRef = useRef();

  useEffect(() => {
    const cancelToken = axios.CancelToken;
    const source = cancelToken.source();

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      cancelToken: source.token,
      headers: {
        "Content-type": "application/json",
      },
      data: {
        query: `
                query
                {
                    gitRepoStatus(repoId:"${props.repoId}") {
                      gitRemoteData
                      gitCurrentBranch
                      gitRemoteHost
                      gitBranchList 
                    }
                }
              `,
      },
    })
      .then((res) => {
        const repoDetails = res.data.data.gitRepoStatus;
        setRemoteData(repoDetails);
      })
      .catch((err) => {
        setLoading(false);
      });

    return () => {
      return source.cancel();
    };
  }, [props]);

  function remoteHostGenerator() {
    if (remoteData) {
      const { gitRemoteData } = remoteData;
      if (gitRemoteData.includes("||")) {
        return gitRemoteData.split("||").map((item) => {
          return (
            <option value={item} key={item}>
              {item}
            </option>
          );
        });
      } else {
        return <option>{gitRemoteData}</option>;
      }
    }
  }

  function branchListGenerator() {
    if (remoteData) {
      const { gitBranchList } = remoteData;

      return gitBranchList.map((branch) => {
        if (branch !== "NO_BRANCH") {
          return (
            <option value={branch} key={branch}>
              {branch}
            </option>
          );
        }
        return null;
      });
    }
  }

  function actionHandler(remote = "", branch = "") {
    setLoading(true);
    setResult([]);
    const getAxiosRequestBody = (remote, branch) => {
      let gqlQuery = "";
      if (actionType === "fetch") {
        gqlQuery = `mutation {
          fetchFromRemote(repoId: "${repoId}", remoteUrl: "${remote}", remoteBranch: "${branch}"){
            status
            fetchedItems
          }
        }
      `;
      } else {
        gqlQuery = `mutation {
          pullFromRemote(repoId: "${repoId}", remoteUrl: "${remote}", remoteBranch: "${branch}"){
            status
            pulledItems
          }
        }
      `;
      }

      return gqlQuery;
    };

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: getAxiosRequestBody(remote, branch),
      },
    })
      .then((res) => {
        setLoading(false);
        if (res.data.data && !res.data.error) {
          let actionResponse = {};

          if (actionType === "fetch") {
            actionResponse = res.data.data.fetchFromRemote;
          } else {
            actionResponse = res.data.data.pullFromRemote;
          }

          if (actionResponse.status.match(/ABSENT/gi)) {
            setResult([
              <div className="text-xl text-center border-2 border-dashed border-gray-800 p-2 text-gray-700 font-semibold">
                No changes to {actionType === "fetch" ? "Fetch" : "Pull"} from
                remote
              </div>,
            ]);
          } else if (actionResponse.status.match(/ERROR/gi)) {
            setResult([
              <div className="text-xl p-2 text-pink-800 border border-pink-200 shadow rounded font-semibold">
                Error while {actionType === "fetch" ? "Fetching" : "Pulling"}{" "}
                from remote!
              </div>,
            ]);
          } else {
            let resArray = [];
            if (actionType === "fetch") {
              resArray = actionResponse.fetchedItems;
            } else {
              resArray = actionResponse.pulledItems;
            }
            setResult([
              <div className="text-xl text-center border-2 border-dashed border-green-600 p-2 text-green-700 bg-green-200 font-semibold rounded shadow">
                {resArray[0]}
              </div>,
            ]);
          }
        }
      })
      .catch((err) => {
        setLoading(false);
        console.error(err);
        setResult([
          <div className="text-xl p-2 text-red-500 border border-pink-200 shadow rounded font-semibold">
            Error while {actionType === "fetch" ? "Fetching" : "Pulling"} from
            remote!
          </div>,
        ]);
      });
  }

  return (
    <>
      <div className="w-3/4 mx-auto my-auto shadow rounded-lg bg-white pt-4">
        {actionType === "fetch" ? (
          <div>
            <div className="text-center font-sans font-semibold mx-auto w-full p-3 text-2xl border-b-2 border-dashed text-gray-800">
              Fetch from Remote
            </div>
          </div>
        ) : null}
        {actionType === "pull" ? (
          <div className="text-center font-sans font-semibold mx-auto w-full p-3 text-2xl border-b-2 border-dashed text-gray-800">
            Pull from Remote
          </div>
        ) : null}
        <div className="flex flex-wrap w-3/4 mx-auto my-4 justify-around items-center align-middle gap-4">
          <div className="w-full font-sans text-xl font-semibold text-gray-600">
            Available remotes
          </div>
          <div className="w-full mb-6">
            <select
              className="border p-3 text-lg rounded shadow font-sans outline-none"
              defaultValue="checked"
              disabled={remoteData ? false : true}
              onChange={() => {
                setIsRemoteSet(true);
              }}
              onClick={() => {
                setResult([]);
              }}
              ref={remoteRef}
            >
              <option disabled hidden value="checked">
                {remoteData
                  ? "Select the remote repo"
                  : "Loading available remotes..."}
              </option>
              {remoteData ? remoteHostGenerator() : null}
            </select>
          </div>
        </div>

        {isRemoteSet ? (
          <div className="flex flex-wrap w-3/4 mx-auto my-4 justify-around items-center align-middle gap-4">
            <div className="w-full font-sans text-xl font-semibold text-gray-600">
              Available Branches
            </div>
            <div className="w-full mb-6">
              <select
                className="border p-3 text-lg rounded shadow font-sans outline-none"
                defaultValue="checked"
                onChange={() => {
                  setIsBranchSet(true);
                }}
                onClick={() => {
                  setResult([]);
                }}
                ref={branchRef}
              >
                <option disabled hidden value="checked">
                  Select upstream branch
                </option>
                {remoteData ? branchListGenerator() : null}
              </select>
            </div>
          </div>
        ) : null}

        {isRemoteSet && isBranchSet && !loading ? (
          <div
            className="text-center font-semibold text-xl p-4 mx-auto cursor-pointer bg-indigo-400 text-white mt-10 rounded-b hover:bg-indigo-500"
            onClick={(event) => {
              const remoteHost = remoteRef.current.value;
              const branchName = branchRef.current.value;

              if (remoteHost && branchName) {
                actionHandler(remoteHost, branchName);
              } else {
                event.target.style.display = "none";
              }
            }}
          >
            {actionType === "pull" ? "PULL FROM REMOTE" : null}
            {actionType === "fetch" ? "FETCH FROM REMOTE" : null}
          </div>
        ) : null}
        <div>
          {loading ? (
            <>
              <div className="my-4 text-center border-2 border-dashed border-gray-500 font-light font-sans text-xl p-2 mx-auto text-gray-500 bg-gray-50 shadow rounded-md">
                {actionType === "pull" ? "Pulling changes" : "Fetching"} from
                remote...
              </div>
              <div className="flex mx-auto my-6 text-center justify-center">
                <InfiniteLoader loadAnimation={loading}></InfiniteLoader>
              </div>
            </>
          ) : null}
        </div>

        {true || (!loading && result && result.length > 0) ? (
          <>
            {result.map((result) => {
              return (
                <div
                  className="border-dashed border-gray-200 text-center text-xl font-sans shadow bg-red-200 rounded w-full"
                  key={result + `-${uuid()}`}
                >
                  {result}
                </div>
              );
            })}
          </>
        ) : null}
      </div>
    </>
  );
}
Example #26
Source File: CommitLogFileCard.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function CommitLogFileCard({
  repoId,
  commitHash,
  unmountHandler,
}) {
  library.add(far, fas);
  const [commitFiles, setCommitFiles] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  useEffect(() => {
    setIsLoading(true);
    const token = axios.CancelToken;
    const source = token.source();

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      cancelToken: source.token,
      data: {
        query: `
            query
            {
              gitCommitFiles(repoId: "${repoId}", commitHash: "${commitHash}"){
                    type
                    fileName
                }
              }
          `,
      },
    })
      .then((res) => {
        setIsLoading(false);
        if (res.data.data && !res.data.err) {
          setCommitFiles([...res.data.data.gitCommitFiles]);
        }
      })
      .catch((err) => {
        console.log(err);
        setIsLoading(false);
      });
  }, [repoId, commitHash]);

  return (
    <div className="w-11/12 p-6 rounded-lg shadow block mx-auto my-6 bg-blue-50">
      <div
        className="font-sans font-light float-right right-0 cursor-pointer mx-auto text-2xl text-blue-400 mb-0"
        style={{ marginTop: "-20px" }}
        onClick={() => {
          setCommitFiles([]);
          unmountHandler();
        }}
      >
        x
      </div>
      {isLoading ? (
        <div className="mx-4 text-2xl font-sans font-light text-gray-600 text-center">
          Fetching changed files...
        </div>
      ) : null}
      {!isLoading && commitFiles ? (
        <div className="mx-4 text-2xl font-sans font-light text-gray-600">{`${commitFiles.length} Files changed`}</div>
      ) : null}
      <div className="block w-3/4 mx-10 my-4">
        {commitFiles &&
          commitFiles.map(({ type, fileName }) => {
            let iconSelector = "";
            let colorSelector = "";
            switch (type) {
              case "M":
                iconSelector = "plus-square";
                colorSelector = "text-yellow-400";
                break;
              case "A":
                iconSelector = "plus-square";
                colorSelector = "text-green-500";
                break;
              case "D":
                iconSelector = "minus-square";
                colorSelector = "text-red-500";
                break;
              default:
                iconSelector = "plus-square";
                colorSelector = "text-gray-500";
                break;
            }

            return (
              <div
                className="flex justify-evenly items-center align-middle my-auto"
                key={fileName + commitHash}
              >
                <div className={`w-1/4 text-2xl ${colorSelector}`}>
                  <FontAwesomeIcon
                    icon={["far", iconSelector]}
                  ></FontAwesomeIcon>
                </div>
                <div
                  className="truncate w-3/4 font-medium text-sm text-gray-600"
                  title={fileName}
                >
                  {fileName}
                </div>
              </div>
            );
          })}
      </div>
    </div>
  );
}
Example #27
Source File: BranchCompareComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function BranchCompareComponent(props) {
  library.add(fas);
  const [branchList, setBranchList] = useState([]);
  const [currentBranch, setCurrentBranch] = useState("");
  const [compareBranch, setCompareBranch] = useState("");
  const [baseBranch, setBaseBranch] = useState("");
  const [errState, setErrState] = useState(false);

  const memoizedBranchCommitLogChangesComponent = useMemo(() => {
    return (
      <BranchCommitLogChanges
        repoId={props.repoId}
        baseBranch={baseBranch}
        compareBranch={compareBranch}
      ></BranchCommitLogChanges>
    );
  }, [props.repoId, baseBranch, compareBranch]);

  useEffect(() => {
    const token = axios.CancelToken;
    const source = token.source();
    setErrState(false);

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      cancelToken: source.token,
      data: {
        query: `
            query 
            {
                gitRepoStatus(repoId: "${props.repoId}") {
                    gitBranchList  
                    gitCurrentBranch
                }
            }
          `,
      },
    })
      .then((res) => {
        let { gitBranchList, gitCurrentBranch } = res.data.data.gitRepoStatus;

        if (gitBranchList.length <= 0 || gitCurrentBranch === "") {
          setErrState(true);
        }

        gitBranchList =
          gitBranchList &&
          gitBranchList.map((branch) => {
            return branch.trim();
          });

        if (gitBranchList.length > 1) {
          setCompareBranch(gitBranchList[1].trim());
        }

        setBranchList(gitBranchList);
        setCurrentBranch(gitCurrentBranch.trim());
        setBaseBranch(gitCurrentBranch.trim());
      })
      .catch((err) => {
        console.log(err);
        setErrState(true);
      });

    return () => {
      return source.cancel;
    };
  }, [props.repoId]);

  function noBranchToCompare() {
    return (
      <div className="w-full mx-auto my-auto text-center block">
        <FontAwesomeIcon
          icon={["fas", "puzzle-piece"]}
          className="font-sans text-center text-gray-300 my-20"
          size="10x"
        ></FontAwesomeIcon>
        <div className="text-2xl text-gray-300">
          Only one branch is available, hence can't be set for comparison
        </div>
      </div>
    );
  }

  function compareBranchSelectPane() {
    return (
      <div className="w-11/12 p-3 flex mx-auto items-center align-middle rounded-lg shadow-md border-2 justify-around">
        <div className="flex gap-6 justify-between items-center">
          <div className="text-xl text-center font-sans font-semibold border-b-2 border-dashed border-gray-400">
            Base branch
          </div>
          <div>
            <select
              defaultValue={currentBranch}
              className="outline-none p-2 shadow border-2 bg-white rounded-lg"
              onChange={(e) => {
                setBaseBranch(e.currentTarget.value.trim());
              }}
            >
              <option value={currentBranch}>{currentBranch}</option>
              {branchList.map((branch) => {
                if (branch !== currentBranch) {
                  return (
                    <option value={branch} key={branch}>
                      {branch}
                    </option>
                  );
                }
                return null;
              })}
            </select>
          </div>
        </div>
        <div className="flex gap-6 justify-between items-center">
          <div className="text-xl text-center font-sans font-semibold border-b-2 border-dashed border-gray-400">
            Compare branch
          </div>
          <div>
            <select
              className="outline-none p-2 shadow border-2 bg-white rounded-lg"
              onChange={(e) => {
                setCompareBranch(e.currentTarget.value);
              }}
            >
              {branchList.map((branch, index) => {
                if (baseBranch && baseBranch !== branch) {
                  return (
                    <option value={branch} key={branch}>
                      {branch}
                    </option>
                  );
                } else {
                  return index === 0 ? null : (
                    <option value={branch} key={branch}>
                      {branch}
                    </option>
                  );
                }
              })}
            </select>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div>
      {branchList.length === 1 ? (
        noBranchToCompare()
      ) : branchList.length === 0 && !errState ? (
        <div className="mx-auto my-20 text-center flex justify-center text-4xl font-sans text-gray-300">
          Loading Branch Info...
        </div>
      ) : !errState ? (
        compareBranchSelectPane()
      ) : null}
      {baseBranch && compareBranch && !errState
        ? memoizedBranchCommitLogChangesComponent
        : null}

      {errState ? (
        <div className="mx-auto text-center text-2xl text-gray-500 font-sans font-semibold p-4 border-b border-dashed border-gray-400">
          Error occurred while fetching results. Please verify if the repo has
          valid branches
        </div>
      ) : null}
    </div>
  );
}
Example #28
Source File: BranchListComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function BranchListComponent({ repoId }) {
  library.add(fas);

  const [branchList, setBranchList] = useState([]);
  const [listError, setListError] = useState(false);
  const [switchError, setSwitchError] = useState(false);
  const [switchedBranch, setSwitchedBranch] = useState("");
  const [errorBranch, setErrorBranch] = useState("");
  const [deleteError, setDeleteError] = useState(false);
  const [loading, setLoading] = useState(false);
  const [branchSearchTerm, setBranchSearchTerm] = useState("");
  const [filteredBranchList, setFilteredBranchList] = useState([]);

  function resetStates() {
    setListError(false);
    setSwitchError(false);
    setSwitchedBranch("");
    setErrorBranch("");
    setDeleteError(false);
    setBranchSearchTerm("");
    setFilteredBranchList([]);
  }

  useEffect(() => {
    const token = axios.CancelToken;
    const source = token.source();

    setLoading(true);
    setBranchList([]);
    setSwitchedBranch("");

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      cancelToken: source.token,
      data: {
        query: `
          query
          {
            gitRepoStatus(repoId:"${repoId}"){
                gitAllBranchList  
                gitCurrentBranch
            }
          }
        `,
      },
    })
      .then((res) => {
        setLoading(false);

        if (res.data.data && !res.data.error) {
          let {
            gitAllBranchList,
            gitCurrentBranch,
          } = res.data.data.gitRepoStatus;

          if (gitCurrentBranch === "Repo HEAD is nil") {
            setBranchList([]);
            setListError(true);
            return;
          }
          gitAllBranchList = gitAllBranchList.map((branch) => {
            if (branch === gitCurrentBranch) {
              return "*" + branch;
            }
            return branch;
          });
          setBranchList([...gitAllBranchList]);
        } else {
          setListError(true);
        }
      })
      .catch((err) => {
        setLoading(false);

        if (err) {
          console.log("API error occurred : " + err);
          setListError(true);
        }
      });

    return () => source.cancel;
  }, [repoId, switchedBranch]);

  function switchBranchHandler(branchName) {
    resetStates();
    setLoading(true);
    setBranchList([]);
    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: `
            mutation{
              checkoutBranch(repoId: "${repoId}", branchName: "${branchName}")
            }
          `,
      },
    })
      .then((res) => {
        setLoading(false);

        if (res.data.data && !res.data.error) {
          const checkoutStatus = res.data.data.checkoutBranch;
          if (checkoutStatus === "CHECKOUT_FAILED") {
            setErrorBranch(branchName);
            setSwitchError(true);
            return;
          } else {
            setSwitchedBranch(branchName);
          }
        } else {
          setSwitchError(true);
          setErrorBranch(branchName);
        }
      })
      .catch((err) => {
        setLoading(false);

        if (err) {
          setSwitchError(true);
          setErrorBranch(branchName);
        }
      });
  }

  function deleteBranchHandler(branchName, forceFlag) {
    resetStates();
    setLoading(true);

    axios({
      url: globalAPIEndpoint,
      method: "POST",
      data: {
        query: `
            mutation{
              deleteBranch(repoId: "${repoId}", branchName: "${branchName}", forceFlag: ${forceFlag}){
                status
              }
            }
          `,
      },
    })
      .then((res) => {
        setLoading(false);

        if (res.data.data && !res.data.error) {
          if (res.data.data.deleteBranch.status === "BRANCH_DELETE_SUCCESS") {
            setSwitchedBranch(branchName);
          } else {
            setDeleteError(true);
            setErrorBranch(branchName);
          }
        }
      })
      .catch((err) => {
        setLoading(false);

        if (err) {
          setDeleteError(true);
          setErrorBranch(branchName);
        }
      });
  }

  function errorComponent(errorString, branchError = false) {
    return (
      <div className="text-center p-4 rounded bg-red-300 text-xl font-sans mt-10">
        {errorString}
        {branchError ? (
          <span className="font-semibold border-b border-dashed mx-2">
            {errorBranch}
          </span>
        ) : null}
      </div>
    );
  }

  const searchBranchFromList = (event) => {
    const searchBranch = event.target.value;
    setBranchSearchTerm(searchBranch);
    if (searchBranch !== "") {
      const filteredBranches = branchList.filter((branchName) =>
        branchName.toLowerCase().includes(searchBranch)
      );
      setFilteredBranchList(filteredBranches);
    } else {
      setFilteredBranchList([]);
    }
  };

  const cancelSearchBranchFromList = () => {
    setBranchSearchTerm("");
    setFilteredBranchList([]);
  };

  const renderBranchListComponent = (branch) => {
    const branchPickerComponent = (icon, branchType, branchName) => {
      let activeSwitchStyle = "";
      let activeBranchFlag = false;
      if (branchName.includes("*")) {
        activeBranchFlag = true;
        branchName = branchName.replace("*", "");
      }

      if (activeBranchFlag) {
        activeSwitchStyle = "border-dashed border-b-2 text-indigo-700 text-2xl";
      }
      return (
        <div
          className="flex items-center justify-center px-14 py-4 mx-auto border-dashed border-b"
          key={branchType + branchName}
        >
          <div
            className={
              icon === "wifi"
                ? "mx-2 text-2xl text-blue-500 ml-0"
                : "mx-2 text-2xl text-blue-500"
            }
          >
            <FontAwesomeIcon icon={["fas", icon]}></FontAwesomeIcon>
          </div>
          <div className="xl:block lg:block md:block sm:hidden w-1/3 font-sans text-lg font-semibold text-center text-indigo-500">
            {branchType}
          </div>
          <div
            className={`w-1/2 font-sans font-semibold text-lg text-left cursor-pointer overflow-hidden text-gray-500 hover:text-blue-800 ${activeSwitchStyle}`}
            title={branchName}
            onClick={() => {
              if (!activeBranchFlag) {
                if (branchType !== "Local Branch") {
                  switchBranchHandler(branch);
                } else {
                  switchBranchHandler(branchName);
                }
              }
            }}
          >
            {branchName}
          </div>
          {!activeBranchFlag && branchType === "Local Branch" ? (
            <div className="flex mx-4 justify-between my-auto text-center items-center w-1/4 px-2">
              <div
                className="w-1/2 block mx-auto my-auto text-center px-2 justify-center bg-red-500 p-2 rounded-lg shadow-md cursor-pointer text-white font-sans font-semibold hover:bg-red-600"
                title="Will delete the branch forcefully.Be careful!"
                onClick={() => {
                  if (!activeBranchFlag) {
                    deleteBranchHandler(branchName, true);
                  }
                }}
              >
                <div>
                  <FontAwesomeIcon
                    icon={["fas", "trash-alt"]}
                  ></FontAwesomeIcon>
                </div>
                <div>DELETE</div>
              </div>
            </div>
          ) : (
            <>
              {activeBranchFlag ? (
                <div className="w-1/4 font-sans mx-4 text-sm px-2 font-light border border-dashed p-1 rounded-full text-center bg-blue-100 border-blue-800">
                  Active
                </div>
              ) : (
                <div className="w-1/4 font-sans mx-4 text-sm px-2 font-light border border-dashed p-1 rounded-full text-center bg-yellow-100 border-yellow-700">
                  Remote
                </div>
              )}
            </>
          )}
        </div>
      );
    };

    if (!branch.includes("remotes/")) {
      return branchPickerComponent("code-branch", "Local Branch", branch);
    } else {
      const splitBranch = branch.split("/");
      if (splitBranch.length <= 2) {
        return null;
      }
      const remoteName = splitBranch[1];
      const remoteBranch = splitBranch.slice(2, splitBranch.length).join("/");

      return branchPickerComponent("wifi", remoteName, remoteBranch);
    }
  };

  return (
    <div className="bg-gray-50 p-6 mx-auto my-auto items-center rounded-lg w-11/12 xl:w-3/4 lg:w-3/4 md:w-11/12 sm:w-11/12">
      <div className="text-4xl my-4 font-sans font-semibold text-gray-600">
        Available Branches
      </div>
      <div className="flex justify-start items-center font-sans text-sm font-semibold text-red-500">
        <div>
          <FontAwesomeIcon
            icon={["fas", "exclamation-circle"]}
          ></FontAwesomeIcon>
        </div>
        <div className="mx-2 font-sans font-semibold">
          Note that this section also lets you delete the branches, so be
          cautious!
        </div>
      </div>
      <div className="italic font-sans font-semibold text-lg my-2 border-b-2 border-dashed border-gray-300 text-gray-300">
        Click on a branch to checkout to that branch
      </div>
      <div
        className="w-full mx-auto my-6 overflow-y-auto overflow-x-hidden"
        style={{ height: "400px" }}
      >
        {loading ? (
          <div className="text-center font-sans font-light text-xl my-2 text-gray-600 border-b border-dotted">
            Collecting branch list...
          </div>
        ) : null}
        {!loading ? (
          <div className="flex flex-row mx-8 shadow-md rounded-md my-4">
            <div className="b-1 text-center p-4 text-white bg-blue-500 rounded-l-md">
              <FontAwesomeIcon icon={["fas", "search"]}></FontAwesomeIcon>
            </div>
            <div className="w-full">
              <input
                id="branchListSearchInput"
                type="text"
                placeholder="Search For Branch Name"
                className="border-0 outline-none w-full p-4 focus:outline-none"
                onChange={searchBranchFromList}
                value={branchSearchTerm}
              ></input>
            </div>
            <div
              className="b-1 text-center p-4 text-gray-500 cursor-pointer bg-white rounded-r-md"
              onClick={cancelSearchBranchFromList}
            >
              <FontAwesomeIcon icon={["fas", "times"]}></FontAwesomeIcon>
            </div>
          </div>
        ) : null}
        {!listError && branchList && branchSearchTerm !== "" ? (
          filteredBranchList.length > 0 ? (
            filteredBranchList.map((branch) => {
              return renderBranchListComponent(branch);
            })
          ) : (
            <div className="text-center font-sans font-light text-xl my-2 text-gray-600 border-b border-dotted">
              <span className="mx-2 font-semibold border-b border-dashed">
                {branchSearchTerm}
              </span>
              branch is not available!
            </div>
          )
        ) : (
          branchList.map((branch) => {
            return renderBranchListComponent(branch);
          })
        )}
      </div>
      {listError
        ? errorComponent("Error occurred while listing branches!")
        : null}

      {switchError
        ? errorComponent("Error occurred while switching to", true)
        : null}

      {switchedBranch && switchedBranch.length > 0 && deleteError
        ? errorComponent("Branch deletion failed for", true)
        : null}
    </div>
  );
}
Example #29
Source File: FileExplorerComponent.js    From gitconvex with Apache License 2.0 4 votes vote down vote up
export default function FileExplorerComponent(props) {
  library.add(fab, fas);

  const [gitRepoFiles, setGitRepoFiles] = useState([]);
  const [codeViewToggle, setCodeViewToggle] = useState(false);
  const [gitFileBasedCommits, setGitFileBasedCommits] = useState([]);
  const [directoryNavigator, setDirectoryNavigator] = useState([]);
  const [codeViewItem, setCodeViewItem] = useState("");
  const [selectionIndex, setSelectionIndex] = useState(0);
  const [isEmpty, setIsEmpty] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [cwd, setCwd] = useState("");

  const { repoIdState } = props;

  const memoizedCodeFileViewComponent = useMemo(() => {
    return (
      <CodeFileViewComponent
        repoId={repoIdState}
        fileItem={codeViewItem}
        commitMessage={gitFileBasedCommits[selectionIndex]}
      ></CodeFileViewComponent>
    );
  }, [repoIdState, codeViewItem, gitFileBasedCommits, selectionIndex]);

  function filterNullCommitEntries(gitTrackedFiles, gitFileBasedCommit) {
    let localGitCommits = gitFileBasedCommit;
    let localTrackedFiles = gitTrackedFiles.filter((item, index) => {
      if (item) {
        return true;
      } else {
        localGitCommits[index] = "";
        return false;
      }
    });

    localGitCommits = localGitCommits.filter((commit) => commit);

    setGitRepoFiles([...localTrackedFiles]);
    setGitFileBasedCommits([...localGitCommits]);
  }

  useEffect(() => {
    const repoId = props.repoIdState;
    setIsEmpty(false);
    setIsLoading(true);
    axios({
      url: globalAPIEndpoint,
      method: "POST",
      headers: {
        "Content-type": "application/json",
      },
      data: {
        query: `
          query
          {
            gitFolderContent(repoId:"${repoId}", directoryName: ""){
              trackedFiles
              fileBasedCommits   
            }
          }
        `,
      },
    })
      .then((res) => {
        setIsLoading(false);
        const {
          trackedFiles,
          fileBasedCommits,
        } = res.data.data.gitFolderContent;

        if (trackedFiles.length === 0 || fileBasedCommits.length === 0) {
          setIsEmpty(true);
          return;
        }

        if (trackedFiles && fileBasedCommits) {
          filterNullCommitEntries(trackedFiles, fileBasedCommits);
        }
      })
      .catch((err) => {
        console.log(err);
        setIsLoading(false);
      });
  }, [props]);

  function directorySeparatorRemover(directoryPath) {
    if (directoryPath.match(/.\/./gi)) {
      directoryPath = directoryPath.split("/")[
        directoryPath.split("/").length - 1
      ];
    } else if (directoryPath.match(/[^\\]\\[^\\]/gi)) {
      directoryPath = directoryPath.split("\\")[
        directoryPath.split("\\").length - 1
      ];
    } else if (directoryPath.match(/.\\\\./gi)) {
      directoryPath = directoryPath.split("\\\\")[
        directoryPath.split("\\\\").length - 1
      ];
    }

    return directoryPath;
  }

  const fetchFolderContent = (
    directoryName,
    slicePosition,
    sliceIndicator,
    homeIndicator
  ) => {
    if (repoIdState) {
      setGitRepoFiles([]);
      setGitFileBasedCommits([]);
      let localDirNavigator = directoryNavigator;

      if (sliceIndicator) {
        let slicedDirectory = localDirNavigator.slice(0, slicePosition);
        if (slicedDirectory.length > 0) {
          directoryName = slicedDirectory.join("/") + "/" + directoryName;
        }
      }

      setCwd(directoryName);
      setIsLoading(true);

      axios({
        url: globalAPIEndpoint,
        method: "POST",
        headers: {
          "Content-type": "application/json",
        },
        data: {
          query: `
            query
            {
              gitFolderContent(repoId:"${repoIdState}", directoryName: "${directoryName}"){
                trackedFiles
                fileBasedCommits   
              }
            }
          `,
        },
      })
        .then((res) => {
          setIsLoading(false);
          if (res.data.data && !res.data.error) {
            const localFolderContent = res.data.data.gitFolderContent;

            filterNullCommitEntries(
              localFolderContent.trackedFiles,
              localFolderContent.fileBasedCommits
            );

            directoryName = directorySeparatorRemover(directoryName);

            if (homeIndicator) {
              setDirectoryNavigator([]);
              return;
            }

            if (directoryNavigator.length === 0) {
              setDirectoryNavigator([directoryName]);
            } else {
              if (
                sliceIndicator &&
                slicePosition < directoryNavigator.length - 1
              ) {
                const iterator =
                  directoryNavigator.length - (slicePosition + 1);

                for (let i = 0; i < iterator; i++) {
                  localDirNavigator.pop();
                }
                setDirectoryNavigator([...localDirNavigator]);
              } else {
                setDirectoryNavigator([...directoryNavigator, directoryName]);
              }
            }
          } else {
            setIsLoading(false);
            console.log(
              "ERROR: Error occurred while fetching the folder content!"
            );
          }
        })
        .catch((err) => {
          setIsLoading(false);
          if (err) {
            console.log(
              "ERROR: Error occurred while fetching the folder content!",
              err
            );
          }
        });
    }
  };

  const gitTrackedFileComponent = () => {
    var fileIcon;

    if (gitRepoFiles && gitRepoFiles.length > 0) {
      var formattedFiles = [];
      var directoryEntry = [];
      var fileEntry = [];

      gitRepoFiles.forEach(async (entry, index) => {
        const splitEntry = entry.split(":");

        if (splitEntry[1] && splitEntry[1].includes("directory")) {
          let directoryPath = directorySeparatorRemover(splitEntry[0]);

          directoryEntry.push(
            <div
              className="block w-full p-2 border-b border-gray-200"
              key={`directory-key-${uuid()}`}
            >
              <div className="flex cursor-pointer items-center">
                <div className="w-1/6">
                  <FontAwesomeIcon
                    icon={["fas", "folder"]}
                    className="font-sans text-xl"
                  ></FontAwesomeIcon>
                </div>
                <div
                  className="font-sans w-1/2 text-gray-600 text-xl mx-3 hover:text-indigo-400"
                  onClick={(event) => {
                    fetchFolderContent(splitEntry[0], 0, false);
                  }}
                >
                  {directoryPath}
                </div>

                <div className="w-3/5 p-2 overflow-hidden truncate rounded-lg mx-auto text-left bg-green-200 text-green-900">
                  {gitFileBasedCommits[index]}
                </div>
              </div>
            </div>
          );
        } else if (splitEntry[1] && splitEntry[1].includes("File")) {
          if (splitEntry[0] === "LICENSE") {
            fileIcon = require("../../../../../assets/icons/file_type_license.svg");
          } else {
            fileIcon = require("../../../../../assets/icons/" +
              getIconForFile(splitEntry[0]));
          }
          fileEntry.push(
            <div
              className="block w-full p-2 border-b border-gray-200"
              key={`file-key-${uuid()}`}
            >
              <div className="flex items-center align-middle cursor-pointer">
                <div className="w-1/6">
                  <img
                    src={fileIcon.default}
                    style={{
                      width: "26px",
                      filter: "grayscale(30%)",
                    }}
                    alt={fileIcon.default}
                  ></img>
                </div>
                <div
                  className="font-sans w-1/2 text-gray-700 text-xl mx-3 hover:text-indigo-400"
                  onClick={() => {
                    setSelectionIndex(index);
                    if (cwd === "" || cwd === "/") {
                      setCodeViewItem(splitEntry[0]);
                    } else {
                      setCodeViewItem(cwd + "/" + splitEntry[0]);
                    }
                    setCodeViewToggle(true);
                  }}
                >
                  {splitEntry[0]}
                </div>
                <div className="w-3/5 p-2 overflow-hidden truncate rounded-lg mx-auto text-left bg-indigo-200 text-indigo-900">
                  {gitFileBasedCommits[index]}
                </div>
              </div>
            </div>
          );
        }
      });

      formattedFiles.push(directoryEntry);
      formattedFiles.push(fileEntry);

      return (
        <div
          className="block mx-auto justify-center p-2"
          style={{
            color: "#79b8ff",
          }}
          key="repo-key"
        >
          <div className="flex w-full justify-around p-2 mx-auto pb-4 border-b border-blue-400">
            <div className="w-1/6"></div>
            <div className="w-2/4 font-sans font-semibold">
              File / Directory
            </div>
            <div className="w-2/4 font-sans font-semibold">Latest commit</div>
          </div>
          {formattedFiles}
        </div>
      );
    }
  };

  return (
    <>
      {isLoading ? (
        <>
          <div className="flex justify-center mx-auto my-2 w-3/4">
            <div className="w-full mx-auto text-2xl text-center font-sans font-semibold text-gray-700 border-b-2 border-dashed border-gray-400">
              Loading tracked files...
            </div>
          </div>
          <div className="flex mx-auto my-6 text-center justify-center">
            <InfiniteLoader
              loadAnimation={!gitRepoFiles.length}
            ></InfiniteLoader>
          </div>
        </>
      ) : (
        <>
          {codeViewToggle ? (
            <div
              className="fixed flex w-full h-full top-0 left-0 right-0 overflow-auto"
              id="code-view__backdrop"
              style={{ background: "rgba(0,0,0,0.5)", zIndex: 99 }}
              onClick={(event) => {
                if (event.target.id === "code-view__backdrop") {
                  setCodeViewToggle(false);
                }
              }}
            >
              <div
                className="w-14 h-14 mr-5 mt-6 rounded-full bg-red-500 text-white flex justify-center items-center shadow cursor-pointer fixed right-0 top-0"
                onClick={() => {
                  setCodeViewToggle(false);
                }}
              >
                <FontAwesomeIcon
                  className="flex text-center text-3xl my-auto"
                  icon={["fas", "times"]}
                ></FontAwesomeIcon>
              </div>
              <div className="w-full h-full mx-auto my-auto flex mt-4 mb-10">
                {memoizedCodeFileViewComponent}
              </div>
            </div>
          ) : null}

          <div>
            <div
              className="w-1/6 text-gray-600 cursor-pointer border-b-2 border-dashed text-center flex justify-center gap-4 p-3 rounded mx-6 myy-auto items-center align-middle text-xl"
              onClick={() => {
                fetchFolderContent("", 0, false, true);
              }}
            >
              <div>
                <FontAwesomeIcon icon={["fas", "home"]}></FontAwesomeIcon>
              </div>
              <div>Home</div>
              <div className="text-2xl font-sans text-blue-400">./</div>
            </div>
            {directoryNavigator && gitRepoFiles && gitRepoFiles.length > 0 ? (
              <div className="mx-6 p-3 flex font-sans justify-start items-center gap-4">
                <div
                  className="flex p-4 w-3/4 gap-4 items-center break-words overflow-x-auto"
                  id="repoFolderNavigator"
                >
                  {directoryNavigator.map((item, index) => {
                    return (
                      <div
                        className="flex items-center justify-start gap-2"
                        key={item + "-" + index}
                      >
                        <div
                          className={`${
                            index !== directoryNavigator.length - 1
                              ? "text-blue-400 cursor-pointer font-semibold hover:text-blue-500 underline"
                              : ""
                          } text-xl`}
                          onClick={() => {
                            if (index !== directoryNavigator.length - 1) {
                              fetchFolderContent(item, index, true);
                            }
                          }}
                        >
                          {item}
                        </div>
                        <div>/</div>
                      </div>
                    );
                  })}
                </div>
              </div>
            ) : null}

            <div className="block w-11/12 my-6 mx-auto justify-center p-6 rounded-lg bg-white shadow overflow-auto border">
              {!isEmpty ? (
                gitTrackedFileComponent()
              ) : (
                <div className="flex w-3/4 gap-4 mx-auto items-center align-middle justify-center rounded-lg text-gray-500 text-center border-b-4 text-2xl border-dashed p-1 border-gray-300">
                  <div>
                    <FontAwesomeIcon icon={["fas", "unlink"]}></FontAwesomeIcon>
                  </div>
                  <div>No Tracked Files in the directory!</div>
                </div>
              )}
            </div>
          </div>
        </>
      )}
    </>
  );
}