Merge pull request #14 from bitnine-oss/@feature/edge-thickness

@feature/edge thickness
diff --git a/frontend/src/components/contents/presentations/Editor.jsx b/frontend/src/components/contents/presentations/Editor.jsx
index 4ed1912..e86eb79 100644
--- a/frontend/src/components/contents/presentations/Editor.jsx
+++ b/frontend/src/components/contents/presentations/Editor.jsx
@@ -1,200 +1,200 @@
-/*
- * Copyright 2020 Bitnine Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import React, { useEffect, useState } from 'react';
-import { useDispatch } from 'react-redux';
-import uuid from 'react-uuid';
-import PropTypes from 'prop-types';
-import AlertContainers from '../../alert/containers/AlertContainers';
-import CodeMirror from '../../editor/containers/CodeMirrorWapperContainer';
-import SideBarToggle from '../../editor/containers/SideBarMenuToggleContainer';
-
-const Editor = ({
-  setCommand,
-  command,
-  addFrame,
-  trimFrame,
-  addAlert,
-  alertList,
-  isActive,
-  database,
-  executeCypherQuery,
-  addCommandHistory,
-  toggleMenu,
-  // addCommandFavorites,
-}) => {
-  const dispatch = useDispatch();
-  const [alerts, setAlerts] = useState([]);
-
-  // const favoritesCommand = () => {
-  //   dispatch(() => addCommandFavorites(command));
-  // };
-
-  const clearCommand = () => {
-    setCommand('');
-  };
-
-  const onClick = () => {
-    const refKey = uuid();
-    if (command.toUpperCase().startsWith(':PLAY')) {
-      dispatch(() => addFrame(command, 'Contents', refKey));
-    } else if (command.toUpperCase() === ':SERVER STATUS') {
-      dispatch(() => trimFrame('ServerStatus'));
-      dispatch(() => addFrame(command, 'ServerStatus', refKey));
-    } else if (database.status === 'disconnected' && command.toUpperCase() === ':SERVER DISCONNECT') {
-      dispatch(() => trimFrame('ServerDisconnect'));
-      dispatch(() => trimFrame('ServerConnect'));
-      dispatch(() => addAlert('ErrorNoDatabaseConnected'));
-      dispatch(() => addFrame(command, 'ServerDisconnect', refKey));
-    } else if (database.status === 'disconnected' && command.toUpperCase() === ':SERVER CONNECT') {
-      dispatch(() => trimFrame('ServerConnect'));
-      dispatch(() => addFrame(':server connect', 'ServerConnect'));
-    } else if (database.status === 'disconnected' && command.toUpperCase().match('(MATCH|CREATE).*')) {
-      dispatch(() => trimFrame('ServerConnect'));
-      dispatch(() => addAlert('ErrorNoDatabaseConnected'));
-      dispatch(() => addFrame(command, 'ServerConnect', refKey));
-    } else if (database.status === 'connected' && command.toUpperCase() === ':SERVER DISCONNECT') {
-      dispatch(() => trimFrame('ServerDisconnect'));
-      dispatch(() => addAlert('NoticeServerDisconnected'));
-      dispatch(() => addFrame(command, 'ServerDisconnect', refKey));
-    } else if (database.status === 'connected' && command.toUpperCase() === ':SERVER CONNECT') {
-      dispatch(() => trimFrame('ServerStatus'));
-      dispatch(() => addAlert('NoticeAlreadyConnected'));
-      dispatch(() => addFrame(command, 'ServerStatus', refKey));
-    } else if (database.status === 'connected') {
-      const reqStringValue = command;
-      dispatch(() => executeCypherQuery([refKey, reqStringValue]).then((response) => {
-        if (response.type === 'cypher/executeCypherQuery/fulfilled') {
-          addFrame(reqStringValue, 'CypherResultFrame', refKey);
-        } else if (response.type === 'cypher/executeCypherQuery/rejected') {
-          addFrame(reqStringValue, 'CypherResultFrame', refKey);
-          dispatch(() => addAlert('ErrorCypherQuery'));
-        }
-      }));
-    }
-    dispatch(() => addCommandHistory(command));
-    clearCommand();
-  };
-
-  useEffect(() => {
-    setAlerts(
-      alertList.map((alert) => (
-        <AlertContainers
-          key={alert.alertProps.key}
-          alertKey={alert.alertProps.key}
-          alertName={alert.alertName}
-          errorMessage={alert.alertProps.errorMessage}
-        />
-      )),
-    );
-  }, [alertList]);
-
-  return (
-    <div className="container-fluid">
-      <div className="editor">
-        <div className="container-fluid editor-area card-header">
-          <div className="input-group input-style">
-            <div style={{
-              height: '60px',
-              width: '60px',
-              color: '#ffffff',
-              textAlign: 'left',
-              lineHeight: '30px',
-            }}
-            >
-              <spna>
-                Query
-                <br />
-                Editor
-              </spna>
-            </div>
-            <div className="form-control col-11 editor-code-wrapper">
-              <CodeMirror
-                onClick={onClick}
-                value={command}
-                onChange={setCommand}
-              />
-            </div>
-            <div className="input-group-append ml-auto editor-button-wrapper" id="editor-buttons">
-              {/* <button className="frame-head-button btn btn-link"
-               type="button" onClick={() => favoritesCommand()}>
-                <FontAwesomeIcon
-                  icon={faStar}
-                  size="lg"
-                />
-              </button> */}
-              <button className={command ? 'btn show-eraser' : 'btn hide-eraser'} type="button" id="eraser" onClick={() => clearCommand()}>
-                <i className="icon-eraser" />
-              </button>
-              <button
-                className="frame-head-button btn btn-link"
-                type="button"
-                onClick={() => onClick()}
-                title="Run Query"
-              >
-                <i className="icon-play" />
-              </button>
-              <button
-                className="frame-head-button btn btn-link"
-                type="button"
-                onClick={() => {
-                  toggleMenu('home');
-                  if (!isActive) {
-                    document.getElementById('wrapper').classList.remove('wrapper');
-                    document.getElementById('wrapper').classList.add('wrapper-extension-padding');
-                  } else {
-                    document.getElementById('wrapper').classList.remove('wrapper-extension-padding');
-                    document.getElementById('wrapper').classList.add('wrapper');
-                  }
-                }}
-                title={(isActive) ? 'Hide' : 'Show'}
-              >
-                <SideBarToggle isActive={isActive} />
-              </button>
-            </div>
-          </div>
-        </div>
-      </div>
-      {alerts}
-    </div>
-  );
-};
-
-Editor.propTypes = {
-  setCommand: PropTypes.func.isRequired,
-  command: PropTypes.string.isRequired,
-  addFrame: PropTypes.func.isRequired,
-  trimFrame: PropTypes.func.isRequired,
-  addAlert: PropTypes.func.isRequired,
-  alertList: PropTypes.arrayOf(PropTypes.shape({
-    alertName: PropTypes.string.isRequired,
-    alertProps: PropTypes.shape({
-      key: PropTypes.string.isRequired,
-      alertType: PropTypes.string.isRequired,
-      errorMessage: PropTypes.string.isRequired,
-    }),
-  })).isRequired,
-  isActive: PropTypes.bool.isRequired,
-  database: PropTypes.shape({
-    status: PropTypes.string.isRequired,
-  }).isRequired,
-  executeCypherQuery: PropTypes.func.isRequired,
-  addCommandHistory: PropTypes.func.isRequired,
-  toggleMenu: PropTypes.func.isRequired,
-  // addCommandFavorites: PropTypes.func.isRequired,
-};
-
-export default Editor;
+/*

+ * Copyright 2020 Bitnine Co., Ltd.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+import React, { useEffect, useState } from 'react';

+import { useDispatch } from 'react-redux';

+import uuid from 'react-uuid';

+import PropTypes from 'prop-types';

+import AlertContainers from '../../alert/containers/AlertContainers';

+import CodeMirror from '../../editor/containers/CodeMirrorWapperContainer';

+import SideBarToggle from '../../editor/containers/SideBarMenuToggleContainer';

+

+const Editor = ({

+  setCommand,

+  command,

+  addFrame,

+  trimFrame,

+  addAlert,

+  alertList,

+  isActive,

+  database,

+  executeCypherQuery,

+  addCommandHistory,

+  toggleMenu,

+  // addCommandFavorites,

+}) => {

+  const dispatch = useDispatch();

+  const [alerts, setAlerts] = useState([]);

+

+  // const favoritesCommand = () => {

+  //   dispatch(() => addCommandFavorites(command));

+  // };

+

+  const clearCommand = () => {

+    setCommand('');

+  };

+

+  const onClick = () => {

+    const refKey = uuid();

+    if (command.toUpperCase().startsWith(':PLAY')) {

+      dispatch(() => addFrame(command, 'Contents', refKey));

+    } else if (command.toUpperCase() === ':SERVER STATUS') {

+      dispatch(() => trimFrame('ServerStatus'));

+      dispatch(() => addFrame(command, 'ServerStatus', refKey));

+    } else if (database.status === 'disconnected' && command.toUpperCase() === ':SERVER DISCONNECT') {

+      dispatch(() => trimFrame('ServerDisconnect'));

+      dispatch(() => trimFrame('ServerConnect'));

+      dispatch(() => addAlert('ErrorNoDatabaseConnected'));

+      dispatch(() => addFrame(command, 'ServerDisconnect', refKey));

+    } else if (database.status === 'disconnected' && command.toUpperCase() === ':SERVER CONNECT') {

+      dispatch(() => trimFrame('ServerConnect'));

+      dispatch(() => addFrame(':server connect', 'ServerConnect'));

+    } else if (database.status === 'disconnected' && command.toUpperCase().match('(MATCH|CREATE).*')) {

+      dispatch(() => trimFrame('ServerConnect'));

+      dispatch(() => addAlert('ErrorNoDatabaseConnected'));

+      dispatch(() => addFrame(command, 'ServerConnect', refKey));

+    } else if (database.status === 'connected' && command.toUpperCase() === ':SERVER DISCONNECT') {

+      dispatch(() => trimFrame('ServerDisconnect'));

+      dispatch(() => addAlert('NoticeServerDisconnected'));

+      dispatch(() => addFrame(command, 'ServerDisconnect', refKey));

+    } else if (database.status === 'connected' && command.toUpperCase() === ':SERVER CONNECT') {

+      dispatch(() => trimFrame('ServerStatus'));

+      dispatch(() => addAlert('NoticeAlreadyConnected'));

+      dispatch(() => addFrame(command, 'ServerStatus', refKey));

+    } else if (database.status === 'connected') {

+      const reqStringValue = command;

+      dispatch(() => executeCypherQuery([refKey, reqStringValue]).then((response) => {

+        if (response.type === 'cypher/executeCypherQuery/fulfilled') {

+          addFrame(reqStringValue, 'CypherResultFrame', refKey);

+        } else if (response.type === 'cypher/executeCypherQuery/rejected') {

+          addFrame(reqStringValue, 'CypherResultFrame', refKey);

+          dispatch(() => addAlert('ErrorCypherQuery'));

+        }

+      }));

+    }

+    dispatch(() => addCommandHistory(command));

+    clearCommand();

+  };

+

+  useEffect(() => {

+    setAlerts(

+      alertList.map((alert) => (

+        <AlertContainers

+          key={alert.alertProps.key}

+          alertKey={alert.alertProps.key}

+          alertName={alert.alertName}

+          errorMessage={alert.alertProps.errorMessage}

+        />

+      )),

+    );

+  }, [alertList]);

+

+  return (

+    <div className="container-fluid">

+      <div className="editor">

+        <div className="container-fluid editor-area card-header">

+          <div className="input-group input-style">

+            <div style={{

+              height: '60px',

+              width: '60px',

+              color: '#ffffff',

+              textAlign: 'left',

+              lineHeight: '30px',

+            }}

+            >

+              <span>

+                Query

+                <br />

+                Editor

+              </span>

+            </div>

+            <div className="form-control col-11 editor-code-wrapper">

+              <CodeMirror

+                onClick={onClick}

+                value={command}

+                onChange={setCommand}

+              />

+            </div>

+            <div className="input-group-append ml-auto editor-button-wrapper" id="editor-buttons">

+              {/* <button className="frame-head-button btn btn-link"

+               type="button" onClick={() => favoritesCommand()}>

+                <FontAwesomeIcon

+                  icon={faStar}

+                  size="lg"

+                />

+              </button> */}

