Sean Rhee 5 лет назад
Родитель
Сommit
89185b6407

BIN
dashboard/src/assets/135838220_453682579008540_3631330216063463363_n.jpg


BIN
dashboard/src/assets/135843858_160478529194149_2718194807911771299_n.jpg


+ 24 - 0
dashboard/src/assets/GithubIcon.tsx

@@ -0,0 +1,24 @@
+import React, { Component } from 'react';
+import styled from 'styled-components';
+
+type PropsType = {
+};
+
+type StateType = {
+};
+
+
+export default class GHIcon extends Component<PropsType, StateType> {
+  render() {
+    return(
+      <Svg height='18' width='18' viewBox='0 0 16 16'>
+        <path fill-rule='evenodd' d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
+      </Svg>
+    );
+  }
+}
+
+const Svg = styled.svg`
+  fill: white;
+  margin-right: 6px;
+`;

+ 7 - 108
dashboard/src/components/repo-selector/ActionConfEditor.tsx

@@ -1,12 +1,10 @@
 import React, { Component } from 'react';
 import styled from 'styled-components';
-import github from '../../assets/github.png';
 
-import api from '../../shared/api';
-import { RepoType, ActionConfigType } from '../../shared/types';
+import { ActionConfigType } from '../../shared/types';
 import { Context } from '../../shared/Context';
 
-import Loading from '../Loading';
+import RepoList from './RepoList';
 import BranchList from './BranchList';
 import ContentsList from './ContentsList';
 import ActionDetails from './ActionDetails';
