jusrhee 5 лет назад
Родитель
Сommit
70c7e0f533

+ 32 - 0
dashboard/package-lock.json

@@ -4297,6 +4297,11 @@
         "negotiator": "0.6.2"
       }
     },
+    "ace-builds": {
+      "version": "1.4.12",
+      "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz",
+      "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
+    },
     "acorn": {
       "version": "7.4.0",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
@@ -6642,6 +6647,11 @@
         "debug": "^2.6.0"
       }
     },
+    "diff-match-patch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+      "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
+    },
     "diff-sequences": {
       "version": "24.9.0",
       "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz",
@@ -9955,6 +9965,16 @@
       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
       "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
     },
+    "lodash.get": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+      "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+    },
+    "lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+    },
     "lodash.memoize": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -12458,6 +12478,18 @@
         "prop-types": "^15.6.2"
       }
     },
+    "react-ace": {
+      "version": "9.1.3",
+      "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-9.1.3.tgz",
+      "integrity": "sha512-1TZBs/9hFGgPuzu6DUiBogyhRA5Z1Po2wzPfZslbrTFGQtbNe+JXHuPoJNlUu/uerElzOLLsuJEDTO9FfLnZJA==",
+      "requires": {
+        "ace-builds": "^1.4.6",
+        "diff-match-patch": "^1.0.4",
+        "lodash.get": "^4.4.2",
+        "lodash.isequal": "^4.5.0",
+        "prop-types": "^15.7.2"
+      }
+    },
     "react-app-polyfill": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.6.tgz",

+ 2 - 0
dashboard/package.json

@@ -12,7 +12,9 @@
     "@types/react-dom": "^16.9.8",
     "@types/react-modal": "^3.10.6",
     "@types/styled-components": "^5.1.3",
+    "ace-builds": "^1.4.12",
     "react": "^16.13.1",
+    "react-ace": "^9.1.3",
     "react-dom": "^16.13.1",
     "react-modal": "^3.11.2",
     "react-scripts": "3.4.3",

+ 74 - 0
dashboard/src/lib/YamlEditor.jsx

@@ -0,0 +1,74 @@
+import React from 'react';
+import styled from 'styled-components';
+import AceEditor from 'react-ace';
+
+import 'ace-builds/src-noconflict/mode-yaml';
+import 'ace-builds/src-noconflict/theme-monokai';
+
+class YamlEditor extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      yaml: ``,
+    }
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSubmit = this.handleSubmit.bind(this);
+  }
+
+  // Uses the yaml-lint library to determine if a given string is valid yaml.
+  // If the code is invalid, it returns an error message detailing what went wrong.
+  checkYaml = (y) => {
+    /*
+    yamlLint.lint(y).then(() => {
+      alert('Valid YAML file.');
+    }).catch((error) => {
+      alert(error.message);
+    });
+    */
+  }
+
+  // Calls checkYaml and passes in the value from the textarea
+  handleChange = (e) => {
+    this.setState({ yaml: e });
+  }
+  handleSubmit = (e) => {
+    this.checkYaml(this.state.yaml);
+    e.preventDefault();
+  }
+
+  render() {
+    return (
+      <Holder>
+        <Editor onSubmit={this.handleSubmit}>
+          <AceEditor
+            mode='yaml'
+            theme='monokai'
+            onChange={this.handleChange}
+            name='codeEditor'
+            editorProps={{ $blockScrolling: true }}
+            width='100%'
+            defaultValue={`# If you are using certificate files, include those explicitly`}
+            style={{ 
+              borderRadius: '5px',
+            }}
+          />
+        </Editor>
+      </Holder>
+    );
+  }
+}
+
+export default YamlEditor;
+
+const Editor = styled.form`
+  margin-top: 0px;
+  margin-bottom: 12px;
+  width: calc(100% - 0px);
+  border-radius: 5px;
+  border: 1px solid #ffffff22;
+  height: 295px;
+  overflow: auto;
+`;
+
+const Holder = styled.div`
+`;

+ 38 - 9
dashboard/src/main/home/modals/ClusterConfigModal.tsx

@@ -4,6 +4,7 @@ import { textChangeRangeIsUnchanged } from 'typescript';
 import close from '../../../assets/close.png';
 
 import { Context } from '../../../Context';
+import YamlEditor from '../../../lib/YamlEditor';
 
 type PropsType = {
 };
@@ -23,24 +24,17 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
     }
   }
   
-  /*
   renderTabContents = () => {
     if (this.state.currentTab === 'kubeconfig') {
       return (
         <div>
           <Subtitle>Copy and paste your kubeconfig below.</Subtitle>
-          <ImageList>
-            {this.renderImageList(images)}
-            {this.renderCustomImageList()}
-          </ImageList>
-          <Footer>
-            <SaveButton />
-          </Footer>
+          <YamlEditor />
+          <Button>Save Kubeconfig</Button>
         </div>
       )
     }
   }
-  */
 
   render() {
     return (
@@ -64,6 +58,7 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
             {this.renderLine('select')}
           </Tab>
         </TabSelector>
+        {this.renderTabContents()}
       </StyledClusterConfigModal>
     );
   }
@@ -71,6 +66,40 @@ export default class ClusterConfigModal extends Component<PropsType, StateType>
 
 ClusterConfigModal.contextType = Context;
 
+const Button = styled.button`
+  position: absolute;
+  bottom: 25px;
+  right: 27px;
+  height: 40px;
+  font-size: 13px;
+  font-weight: 500;
+  font-family: 'Work Sans', sans-serif;
+  color: white;
+  padding: 6px 20px 7px 20px;
+  text-align: left;
+  border: 0;
+  border-radius: 5px;
+  background: ${(props) => (!props.disabled ? '#616FEEcc' : '#ddd')};
+  box-shadow: ${(props) => (!props.disabled ? '0 2px 5px 0 #00000030' : 'none')};
+  cursor: ${(props) => (!props.disabled ? 'pointer' : 'default')};
+  user-select: none;
+  :focus { outline: 0 }
+  :hover {
+    background: ${(props) => (!props.disabled ? '#616FEEff' : '#ddd')};
+  }
+`;
+
+const Subtitle = styled.div`
+  padding: 15px 0px;
+  font-family: 'Work Sans', sans-serif;
+  font-size: 13px;
+  color: #aaa;
+  margin-top: 8px;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+`;
+
 const Highlight = styled.div`
   width: 80%;
   height: 1px;