Просмотр исходного кода

set + update kubeconfig integrated

jusrhee 5 лет назад
Родитель
Сommit
47c87e7cee

+ 1 - 0
cmd/migrate/main.go

@@ -25,6 +25,7 @@ func main() {
 	err = db.AutoMigrate(
 		&models.User{},
 		&models.ClusterConfig{},
+		&models.Session{},
 	)
 
 	if err != nil {

+ 122 - 0
dashboard/src/main/CurrentError.tsx

@@ -0,0 +1,122 @@
+import React, { Component } from 'react';
+import styled from 'styled-components';
+import close from '../assets/close.png';
+
+import { Context } from '../shared/Context';
+
+type PropsType = {
+};
+
+type StateType = {
+};
+
+export default class CurrentError extends Component<PropsType, StateType> {
+  state = {
+    expanded: false
+  }
+  
+  render() {
+    if (this.context.currentError) {
+      if (!this.state.expanded) {
+        return (
+          <StyledCurrentError onClick={() => this.setState({ expanded: true })}>
+            <ErrorText>Error: {this.context.currentError}</ErrorText>
+            <CloseButton onClick={(e) => {
+              this.context.setCurrentError(null);
+              e.stopPropagation();
+            }}>
+              <CloseButtonImg src={close} />
+            </CloseButton>
+          </StyledCurrentError>
+        );
+      }
+
+      return (
+        <ExpandedError onClick={() => this.setState({ expanded: false })}>
+          Error: {this.context.currentError}
+          <CloseButtonAlt onClick={() => this.context.setCurrentError(null)}>
+            <CloseButtonImg src={close} />
+          </CloseButtonAlt>
+        </ExpandedError>
+      );
+    }
+
+    return null;
+  }
+}
+
+CurrentError.contextType = Context;
+
+const CloseButton = styled.div`
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  margin-left: 10px;
+  cursor: pointer;
+  :hover {
+    background-color: #ffffff11;
+  }
+`;
+
+const CloseButtonAlt = styled(CloseButton)`
+  position: absolute;
+  top: 5px;
+  right: 5px;
+`;
+
+const CloseButtonImg = styled.img`
+  width: 10px;
+`;
+
+const ErrorText = styled.div`
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  width: calc(100% - 50px);
+`;
+
+const StyledCurrentError = styled.div`
+  position: fixed;
+  bottom: 20px;
+  width: 300px;
+  left: 17px;
+  padding: 15px;
+  padding-right: 0px;
+  font-family: 'Work Sans', sans-serif;
+  height: 50px;
+  font-size: 13px;
+  border-radius: 3px;
+  background: #383842dd;
+  border: 1px solid #ffffff55;
+  display: flex;
+  align-items: center;
+  color: #FFDB8C;
+
+  > i {
+    font-size: 18px;
+    margin-right: 10px;
+  }
+
+  animation: floatIn 0.5s;
+  animation-fill-mode: forwards;
+
+  @keyframes floatIn {
+    from {
+      opacity: 0; transform: translateY(20px);
+    }
+    to {
+      opacity: 1; transform: translateY(0px);
+    }
+  }
+`;
+
+const ExpandedError = styled(StyledCurrentError)`
+  width: 500px;
+  height: auto;
+  max-height: 300px;
+  padding: 20px;
+  overflow-y: auto;
+`;

+ 6 - 73
dashboard/src/main/Main.tsx

@@ -7,6 +7,7 @@ import { Context } from '../shared/Context';
 
 import Login from './Login';
 import Register from './Register';
+import CurrentError from './CurrentError';
 import Home from './home/Home';
 import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom';
 
@@ -42,18 +43,9 @@ export default class Main extends Component<PropsType, StateType> {
     this.setState({isLoggedIn: true, initialized: true});
     localStorage.setItem('init', 'true');
   }
-
-  renderCurrentError = (): JSX.Element | undefined => {
-    if (this.context.currentError) {
-      return (
-        <CurrentError>
-          <ErrorText>Error: {this.context.currentError}</ErrorText>
-          <CloseButton onClick={() => { this.context.setCurrentError(null) }}>
-            <CloseButtonImg src={close} />
-          </CloseButton>
-        </CurrentError>
-      );
-    }
+  
+  authenticate = () => {
+    this.setState({ isLoggedIn: true, initialized: true });
   }
 
   render() {
@@ -65,7 +57,7 @@ export default class Main extends Component<PropsType, StateType> {
           <Switch>
             <Route path='/login' render={() => {
               if (!this.state.isLoggedIn && this.state.initialized) {
-                return <Login authenticate={() => this.setState({ isLoggedIn: true, initialized: true })} />
+                return <Login authenticate={this.authenticate} />
               } else {
                 return <Redirect to='/' />
               }
@@ -98,7 +90,7 @@ export default class Main extends Component<PropsType, StateType> {
             }}/>
           </Switch>
         </BrowserRouter>
-        {this.renderCurrentError()}
+        <CurrentError />
       </StyledMain>
     );
   }
@@ -106,71 +98,12 @@ export default class Main extends Component<PropsType, StateType> {
 
 Main.contextType = Context;
 
-const CloseButton = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 30px;
-  height: 30px;
-  border-radius: 50%;
-  margin-left: 10px;
-  cursor: pointer;
-  :hover {
-    background-color: #ffffff11;
-  }
-`;
-
-const CloseButtonImg = styled.img`
-  width: 10px;
-`;
-
 const GlobalStyle = createGlobalStyle`
   * {
     box-sizing: border-box;
   }
 `;
 
-const ErrorText = styled.div`
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  width: calc(100% - 50px);
-`;
-
-const CurrentError = styled.div`
-  position: fixed;
-  bottom: 20px;
-  width: 300px;
-  left: 17px;
-  padding: 15px;
-  padding-right: 0px;
-  font-family: 'Work Sans', sans-serif;
-  height: 50px;
-  font-size: 13px;
-  border-radius: 3px;
-  background: #383842dd;
-  border: 1px solid #ffffff55;
-  display: flex;
-  align-items: center;
-
-  > i {
-    font-size: 18px;
-    margin-right: 10px;
-  }
-
-  animation: floatIn 0.5s;
-  animation-fill-mode: forwards;
-
-  @keyframes floatIn {
-    from {
-      opacity: 0; transform: translateY(20px);
-    }
-    to {
-      opacity: 1; transform: translateY(0px);
-    }
-  }
-`;
-
 const StyledMain = styled.div`
   height: 100vh;
   width: 100vw;

+ 36 - 26
dashboard/src/main/home/modals/ClusterConfigModal.tsx

@@ -32,36 +32,40 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
   };
   
   updateChecklist = () => {
-    let { setCurrentError } = this.context;
+    let { setCurrentError, userId } = this.context;
 
     // Parse kubeconfig to retrieve all possible clusters
-    api.getAllClusters('<token>', {}, { id: 0 }, (err: any, res: any) => {
+    api.getAllClusters('<token>', {}, { id: userId }, (err: any, res: any) => {
       if (err) {
-        setCurrentError(JSON.stringify(err));
+        setCurrentError('getAllClusters: ' + JSON.stringify(err));
       } else {
-        let clusters = res.data.clusters;
+        let clusters = res.data;
         this.setState({ clusters });
 
-        // Check against list of connected clusters
-        api.getClusters('<token>', {}, { id: 0 }, (err: any, res: any) => {
-          if (err) {
-            setCurrentError(JSON.stringify(err));
-          } else {
-            let selected = clusters.map((x: ClusterConfig) => res.data.clusters.includes(x));
-            this.setState({ selected });
-          }
-        });
+        if (clusters && clusters.length > 0) {
+          
+          // Check against list of connected clusters
+          api.getClusters('<token>', {}, { id: userId }, (err: any, res: any) => {
+            if (err) {
+              setCurrentError('getClusters: ' + JSON.stringify(err));
+            } else {
+              console.log(res)
+              let selected = clusters.map((x: ClusterConfig) => res.data.includes(x));
+              this.setState({ selected });
+            }
+          });
+        }
       }
     });
   }
 
   componentDidMount() {
-    let { setCurrentError } = this.context;
+    let { setCurrentError, userId } = this.context;
 
-    api.getUser('<token>', {}, { id: 0 }, (err: any, res: any) => {      
+    api.getUser('<token>', {}, { id: userId }, (err: any, res: any) => {
       if (err) {
-        setCurrentError(JSON.stringify(err));
-      } else {
+        setCurrentError('getUser: ' + JSON.stringify(err));
+      } else if (res.data.rawKubeConfig !== '') {
         this.setState({ rawKubeconfig: res.data.rawKubeConfig });
       }
     });
@@ -82,11 +86,13 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
   };
 
   renderClusterList = (): JSX.Element[] | JSX.Element => {
-    if (this.state.clusters.length > 0) {
-      return this.state.clusters.map((cluster: ClusterConfig, i) => {
+    let { clusters, selected } = this.state;
+
+    if (clusters && clusters.length > 0) {
+      return clusters.map((cluster: ClusterConfig, i) => {
         return (
           <Row key={i} onClick={() => this.toggleCluster(i)}>
-            <Checkbox checked={this.state.selected[i]}>
+            <Checkbox checked={selected[i]}>
               <i className="material-icons">done</i>
             </Checkbox>
             {cluster.name}
@@ -108,12 +114,13 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
 
   handleSaveKubeconfig = () => {
     let { rawKubeconfig } = this.state;
+    let { userId } = this.context;
 
     this.setState({ saveKubeconfigStatus: 'loading' });
     api.updateUser(
       '<token>',
-      { rawKubeconfig },
-      { id: 0 },
+      { rawKubeConfig: rawKubeconfig },
+      { id: userId },
       (err: any, res: any) => {
         if (err) {
           this.setState({ saveKubeconfigStatus: 'error' });
@@ -130,10 +137,10 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
   }
 
   handleSaveSelected = () => {
-    let { clusters, selected } = this.state;
+    let { clusters, selected, rawKubeconfig } = this.state;
+    let { userId } = this.context;
 
     this.setState({ saveSelectedStatus: 'loading' });
-
     let allowedClusters: string[] = [];
     clusters.forEach((x, i) => {
       if (selected[i]) {
@@ -141,10 +148,12 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
       }
     });
 
+    console.log(allowedClusters);
+
     api.updateUser(
       '<token>',
-      { allowedClusters },
-      { id: 0 },
+      { rawKubeConfig: rawKubeconfig, allowedClusters },
+      { id: userId },
       (err: any, res: any) => {
         if (err) {
           this.setState({ saveSelectedStatus: 'error' });
@@ -183,6 +192,7 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
           text='Save Selected'
           disabled={this.state.clusters.length === 0}
           onClick={this.handleSaveSelected}
+          status={this.state.saveSelectedStatus}
         />
       </div>
     )

+ 3 - 7
dashboard/src/main/home/sidebar/ClusterSection.tsx

@@ -54,17 +54,13 @@ export default class ClusterSection extends Component<PropsType, StateType> {
   };
 
   componentDidMount() {
-    console.log(process.env.API_SERVER);
-    // TODO: remove
-    // this.setState({ clusters: dummyClusters });
+    let { setCurrentError, userId } = this.context;
 
-    let { setCurrentError } = this.context;
-
-    api.getClusters('<token>', {}, { id: 0 }, (err: any, res: any) => {      
+    api.getClusters('<token>', {}, { id: userId }, (err: any, res: any) => {      
       if (err) {
         setCurrentError(JSON.stringify(err));
       } else {
-        this.setState({ clusters: res.data.clusters });
+        this.setState({ clusters: res.data });
       }
     });
   }

+ 9 - 1
dashboard/src/shared/Context.tsx

@@ -36,9 +36,17 @@ class ContextProvider extends Component {
     currentCluster: null as string | null,
     setCurrentCluster: (currentCluster: string): void => {
       this.setState({ currentCluster });
-    }
+    },
+    userId: null as number | null,
+    setUserId: (userId: number): void => {
+      this.setState({ userId });
+    },
   };
 
+  componentDidMount() {
+    this.setState({ userId: 1 });
+  }
+
   render() {
     return (
       <Provider value={this.state}>{this.props.children}</Provider>

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

@@ -28,7 +28,7 @@ const getUser = baseApi<{}, { id: number }>('GET', pathParams => {
 });
 
 const updateUser = baseApi<{
-  rawKubeconfig?: string,
+  rawKubeConfig?: string,
   allowedClusters?: string[]
 }, { id: number }>('PUT', pathParams => {
   return `/api/users/${pathParams.id}`;

+ 2 - 2
dashboard/src/shared/baseApi.tsx

@@ -20,7 +20,7 @@ export const baseApi = <T extends {}, S = {}>(requestType: string, endpoint: ((p
         }
       })
       .then(res => {
-        callback && callback(null, res.data);
+        callback && callback(null, res);
       })
       .catch(err => {
         callback && callback(err, null);
@@ -32,7 +32,7 @@ export const baseApi = <T extends {}, S = {}>(requestType: string, endpoint: ((p
         }
       })
       .then(res => {
-        callback && callback(null, res.data);
+        callback && callback(null, res);
       })
       .catch(err => {
         callback && callback(err, null);