+              <button className={command ? 'btn show-eraser' : 'btn hide-eraser'} type="button" id="eraser" onClick={() => clearCommand()}>

+                <i className="icon-eraser" />

+              </button>

+              <button

+                className="frame-head-button btn btn-link"

+                type="button"

+                onClick={() => onClick()}

+                title="Run Query"

+              >

+                <i className="icon-play" />

+              </button>

+              <button

+                className="frame-head-button btn btn-link"

+                type="button"

+                onClick={() => {

+                  toggleMenu('home');

+                  if (!isActive) {

+                    document.getElementById('wrapper').classList.remove('wrapper');

+                    document.getElementById('wrapper').classList.add('wrapper-extension-padding');

+                  } else {

+                    document.getElementById('wrapper').classList.remove('wrapper-extension-padding');

+                    document.getElementById('wrapper').classList.add('wrapper');

+                  }

+                }}

+                title={(isActive) ? 'Hide' : 'Show'}

+              >

+                <SideBarToggle isActive={isActive} />

+              </button>

+            </div>

+          </div>

+        </div>

+      </div>

+      {alerts}

+    </div>

+  );

+};

+

+Editor.propTypes = {

+  setCommand: PropTypes.func.isRequired,

+  command: PropTypes.string.isRequired,

+  addFrame: PropTypes.func.isRequired,

+  trimFrame: PropTypes.func.isRequired,

+  addAlert: PropTypes.func.isRequired,

+  alertList: PropTypes.arrayOf(PropTypes.shape({

+    alertName: PropTypes.string.isRequired,

+    alertProps: PropTypes.shape({

+      key: PropTypes.string.isRequired,

+      alertType: PropTypes.string.isRequired,

+      errorMessage: PropTypes.string.isRequired,

+    }),

+  })).isRequired,

+  isActive: PropTypes.bool.isRequired,

+  database: PropTypes.shape({

+    status: PropTypes.string.isRequired,

+  }).isRequired,

+  executeCypherQuery: PropTypes.func.isRequired,

+  addCommandHistory: PropTypes.func.isRequired,

+  toggleMenu: PropTypes.func.isRequired,

+  // addCommandFavorites: PropTypes.func.isRequired,

+};