@@ -21,82 +19,16 @@ type PropsType = {
 };
 
 type StateType = {
-  repos: RepoType[],
   loading: boolean,
   error: boolean,
 };
 
 export default class ActionConfEditor extends Component<PropsType, StateType> {
   state = {
-    repos: [] as RepoType[],
     loading: true,
     error: false,
   }
 
-  componentDidMount() {
-    let { currentProject } = this.context;
-
-    // Get repos
-    api.getGitRepos('<token>', {
-    }, { project_id: currentProject.id }, (err: any, res: any) => {
-      if (err) {
-        this.setState({ loading: false, error: true });
-      } else {
-        var allRepos: any = [];
-        for (let i = 0; i < res.data.length; i++) {
-          var grid = res.data[i].id;
-          api.getGitRepoList('<token>', {}, { project_id: currentProject.id, git_repo_id: grid }, (err: any, res: any) => {
-            if (err) {
-              console.log(err);
-              this.setState({ loading: false, error: true });
-            } else {
-              res.data.forEach((repo: any, id: number) => {
-                repo.GHRepoID = grid;
-              })
-              allRepos = allRepos.concat(res.data);
-              this.setState({ repos: allRepos, loading: false, error: false });
-            }
-          })
-        }
-        if (res.data.length < 1) {
-          this.setState({ loading: false, error: false });
-        }
-      }
-    });
-  }
-
-  setRepo = (x: RepoType) => {
-    let { actionConfig, setActionConfig } = this.props;
-    let updatedConfig = actionConfig;
-    updatedConfig.git_repo = x.FullName;
-    updatedConfig.git_repo_id = x.GHRepoID;
-    setActionConfig(updatedConfig);
-  }
-
-  renderRepoList = () => {
-    let { repos, loading, error } = this.state;
-    if (loading) {
-      return <LoadingWrapper><Loading /></LoadingWrapper>
-    } else if (error || !repos) {
-      return <LoadingWrapper>Error loading repos.</LoadingWrapper>
-    } else if (repos.length == 0) {
-      return <LoadingWrapper>No connected repos found.</LoadingWrapper>
-    }
-
-    return repos.map((repo: RepoType, i: number) => {
-      return (
-        <RepoName
-          key={i}
-          isSelected={repo.FullName === this.props.actionConfig.git_repo}
-          lastItem={i === repos.length - 1}
-          onClick={() => this.setRepo(repo)}
-        >
-          <img src={github} />{repo.FullName}
-        </RepoName>
-      );
-    });
-  }
-
   renderExpanded = () => {
     let {
       actionConfig,
@@ -110,7 +42,11 @@ export default class ActionConfEditor extends Component<PropsType, StateType> {
     if (!actionConfig.git_repo) {
       return (
         <ExpandedWrapper>
-          {this.renderRepoList()}
+          <RepoList
+            actionConfig={actionConfig}
+            setActionConfig={(x: ActionConfigType) => setActionConfig(x)}
+            readOnly={false}
+          />
         </ExpandedWrapper>
       );
     } else if (!branch) {
@@ -155,43 +91,6 @@ export default class ActionConfEditor extends Component<PropsType, StateType> {
 
 ActionConfEditor.contextType = Context;
 
-const RepoName = styled.div`
-  display: flex;
-  width: 100%;
-  font-size: 13px;
-  border-bottom: 1px solid ${(props: { lastItem: boolean, isSelected: boolean }) => props.lastItem ? '#00000000' : '#606166'};
-  color: #ffffff;
-  user-select: none;
-  align-items: center;
-  padding: 10px 0px;
-  cursor: pointer;
-  background: ${(props: { isSelected: boolean, lastItem: boolean }) => props.isSelected ? '#ffffff22' : '#ffffff11'};
-  :hover {
-    background: #ffffff22;
-
-    > i {
-      background: #ffffff22;
-    }
-  }
-
-  > img {
-    width: 18px;
-    height: 18px;
-    margin-left: 12px;
-    margin-right: 12px;
-  }
-`;
-
-const LoadingWrapper = styled.div`
-  padding: 30px 0px;
-  background: #ffffff11;
-  display: flex;
-  align-items: center;
-  font-size: 13px;
-  justify-content: center;
-  color: #ffffff44;
-`;
-
 const ExpandedWrapper = styled.div`
   margin-top: 10px;
   width: 100%;

+ 189 - 0
dashboard/src/components/repo-selector/RepoList.tsx

@@ -0,0 +1,189 @@
+import React, { Component } from 'react';
+import styled from 'styled-components';
+import github from '../../assets/github.png';
+
+import api from '../../shared/api';
+import { RepoType, ActionConfigType } from '../../shared/types';
+import { Context } from '../../shared/Context';
+
+import Loading from '../Loading';
+
+type PropsType = {
+  actionConfig: ActionConfigType | null,
+  setActionConfig: (x: ActionConfigType) => void,
+  readOnly: boolean,
+};
+
+type StateType = {
+  repos: RepoType[],
+  loading: boolean,
+  error: boolean,
+  height: number,
+};
+
+export default class ActionConfEditor extends Component<PropsType, StateType> {
+  state = {
+    repos: [] as RepoType[],
+    loading: true,
+    error: false,
+    height: window.innerHeight - 256,
+  }
+
+  componentDidMount() {
+    if (this.props.readOnly) {
+      window.addEventListener('resize', this.updateHeight.bind(this));
+    }
+
+    let { currentProject } = this.context;
+
+    // Get repos
+    api.getGitRepos('<token>', {
+    }, { project_id: currentProject.id }, (err: any, res: any) => {
+      if (err) {
+        this.setState({ loading: false, error: true });
+      } else {
+        var allRepos: any = [];
+        for (let i = 0; i < res.data.length; i++) {
+          var grid = res.data[i].id;
+          api.getGitRepoList('<token>', {}, { project_id: currentProject.id, git_repo_id: grid }, (err: any, res: any) => {
+            if (err) {
+              console.log(err);
+              this.setState({ loading: false, error: true });
+            } else {
+              res.data.forEach((repo: any, id: number) => {
+                repo.GHRepoID = grid;
+              })
+              allRepos = allRepos.concat(res.data);
+              this.setState({ repos: allRepos, loading: false, error: false });
+            }
+          })
+        }
+        if (res.data.length < 1) {
+          this.setState({ loading: false, error: false });
+        }
+      }
+    });
+  }
+
+  componentWillUnmount() {
+    if (this.props.readOnly) {
+      window.removeEventListener('resize', this.updateHeight.bind(this));
+    }
+  }
+
+  updateHeight = () => {
+    this.setState({ height: window.innerHeight - 256 });
+  }
+
+  setRepo = (x: RepoType) => {
+    let { actionConfig, setActionConfig } = this.props;
+    let updatedConfig = actionConfig;
+    updatedConfig.git_repo = x.FullName;
+    updatedConfig.git_repo_id = x.GHRepoID;
+    setActionConfig(updatedConfig);
+  }
+
+  renderRepoList = () => {
+    let { repos, loading, error } = this.state;
+    if (loading) {
+      return <LoadingWrapper><Loading /></LoadingWrapper>
+    } else if (error || !repos) {
+      return <LoadingWrapper>Error loading repos.</LoadingWrapper>
+    } else if (repos.length == 0) {
+      return <LoadingWrapper>No connected repos found.</LoadingWrapper>
+    }
+
+    return repos.map((repo: RepoType, i: number) => {
+      return (
+        <RepoName
+          key={i}
+          isSelected={repo.FullName === this.props.actionConfig.git_repo}
+          lastItem={i === repos.length - 1}
+          onClick={() => this.setRepo(repo)}
+          readOnly={this.props.readOnly}
+        >
+          <img src={github} />{repo.FullName}
+        </RepoName>
+      );
+    });
+  }
+
+  renderExpanded = () => {
+    if (this.props.readOnly) {
+      return (
+        <ExpandedWrapperAlt
+          heightLimit={this.state.height}
+        >
+          {this.renderRepoList()}
+        </ExpandedWrapperAlt>
+      );
+    } else {
+      return (
+        <ExpandedWrapper>
+          {this.renderRepoList()}
+        </ExpandedWrapper>
+      );
+    }
+  }
+
+  render() {
+    return (
+      <>
+        {this.renderExpanded()}
+      </>
+    );
+  }
+}
+
+ActionConfEditor.contextType = Context;
+
+const RepoName = styled.div`
+  display: flex;
+  width: 100%;
+  font-size: 13px;
+  border-bottom: 1px solid ${(props: { lastItem: boolean, isSelected: boolean, readOnly: boolean }) => props.lastItem ? '#00000000' : '#606166'};
+  color: #ffffff;
+  user-select: none;
+  align-items: center;
+  padding: 10px 0px;
+  cursor: ${(props: { lastItem: boolean, isSelected: boolean, readOnly: boolean }) => props.readOnly ? 'default' : 'pointer'};
+  pointer-events: ${(props: { lastItem: boolean, isSelected: boolean, readOnly: boolean }) => props.readOnly ? 'none' : 'auto'};
+  background: ${(props: { lastItem: boolean, isSelected: boolean, readOnly: boolean }) => props.isSelected ? '#ffffff22' : '#ffffff11'};
+  :hover {
+    background: #ffffff22;
+
+    > i {
+      background: #ffffff22;
+    }
+  }
+
+  > img {
+    width: 18px;
+    height: 18px;
+    margin-left: 12px;
+    margin-right: 12px;
+  }
+`;
+
+const LoadingWrapper = styled.div`
+  padding: 30px 0px;
+  background: #ffffff11;
+  display: flex;
+  align-items: center;
+  font-size: 13px;
+  justify-content: center;
+  color: #ffffff44;
+`;
+
+const ExpandedWrapper = styled.div`
+  width: 100%;
+  border-radius: 3px;
+  border: 0px solid #ffffff44;
+  max-height: 275px;
+`;
+
+const ExpandedWrapperAlt = styled(ExpandedWrapper)`
+  border: 1px solid #ffffff44;
+  max-height: ${(props: { heightLimit: number }) => props.heightLimit}px;
+  overflow-y: auto;
+`;

+ 2 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx

@@ -71,8 +71,9 @@ export default class SettingsSection extends Component<PropsType, StateType> {
       storage: StorageType.Secret
     }, { id: currentProject.id, name: this.props.currentChart.name }, (err: any, res: any) => {
       if (err) {
-        console.log(err)
+        console.log(err);
       } else {
+        console.log(res.data);
         this.setState({ action: res.data.git_action_config, webhookToken: res.data.webhook_token });
       }
     });

+ 2 - 1
dashboard/src/main/home/integrations/IntegrationList.tsx

@@ -46,7 +46,7 @@ export default class IntegrationList extends Component<PropsType, StateType> {
       return integrations.map((integration: string, i: number) => {
         let icon = integrationList[integration] && integrationList[integration].icon;
         let label = integrationList[integration] && integrationList[integration].label;
-        let disabled = integration === 'kubernetes' || integration === 'repo';
+        let disabled = integration === 'kubernetes';
         return (
           <Integration
             key={i}
@@ -63,6 +63,7 @@ export default class IntegrationList extends Component<PropsType, StateType> {
         );
       });
     }
+    console.log(integrations);
     return (
       <Placeholder>
         No integrations set up yet.

+ 71 - 32
dashboard/src/main/home/integrations/Integrations.tsx

@@ -4,10 +4,13 @@ import styled from 'styled-components';
 import { Context } from '../../../shared/Context';
 import api from '../../../shared/api';
 import { integrationList } from '../../../shared/common';
-import { ChoiceType } from '../../../shared/types';
+import { ActionConfigType } from '../../../shared/types';
 
 import IntegrationList from './IntegrationList';
 import IntegrationForm from './integration-form/IntegrationForm';
+import RepoList from '../../../components/repo-selector/RepoList';
+
+import GHIcon from '../../../assets/GithubIcon';
 
 type PropsType = {
 };
@@ -114,6 +117,7 @@ export default class Integrations extends Component<PropsType, StateType> {
   }
 
   renderContents = () => {
+    let { currentProject } = this.context;
     let { currentCategory, currentIntegration } = this.state;
 
     // TODO: Split integration page into separate component
@@ -145,37 +149,72 @@ export default class Integrations extends Component<PropsType, StateType> {
       let icon = integrationList[currentCategory] && integrationList[currentCategory].icon;
       let label = integrationList[currentCategory] && integrationList[currentCategory].label;
       let buttonText = integrationList[currentCategory] && integrationList[currentCategory].buttonText;
-      return (
-        <div>
-          <TitleSectionAlt>
-            <Flex>
-              <i className="material-icons" onClick={() => this.setState({ currentCategory: null })}>
-                keyboard_backspace
-              </i>
-              <Icon src={icon && icon} />
-              <Title>{label}</Title>
-            </Flex>
-
-            <Button 
-              onClick={() => this.context.setCurrentModal('IntegrationsModal', { 
-                category: currentCategory,
-                setCurrentIntegration: (x: string) => this.setState({ currentIntegration: x })
-              })}
-            >
-              <i className="material-icons">add</i>
-              {buttonText}
-            </Button>
-          </TitleSectionAlt>
-
-          <LineBreak />
-
-          <IntegrationList
-            integrations={this.state.currentOptions}
-            titles={this.state.currentTitles}
-            setCurrent={(x: string) => this.setState({ currentIntegration: x })}
-          />
-        </div>
-      );
+      if (currentCategory !== 'repo') {
+        return (
+          <div>
+            <TitleSectionAlt>
+              <Flex>
+                <i className="material-icons" onClick={() => this.setState({ currentCategory: null })}>
+                  keyboard_backspace
+                </i>
+                <Icon src={icon && icon} />
+                <Title>{label}</Title>
+              </Flex>
+              <Button 
+                onClick={() => this.context.setCurrentModal('IntegrationsModal', { 
+                  category: currentCategory,
+                  setCurrentIntegration: (x: string) => this.setState({ currentIntegration: x })
+                })}
+              >
+                <i className="material-icons">add</i>
+                {buttonText}
+              </Button>
+            </TitleSectionAlt>
+  
+            <LineBreak />
+  
+            <IntegrationList
+              integrations={this.state.currentOptions}
+              titles={this.state.currentTitles}
+              setCurrent={(x: string) => this.setState({ currentIntegration: x })}
+            />
+          </div>
+        );
+      } else {
+        return (
+          <div>
+            <TitleSectionAlt>
+              <Flex>
+                <i className="material-icons" onClick={() => this.setState({ currentCategory: null })}>
+                  keyboard_backspace
+                </i>
+                <Icon src={icon && icon} />
+                <Title>{label}</Title>
+              </Flex>
+              <Button 
+                onClick={() => window.open(`/api/oauth/projects/${currentProject.id}/github`)}
+              >
+                <GHIcon />
+                {buttonText}
+              </Button>
+            </TitleSectionAlt>
+  
+            <LineBreak />
+  
+            <RepoList
+              actionConfig={{
+                git_repo: '',
+                image_repo_uri: '',
+                git_repo_id: 0,
+                dockerfile_path: '',
+              } as ActionConfigType}
+              setActionConfig={(x: ActionConfigType) => {}}
+              readOnly={true}
+            />
+          </div>
+        );
+      }
+      
     }
     return (
       <div>

+ 19 - 18
dashboard/src/main/home/templates/expanded-template/LaunchTemplate.tsx

@@ -98,10 +98,6 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
     let name = this.state.templateName || randomWords({ exactly: 3, join: '-' });
     this.setState({ saveValuesStatus: 'loading' });
 
-    if (this.state.sourceType !== 'registry') {
-      this.createGHAction(name, this.state.selectedNamespace);
-    }
-
     let values = {};
     for (let key in wildcard) {
       _.set(values, key, wildcard[key]);
@@ -135,6 +131,10 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
           namespace: this.state.selectedNamespace,
           values: values,
         })
+
+        if (this.state.sourceType === 'repo') {
+          this.createGHAction(name, this.state.selectedNamespace);
+        }
       }
     });
   }
@@ -144,10 +144,6 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
     let name = this.state.templateName || randomWords({ exactly: 3, join: '-' });
     this.setState({ saveValuesStatus: 'loading' });
 
-    if (this.state.sourceType !== 'registry') {
-      this.createGHAction(name, this.state.selectedNamespace);
-    }
-
     // Convert dotted keys to nested objects
     let values = {};
     for (let key in rawValues) {
@@ -165,8 +161,15 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
       tag = 'latest';
     }
 
+    
+    if (this.state.sourceType === 'repo') {
+      imageUrl = 'hello-world';
+      tag = 'latest';
+    }
+
     _.set(values, "image.repository", imageUrl)
     _.set(values, "image.tag", tag)
+    console.log(values);
 
     api.deployTemplate('<token>', {
       templateName: this.props.currentTemplate.name,
@@ -197,6 +200,10 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
           namespace: this.state.selectedNamespace,
           values: values,
         })
+
+        if (this.state.sourceType === 'repo') {
+          this.createGHAction(name, this.state.selectedNamespace);
+        }
       }
     });
   }
@@ -337,16 +344,10 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
         return (
           <>
             <Subtitle>
-              Select the container image you would like to connect to this template
-              {false &&
-                <>
-                  or
-                  <Highlight onClick={() => this.setState({ sourceType: 'repo' })}>
-                    link a git repository
-                  </Highlight>
-                </>
-              } 
-              .
+              Select the container image you would like to connect to this template or
+              <Highlight onClick={() => this.setState({ sourceType: 'repo' })}>
+                link a git repository
+              </Highlight>.
               <Required>*</Required>
             </Subtitle>
             <DarkMatter />

+ 1 - 1
dashboard/src/shared/common.tsx

@@ -21,7 +21,7 @@ export const integrationList: any = {
   'repo': {
     icon: 'https://3.bp.blogspot.com/-xhNpNJJyQhk/XIe4GY78RQI/AAAAAAAAItc/ouueFUj2Hqo5dntmnKqEaBJR4KQ4Q2K3ACK4BGAYYCw/s1600/logo%2Bgit%2Bicon.png',
     label: 'Git Repository',
-    buttonText: 'Add a Repository',
+    buttonText: 'Link a Github Account',
   },
   'registry': {
     icon: 'https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/97_Docker_logo_logos-512.png',