فهرست منبع

add search button and bar, rewrite repolist to be a functional component, add type to context

Ivan Galakhov 4 سال پیش
والد
کامیت
4669ebffd0

+ 52 - 0
dashboard/src/components/Button.tsx

@@ -0,0 +1,52 @@
+import React from 'react';
+import styled from "styled-components";
+
+interface Props {
+  disabled?: boolean
+  children: React.ReactNode
+}
+
+const Button = ({children, disabled} : Props) => {
+    return <ButtonWrapper disabled={disabled}>{children}</ButtonWrapper>
+}
+
+export default Button;
+
+const ButtonWrapper = styled.div`
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 13px;
+  cursor: pointer;
+  font-family: "Work Sans", sans-serif;
+  color: white;
+  font-weight: 500;
+  padding: 10px;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  box-shadow: 0 5px 8px 0px #00000010;
+  cursor: ${(props: { disabled?: boolean }) =>
+  props.disabled ? "not-allowed" : "pointer"};
+
+  background: ${(props: { disabled?: boolean }) =>
+  props.disabled ? "#aaaabbee" : "#616FEEcc"};
+  :hover {
+    background: ${(props: { disabled?: boolean }) =>
+  props.disabled ? "" : "#505edddd"};
+  }
+
+  > i {
+    color: white;
+    width: 18px;
+    height: 18px;
+    font-weight: 600;
+    font-size: 12px;
+    border-radius: 20px;
+    display: flex;
+    align-items: center;
+    margin-right: 5px;
+    justify-content: center;
+  }
+`;

+ 81 - 70
dashboard/src/components/repo-selector/RepoList.tsx

@@ -1,53 +1,51 @@
-import React, { Component } from "react";
+import React, { useState, useContext, useEffect } from "react";
 import styled from "styled-components";
 import github from "assets/github.png";
-import info from "assets/info.svg";
 
 import api from "shared/api";
 import { RepoType, ActionConfigType } from "shared/types";
 import { Context } from "shared/Context";
 
 import Loading from "../Loading";
+import Button from "../Button";
 