+

+export default Editor;

diff --git a/frontend/src/components/cypherresult/components/EdgeThicknessMenu.jsx b/frontend/src/components/cypherresult/components/EdgeThicknessMenu.jsx
new file mode 100644
index 0000000..40839ba
--- /dev/null
+++ b/frontend/src/components/cypherresult/components/EdgeThicknessMenu.jsx
@@ -0,0 +1,115 @@
+/* eslint-disable react/prop-types */
+/* eslint-disable no-unused-vars */
+import React, { useState, useEffect } from 'react';
+import {
+  Modal, Select, Input, Button,
+} from 'antd';
+import style from './popover.module.scss';
+
+const EdgeThicknessSettingModal = ({
+  onSubmit,
+  properties,
+}) => {
+  const [standardEdge, setStdEdge] = useState('');
+  const [standardProperty, setStdProperty] = useState('');
+  const [MinValue, setMinValue] = useState('');
+  const [MaxValue, setMaxValue] = useState('');
+
+  useEffect(() => {
+    if (standardEdge === '') setStdProperty('');
+  }, [standardEdge]);
+
+  const selectionEdge = () => {
+    const edgeList = new Set(properties.map((p) => p.edge));
+    return Array.from(edgeList).map((edge) => (
+      <>
+        <option className={style.option} value={edge}>
+          {edge}
+        </option>
+      </>
+    ));
+  };
+
+  const selectionPropertie = () => {
+    const propertyList = new Set(
+      properties.map((p) => (p.edge === standardEdge ? p.property : undefined)),
+    );
+    return Array.from(propertyList).map((property) => (
+      property
+        ? (
+          <>
+            <option className={style.option} value={property}>
+              {property}
+            </option>
+          </>
+        )
+        : <></>
+    ));
+  };
+
+  const apply = () => {
+    const thickness = {
+      edge: standardEdge,
+      property: standardProperty,
+      min: MinValue,
+      max: MaxValue,
+    };
+    onSubmit(thickness);
+  };
+
+  const reset = () => {
+    onSubmit(null);
+    setStdEdge('');
+    setStdProperty('');
+    setMinValue('');
+    setMaxValue('');
+  };
+
+  return (
+    <div style={{ width: '370px' }}>
+      <p className={style.title}>Apply Edge Weight</p>
+      <select
+        className={`${standardEdge === '' ? style.default : style.select}`}
+        defaultValue={null}
+        value={standardEdge}
+        onChange={(e) => setStdEdge(e.target.value)}
+        style={{ width: '95%' }}
+      >
+        <option className={`${style.option}`} value="">Select Edge</option>
+        {selectionEdge()}
+      </select>
+      <select
+        className={`${standardProperty === '' ? style.default : style.select}`}
+        defaultValue={null}
+        value={standardProperty}
+        onChange={(e) => setStdProperty(e.target.value)}
+        style={{ width: '95%' }}
+      >
+        <option className={`${style.option}`} value="">Select Node</option>
+        {selectionPropertie()}
+      </select>
+      <input
+        className={style.input}
+        value={MinValue}
+        onChange={(e) => {
+          if (Number(e.target.value) || e.target.value === '' || e.target.value === '0') setMinValue(Number(e.target.value));
+        }}
+        placeholder="Min Value"
+      />
+      <input
+        className={style.input}
+        value={MaxValue}
+        onChange={(e) => {
+          if (Number(e.target.value) || e.target.value === '' || e.target.value === '0') setMaxValue(Number(e.target.value));
+        }}
+        placeholder="Max Value"
+      />
+      <div className={style.buttons}>
+        <button className={style.btn} type="button" onClick={() => reset()}>Reset</button>
+        <button className={style.btn} type="button" onClick={() => apply()}>Apply</button>
+      </div>
+    </div>
+  );
+};
+
+export default EdgeThicknessSettingModal;
diff --git a/frontend/src/components/cypherresult/components/GraphFilterModal.jsx b/frontend/src/components/cypherresult/components/GraphFilterModal.jsx
index e6615f8..5e0e834 100644
--- a/frontend/src/components/cypherresult/components/GraphFilterModal.jsx
+++ b/frontend/src/components/cypherresult/components/GraphFilterModal.jsx
@@ -107,7 +107,7 @@
             onChange={(value) => {
               filterList[index].property = value;
             }}
-            style={{ minWidth: 120 }}
+            style={{ minWidth: 300 }}
           >
             <Select.Option value={null} disabled>Select</Select.Option>
             {propertyElements}
@@ -135,7 +135,7 @@
     );
   }, [propertyElements, filterList]);
   return (
-    <Modal title="Filter on Graph" visible={visible} onOk={onOk} onCancel={() => setVisible(false)}>
+    <Modal title="Filter on Graph" visible={visible} onOk={onOk} onCancel={() => setVisible(false)} width={800}>
       {
         filterElements
       }
diff --git a/frontend/src/components/cypherresult/components/popover.module.scss b/frontend/src/components/cypherresult/components/popover.module.scss
new file mode 100644
index 0000000..458d44d
--- /dev/null
+++ b/frontend/src/components/cypherresult/components/popover.module.scss
@@ -0,0 +1,72 @@
+.title {
+  font-size: 18px;
+  font-weight: bold;
+}
+.input {
+  width: 100%;
+  height: 48px;
+  background: #F8F9FA 0% 0% no-repeat padding-box !important;
+  border-radius: 5px !important;
+  opacity: 1 !important;
+  border: none;
+  margin: 5px 0px 5px 0px;
+  color: #2756FF;
+}
+.input:hover {
+  border: 1px solid #2756FF;
+}
+.input:focus {
+  border: 1px solid #2756FF;
+}
+.select {
+  width: 100%;
+  height: 48px;
+  background: #F8F9FA 0% 0% no-repeat padding-box !important;
+  border-radius: 5px !important;
+  opacity: 1 !important;
+  border: none;
+  margin: 5px 0px 5px 0px;
+  color: #2756FF;
+}
+.default{
+  width: 100%;
+  height: 48px;
+  background: #F8F9FA 0% 0% no-repeat padding-box !important;
+  border-radius: 5px !important;
+  opacity: 1 !important;
+  border: none;
+  margin: 5px 0px 5px 0px;
+  color:#808080;
+}
+.select select-item {
+  width: 100%;
+  height: 48px;
+  background: #F8F9FA 0% 0% no-repeat padding-box !important;
+  border-radius: 5px !important;
+  opacity: 1 !important;
+  border: none;  
+  color:#808080;
+}
+.buttons {
+  margin: 32px 0 32px 0;
+  text-align: right;
+}
+
+.btn {  
+  width: 100px;
+  height: 45px;
+  font-size: 14px;
+  font-weight: bold;
+  border: 1px solid #2756FF;
+  border-radius: 10px;
+  opacity: 1;
+  margin-left: 10px;
+  margin-right: 10px;
+  color: #2756FF;
+  background-color: #F8F9FA;
+}
+
+.btn:hover {  
+  color: #F8F9FA;
+  background-color: #2756FF;
+}
\ No newline at end of file
diff --git a/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx b/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
index a934ab6..b4e5edd 100644
--- a/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
+++ b/frontend/src/components/cypherresult/presentations/CypherResultCytoscape.jsx
@@ -173,26 +173,66 @@
   };
 
   const changeCaptionOnCytoscapeElements = (elementType, label, caption) => {
-    cytoscapeObject.elements(`${elementType}[label = "${label}"]`).style('label', (ele) => {
-      let displayValue = '< NULL >';
-      if (caption === 'gid') {
-        const idValue = ele.data('id');
-        if (idValue !== null && idValue !== undefined) {
-          displayValue = `[ ${idValue} ]`;
+    if (caption === null) {
+      cytoscapeObject.elements(`${elementType}[label = "${label}"]`).style('label', '');
+    } else {
+      cytoscapeObject.elements(`${elementType}[label = "${label}"]`).style('label', (ele) => {
+        let displayValue = '< NULL >';
+        if (caption === 'gid') {
+          const idValue = ele.data('id');
+          if (idValue !== null && idValue !== undefined) {
+            displayValue = `[ ${idValue} ]`;
+          }
+        } else if (caption === 'label') {
+          const labelValue = ele.data('label');
+          if (labelValue !== null && labelValue !== undefined) {
+            displayValue = `[ :${labelValue} ]`;
+          }
+        } else if (ele !== null && ele !== undefined) {
+          const anonValue = ele.data('properties')[caption];
+          if (anonValue !== null && anonValue !== undefined) {
+            displayValue = anonValue;
+          }
         }
-      } else if (caption === 'label') {
-        const labelValue = ele.data('label');
-        if (labelValue !== null && labelValue !== undefined) {
-          displayValue = `[ :${labelValue} ]`;
-        }
-      } else if (ele !== null && ele !== undefined) {
-        const anonValue = ele.data('properties')[caption];
-        if (anonValue !== null && anonValue !== undefined) {
-          displayValue = anonValue;
-        }
+        return displayValue;
+      });
+    }
+  };
+
+  const applyEdgeThicknessCytoscapeElements = (thickness) => {
+    const edgeSizes = [1, 6, 11, 16, 21];
+    if (thickness !== null) {
+      const range = thickness.max - thickness.min;
+      const edgeSizeByRate = (rate) => {
+        let size = edgeSizes[0];
+        size = (rate >= 0) ? edgeSizes[0] : size;
+        size = (rate >= 20) ? edgeSizes[1] : size;
+        size = (rate >= 40) ? edgeSizes[2] : size;
+        size = (rate >= 60) ? edgeSizes[3] : size;
+        size = (rate >= 80) ? edgeSizes[4] : size;
+        size = (rate >= 100) ? edgeSizes[4] : size;
+        return size;
+      };
+      if (cytoscapeObject) {
+        cytoscapeObject.elements().forEach((e) => {
+          const ele = e;
+          if (ele.group() === 'edges') {
+            if (ele.data().label === thickness.edge && ele.data().properties[thickness.property]) {
+              const propertyValue = ele.data().properties[thickness.property];
+              const propertyRate = (propertyValue / range) * 100;
+              ele.style('width', edgeSizeByRate(propertyRate).toString());
+            }
+          }
+        });
       }
-      return displayValue;
-    });
+    } else if (cytoscapeObject) {
+      cytoscapeObject.elements().forEach((e) => {
+        const ele = e;
+        if (ele.group() === 'edges') {
+          ele.style('width', '');
+        }
+      });
+    }
   };
 
   const applyFilterOnCytoscapeElements = (filters) => {
@@ -242,16 +282,26 @@
     }).addClass(gFilteredClassName);
 
     // Step2. Edge Highlight from not filtered nodes.
+    const targetAndSourceNodeList = [];
     for (let nodeIndex = 0; nodeIndex < notFilteredNodeLength; nodeIndex += 1) {
       const currentNode = notFilteredNodes[nodeIndex];
       const edges = currentNode.connectedEdges();
       const edgesSize = edges.length;
       for (let edgeIndex = 0; edgeIndex < edgesSize; edgeIndex += 1) {
         const currentEdge = edges[edgeIndex];
+        const edgeTargetNode = currentEdge.target();
+        const edgeSourceNode = currentEdge.source();
         const connectedWithHighlightNode = currentEdge.connectedNodes().not(`.${gFilteredClassName}`).filter((ele) => ele !== currentNode);
-        if (connectedWithHighlightNode.length === 0) currentEdge.addClass(gFilteredClassName);
+        if (connectedWithHighlightNode.length === 0) {
+          currentEdge.addClass(gFilteredClassName);
+        } else {
+          targetAndSourceNodeList.push(edgeTargetNode);
+          targetAndSourceNodeList.push(edgeSourceNode);
+        }
       }
     }
+    // Step3 . Edge Highlighting target And source filtered remove
+    targetAndSourceNodeList.forEach((node) => { node.removeClass(gFilteredClassName); });
 
     cytoscapeObject.elements(`.${gFilteredClassName}`).style('opacity', '0.1');
   };