-type PropsType = {
+type Props = {
   actionConfig: ActionConfigType | null;
   setActionConfig: (x: ActionConfigType) => void;
   userId?: number;
   readOnly: boolean;
 };
 
-type StateType = {
-  repos: RepoType[];
-  loading: boolean;
-  error: boolean;
-  searchFilter: string;
-};
-
-export default class RepoList extends Component<PropsType, StateType> {
-  state = {
-    repos: [] as RepoType[],
-    loading: true,
-    error: false,
-    searchFilter: "",
-  };
+const RepoList = ({
+  actionConfig,
+  setActionConfig,
+  userId,
+  readOnly,
+}: Props) => {
+  const [repos, setRepos] = useState<RepoType[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(false);
+  const [searchFilter, setSearchFilter] = useState("");
+  const { currentProject } = useContext(Context);
 
   // TODO: Try to unhook before unmount
-  componentDidMount() {
-    let { currentProject } = this.context;
-
+  useEffect(() => {
     // Get repos
-    if (!this.props.userId && this.props.userId !== 0) {
+    if (!userId && userId !== 0) {
       api
         .getGitRepos("<token>", {}, { project_id: currentProject.id })
         .then(async (res) => {
           if (res.data.length == 0) {
-            this.setState({ loading: false, error: false });
+            setLoading(false);
+            setError(false);
             return;
           }
 
           var allRepos: any = [];
           var errors: any = [];
 
+          console.log(res);
+
           var promises = res.data.map((gitrepo: any, id: number) => {
             return new Promise((resolve, reject) => {
               api
@@ -97,18 +95,21 @@ export default class RepoList extends Component<PropsType, StateType> {
           });
 
           if (allRepos.length == 0 && errors.length > 0) {
-            this.setState({ loading: false, error: true });
+            setLoading(false);
+            setError(true);
           } else {
-            this.setState({
-              repos: allRepos,
-              loading: false,
-              error: false,
-            });
+            setRepos(allRepos);
+            setLoading(false);
+            setError(false);
           }
         })
-        .catch((_) => this.setState({ loading: false, error: true }));
+        .catch((_) => {
+          setLoading(false);
+          setError(true);
+        });
     } else {
-      let grid = this.props.userId;
+      // ??? wouldn't this always be an undefined request?
+      let grid = userId;
 
       api
         .getGitRepoList(
@@ -132,25 +133,25 @@ export default class RepoList extends Component<PropsType, StateType> {
               return 0;
             }
           });
-
-          this.setState({ repos: repos, loading: false, error: false });
+          setRepos(repos);
+          setLoading(false);
+          setError(false);
         })
-        .catch((err) => {
-          this.setState({ loading: false, error: true });
+        .catch((_) => {
+          setLoading(false);
+          setError(true);
         });
     }
-  }
+  }, []);
 
-  setRepo = (x: RepoType) => {
-    let { actionConfig, setActionConfig } = this.props;
+  const setRepo = (x: RepoType) => {
     let updatedConfig = actionConfig;
     updatedConfig.git_repo = x.FullName;
     updatedConfig.git_repo_id = x.GHRepoID;
     setActionConfig(updatedConfig);
   };
 
-  renderRepoList = () => {
-    let { repos, loading, error } = this.state;
+  const renderRepoList = () => {
     if (loading) {
       return (
         <LoadingWrapper>
@@ -164,7 +165,7 @@ export default class RepoList extends Component<PropsType, StateType> {
         <LoadingWrapper>
           No connected Github repos found. You can
           <A
-            href={`/api/oauth/projects/${this.context.currentProject.id}/github?redirected=true`}
+            href={`/api/oauth/projects/${currentProject.id}/github?redirected=true`}
           >
             log in with GitHub
           </A>
@@ -175,16 +176,16 @@ export default class RepoList extends Component<PropsType, StateType> {
 
     return repos
       .filter((repo: RepoType, i: number) => {
-        return repo.FullName.includes(this.state.searchFilter || "");
+        return repo.FullName.includes(searchFilter || "");
       })
       .map((repo: RepoType, i: number) => {
         return (
           <RepoName
             key={i}
-            isSelected={repo.FullName === this.props.actionConfig.git_repo}
+            isSelected={repo.FullName === actionConfig.git_repo}
             lastItem={i === repos.length - 1}
-            onClick={() => this.setRepo(repo)}
-            readOnly={this.props.readOnly}
+            onClick={() => setRepo(repo)}
+            readOnly={readOnly}
           >
             <img src={github} />
             {repo.FullName}
@@ -193,38 +194,42 @@ export default class RepoList extends Component<PropsType, StateType> {
       });
   };
 
-  renderExpanded = () => {
-    if (this.props.readOnly) {
-      return <ExpandedWrapperAlt>{this.renderRepoList()}</ExpandedWrapperAlt>;
+  const renderExpanded = () => {
+    if (readOnly) {
+      return <ExpandedWrapperAlt>{renderRepoList()}</ExpandedWrapperAlt>;
     } else {
       return (
-        <ExpandedWrapper>
-          <InfoRow
-            isSelected={false}
-            lastItem={false}
-            readOnly={this.props.readOnly}
-          >
-            <i className="material-icons">search</i>
-            <SearchInput
-              value={this.state.searchFilter}
-              onChange={(e: any) => {
-                this.setState({ searchFilter: e.target.value });
-              }}
-              placeholder="Search repos..."
-            />
-          </InfoRow>
-          <ExpandedWrapper>{this.renderRepoList()}</ExpandedWrapper>
-        </ExpandedWrapper>
+        <>
+          <SearchRow>
+            <SearchBar>
+              <i className="material-icons">search</i>
+              <SearchInput
+                value={searchFilter}
+                onChange={(e: any) => {
+                  setSearchFilter(e.target.value);
+                }}
+                placeholder="Search repos..."
+              />
+            </SearchBar>
+            <Button>Search</Button>
+          </SearchRow>
+          <ExpandedWrapper>
+            <ExpandedWrapper>{renderRepoList()}</ExpandedWrapper>
+          </ExpandedWrapper>
+        </>
       );
     }
   };
 
-  render() {
-    return <>{this.renderExpanded()}</>;
-  }
-}
+  return <>{renderExpanded()}</>;
+};
+
+export default RepoList;
 
-RepoList.contextType = Context;
+const SearchRow = styled.div`
+  display: flex;
+  border-bottom: 1px solid #606166;
+`;
 
 const RepoName = styled.div`
   display: flex;
@@ -321,6 +326,13 @@ const A = styled.a`
   cursor: pointer;
 `;
 
+const SearchBar = styled.div`
+  display: flex;
+  flex: 1;
+  margin-top: 7px;
+  margin-left: 5px;
+`;
+
 const SearchInput = styled.input`
   outline: none;
   border: none;
@@ -328,6 +340,5 @@ const SearchInput = styled.input`
   background: none;
   width: 100%;
   color: white;
-  padding: 0;
   height: 20px;
 `;

+ 7 - 2
dashboard/src/shared/Context.tsx

@@ -1,8 +1,13 @@
 import React, { Component } from "react";
 
-import { ProjectType, ClusterType, CapabilityType } from "shared/types";
+import {
+  ProjectType,
+  ClusterType,
+  CapabilityType,
+  ContextProps,
+} from "shared/types";
 
-const Context = React.createContext({});
+const Context = React.createContext<Partial<ContextProps>>(null);
 
 const { Provider } = Context;
 const ContextConsumer = Context.Consumer;

+ 21 - 0
dashboard/src/shared/types.tsx

@@ -177,3 +177,24 @@ export interface CapabilityType {
   github: boolean;
   provisioner: boolean;
 }
+
+export interface ContextProps {
+  currentModal?: string;
+  currentModalData: any;
+  setCurrentModal: (currentModal: string, currentModalData?: any) => void;
+  currentError?: string;
+  setCurrentError: (currentError: string) => void;
+  currentCluster?: ClusterType;
+  setCurrentCluster: (currentCluster: ClusterType, callback?: any) => void;
+  currentProject?: ProjectType;
+  setCurrentProject: (currentProject: ProjectType, callback?: any) => void;
+  projects: ProjectType[];
+  setProjects: (projects: ProjectType[]) => void;
+  user: any;
+  setUser: (userId: number, email: string) => void;
+  devOpsMode: boolean;
+  setDevOpsMode: (devOpsMode: boolean) => void;
+  capabilities: CapabilityType;
+  setCapabilities: (capabilities: CapabilityType) => void;
+  clearContext: () => void;
+}