@@ -290,9 +340,13 @@
     getLabels() {
       return Object.keys(props.data.legend.nodeLegend);
     },
+    getEdges() {
+      return Object.keys(props.data.legend.edgeLegend);
+    },
     getCaptionsFromCytoscapeObject,
     applyFilterOnCytoscapeElements,
     resetFilterOnCytoscapeElements,
+    applyEdgeThicknessCytoscapeElements,
   }));
 
   return (
diff --git a/frontend/src/components/cytoscape/CypherResultCytoscapeFooter.jsx b/frontend/src/components/cytoscape/CypherResultCytoscapeFooter.jsx
index 7260f82..73f84a7 100644
--- a/frontend/src/components/cytoscape/CypherResultCytoscapeFooter.jsx
+++ b/frontend/src/components/cytoscape/CypherResultCytoscapeFooter.jsx
@@ -251,7 +251,19 @@
                   </strong>
                 </button>
               ))}
-
+              <button
+                onClick={() => [
+                  updateLabelCaption(footerData.data.type, footerData.data.label, null),
+                  captionChange(footerData.data.type, footerData.data.label, null)]}
+                key={uuid()}
+                type="button"
+                className={`btn captionSelector ${selectedCaption === null ? ' btn-secondary ' : ' btn-outline-dark '}`}
+              >
+                <strong>
+                  &lt;
+                  &gt;
+                </strong>
+              </button>
             </span>
           </div>
           <button
diff --git a/frontend/src/components/cytoscape/CytoscapeStyleSheet.js b/frontend/src/components/cytoscape/CytoscapeStyleSheet.js
index e2db89e..0559b50 100644
--- a/frontend/src/components/cytoscape/CytoscapeStyleSheet.js
+++ b/frontend/src/components/cytoscape/CytoscapeStyleSheet.js
@@ -21,14 +21,8 @@
   }
   const props = ele.data('properties');
   if (props[captionProp] === undefined) {
-    if (ele.isNode()) {
-      selectedLabel.node[ele.data('label')] = 'gid';
-    } else {
-      selectedLabel.edge[ele.data('label')] = 'gid';
-    }
-    return `[ ${ele.data('id')} ]`;
+    return '';
   }
-
   if (ele.isNode()) {
     selectedLabel.node[ele.data('label')] = captionProp;
   } else {
diff --git a/frontend/src/components/frame/Frame.jsx b/frontend/src/components/frame/Frame.jsx
index f565fb5..74d89f6 100644
--- a/frontend/src/components/frame/Frame.jsx
+++ b/frontend/src/components/frame/Frame.jsx
@@ -9,8 +9,9 @@
   // faPaperclip,
   faSync, faTimes,
 } from '@fortawesome/free-solid-svg-icons';
-
-import { Button, Dropdown, Menu } from 'antd';
+import {
+  Button, Dropdown, Menu, Popover,
+} from 'antd';
 import PropTypes from 'prop-types';
 import styles from './Frame.module.scss';
 
@@ -18,7 +19,7 @@
   reqString, content,
   // isPinned, pinFrame,
   refKey, removeFrame,
-  onSearch, onSearchCancel, onDownload, onRefresh,
+  onSearch, onThick, thicnessMenu, onSearchCancel, onDownload, onRefresh,
   bodyNoPadding,
 }) => {
   const [isFullScreen, setFullScreen] = useState(false);
@@ -48,6 +49,19 @@
           </strong>
         </div>
         <div className={styles.ButtonArea}>
+          {onThick ? (
+            <Popover placement="bottomLeft" content={thicnessMenu} trigger="click">
+              <Button
+                size="large"
+                type="link"
+                className={styles.FrameButton}
+                title="Edge Weight"
+                onClick={() => onThick()}
+              >
+                <i className="icon-edge-weight" />
+              </Button>
+            </Popover>
+          ) : null }
           {onSearchCancel ? (
             <Button
               size="large"
@@ -164,7 +178,9 @@
 
 Frame.defaultProps = {
   onSearch: null,
+  onThick: null,
   onSearchCancel: null,
+  thicnessMenu: null,
   onDownload: null,
   onRefresh: null,
   bodyNoPadding: false,
@@ -178,6 +194,8 @@
   refKey: PropTypes.string.isRequired,
   removeFrame: PropTypes.func.isRequired,
   onSearch: PropTypes.func,
+  onThick: PropTypes.func,
+  thicnessMenu: PropTypes.func,
   onSearchCancel: PropTypes.func,
   onDownload: PropTypes.func,
   onRefresh: PropTypes.func,
diff --git a/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx b/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
index 82fb8a0..76e7a51 100644
--- a/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
+++ b/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
@@ -25,6 +25,7 @@
   from '../../cypherresult/containers/CypherResultCytoscapeContainer';
 import CypherResultTableContainer from '../../cypherresult/containers/CypherResultTableContainer';
 import GraphFilterModal from '../../cypherresult/components/GraphFilterModal';
+import EdgeThicknessMenu from '../../cypherresult/components/EdgeThicknessMenu';
 import Frame from '../Frame';
 
 const CypherResultFrame = ({
@@ -38,9 +39,13 @@
   const [cytoscapeContainerKey, setCytoscapeContainerKey] = useState(uuid());
 
   const [filterModalVisible, setFilterModalVisible] = useState(false);
+  const [thicknessModalVisible, setThicknessModalVisible] = useState(false);
 
   const [filterProperties, setFilterProperties] = useState([]);
+  const [edgeProperties, setEdgeProperties] = useState([]);
   const [globalFilter, setGlobalFilter] = useState(null);
+  const [globalThickness, setGlobalThickness] = useState(null);
+
   useEffect(() => {
     if (chartAreaRef.current && filterModalVisible) {
       const labels = chartAreaRef.current.getLabels()
@@ -55,7 +60,18 @@
         ).flat();
       setFilterProperties(labels);
     }
-  }, [filterModalVisible]);
+    if (chartAreaRef.current && thicknessModalVisible) {
+      const edges = chartAreaRef.current.getEdges()
+        .map((edge) => {
+          const propertiesIter = Array.from(chartAreaRef.current.getCaptionsFromCytoscapeObject('edge', edge));
+          return propertiesIter.map((value) => ({
+            edge,
+            property: value,
+          }));
+        }).flat();
+      setEdgeProperties(edges);
+    }
+  }, [filterModalVisible, thicknessModalVisible]);
 
   useEffect(() => {
     if (globalFilter) {
@@ -65,6 +81,10 @@
     }
   }, [globalFilter]);
 
+  useEffect(() => {
+    chartAreaRef.current.applyEdgeThicknessCytoscapeElements(globalThickness);
+  }, [globalThickness]);
+
   const refreshFrame = () => {
     setCytoscapeContainerKey(uuid());
   };
@@ -128,6 +148,17 @@
       <Frame
         bodyNoPadding
         onSearch={() => setFilterModalVisible(true)}
+        onThick={() => setThicknessModalVisible(true)}
+        thicnessMenu={
+          (
+            <EdgeThicknessMenu
+              onSubmit={(thicness) => {
+                setGlobalThickness(thicness);
+              }}
+              properties={edgeProperties}
+            />
+          )
+        }
         onSearchCancel={() => setGlobalFilter(null)}
         onRefresh={refreshFrame}
         onDownload={(type) => {
diff --git a/frontend/src/static/icons/css/fontello.css b/frontend/src/static/icons/css/fontello.css
index 617825c..41d441b 100644
--- a/frontend/src/static/icons/css/fontello.css
+++ b/frontend/src/static/icons/css/fontello.css
@@ -61,4 +61,5 @@
 .icon-play:before { content: '\e803'; font-size: 30px; }
 .icon-close-session:before { content: '\e804'; font-size: 30px; color: #142B80; }
 .icon-refresh:before { content: '\e805'; font-size: 30px; color: #18CCC5; }
-.icon-search-cancel:before { content: '\e806'; font-size: 24px; }
\ No newline at end of file
+.icon-search-cancel:before { content: '\e806'; font-size: 24px; }
+.icon-edge-weight:before { content: '\e807'; font-size: 24px;} 
\ No newline at end of file
diff --git a/frontend/src/static/icons/font/fontello.eot b/frontend/src/static/icons/font/fontello.eot
index 7371ed1..76dc8f9 100644
--- a/frontend/src/static/icons/font/fontello.eot
+++ b/frontend/src/static/icons/font/fontello.eot
Binary files differ
diff --git a/frontend/src/static/icons/font/fontello.svg b/frontend/src/static/icons/font/fontello.svg
index 86d9e18..67f3e31 100644
--- a/frontend/src/static/icons/font/fontello.svg
+++ b/frontend/src/static/icons/font/fontello.svg
@@ -19,6 +19,8 @@
 <glyph glyph-name="refresh" unicode="&#xe805;" d="M864 850h-728a136 136 0 0 1-136-136v-728a136 136 0 0 1 136-136h728a136 136 0 0 1 136 136v728a136 136 0 0 1-136 136z m-154-706a268 268 0 0 0-182-99 270 270 0 0 0-297 226l0 0a49 49 0 0 0 96 15 172 172 0 1 1 187 199v-56l0-1a19 19 0 0 0-29-13l-1 1-142 104a18 18 0 0 0-3 4 18 18 0 0 0 3 25l143 104a19 19 0 0 0 29-12l0-1v-57a270 270 0 0 0 196-439z" horiz-adv-x="1000" />
 
 <glyph glyph-name="search-cancel" unicode="&#xe806;" d="M752 850a105 105 0 0 1-103-123l-72-34a105 105 0 0 1-78 36h0a105 105 0 0 1-78-36l-71 34a105 105 0 1 1-104-86h0a105 105 0 0 1 65 22l84-40a105 105 0 0 1 104-104h0a105 105 0 0 1 104 104l84 40a105 105 0 0 1 65-22h0a105 105 0 0 1 0 209z m-506-135a30 30 0 1 0 31 30 30 30 0 0 0-31-30z m253-121a30 30 0 1 0 30 30v0a30 30 0 0 0-30-30z m253 121a30 30 0 1 0 31 30v0a30 30 0 0 0-31-30z m76-420a234 234 0 1 1 133-211 234 234 0 0 1-133 211z m49-319l-51-51-99 99-99-99-51 51 99 99-99 99 51 51 99-99 99 99 51-51-99-99z m-454 108a305 305 0 0 0 13 89q-123 136-246 272a2971 2971 0 0 1 618 0l-27-30c-9-10-17-19-26-28a301 301 0 0 0 85-21l106 116a46 46 0 0 1 11 17 46 46 0 0 1-22 59 110 110 0 0 1-35 13c-44 8-91 16-138 23-20 2-40 3-59 4-9 1-17 1-26 2l-27 2v-78l24 0q40-2 80-6c-34-3-69-7-104-8a2660 2660 0 0 0-415 7q45 6 91 7l25 1-3 78-27-2c-14-2-28-3-42-4-31-2-63-5-94-9a696 696 0 0 1-107-24 50 50 0 0 1-37-34 53 53 0 0 1 16-51q163-180 325-360a11 11 0 0 0 2-7c1-56 1-107 1-153a65 65 0 0 1 34-65 522 522 0 0 1 80-33 224 224 0 0 1 27-5 303 303 0 0 0-103 228z" horiz-adv-x="1000" />
+
+<glyph glyph-name="edge-weight" unicode="&#xe807;" d="M0 360v-85a32 32 0 0 1 35-28h929a32 32 0 0 1 35 28v85a32 32 0 0 1-35 29h-929a32 32 0 0 1-35-29z m1 262v-44a29 29 0 0 1 31-26h937a29 29 0 0 1 31 26v44a29 29 0 0 1-31 25h-937a29 29 0 0 1-31-25z m-1-598v-142a36 36 0 0 1 39-32h921a36 36 0 0 1 39 32v142a36 36 0 0 1-39 32h-921a36 36 0 0 1-39-32z m0 802v-10a27 27 0 0 1 29-24h941a27 27 0 0 1 29 24v10a27 27 0 0 1-29 24h-941a27 27 0 0 1-29-24z" horiz-adv-x="1000" />
 </font>
 </defs>
 </svg>
\ No newline at end of file
diff --git a/frontend/src/static/icons/font/fontello.ttf b/frontend/src/static/icons/font/fontello.ttf
index 07f5d0f..c74fc93 100644
--- a/frontend/src/static/icons/font/fontello.ttf
+++ b/frontend/src/static/icons/font/fontello.ttf
Binary files differ
diff --git a/frontend/src/static/icons/font/fontello.woff b/frontend/src/static/icons/font/fontello.woff
index cc1defd..85262f2 100644
--- a/frontend/src/static/icons/font/fontello.woff
+++ b/frontend/src/static/icons/font/fontello.woff
Binary files differ
diff --git a/frontend/src/static/icons/font/fontello.woff2 b/frontend/src/static/icons/font/fontello.woff2
index 55d527d..c5dad89 100644
--- a/frontend/src/static/icons/font/fontello.woff2
+++ b/frontend/src/static/icons/font/fontello.woff2
Binary files differ