You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by hb...@apache.org on 2022/11/01 14:08:24 UTC

[age-viewer] branch main updated: Request progress indicator for currently processing requests (#49)

This is an automated email from the ASF dual-hosted git repository.

hbshin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/age-viewer.git


The following commit(s) were added to refs/heads/main by this push:
     new a232cec  Request progress indicator for currently processing requests (#49)
a232cec is described below

commit a232cec4fc1dffd182586e168287fd202cbb54ed
Author: marodins <67...@users.noreply.github.com>
AuthorDate: Tue Nov 1 07:08:19 2022 -0700

    Request progress indicator for currently processing requests (#49)
    
    * add frame earlier and update state of cypher slice to include pending state
    
    * update pending and fulfilled state of cypher slice
    
    * include progress indicator while results are transmitting
    
    * update container component's branch condition
    
    * update cypher slice
    
    * refactor frame creating code and frame component dependency; adjust progress indicator
    
    * clean up comments
---
 .../src/components/contents/containers/Editor.js   |  3 +-
 .../components/contents/presentations/Editor.jsx   |  9 ++--
 .../components/contents/presentations/Frames.jsx   |  7 ++-
 .../containers/CypherGraphResultContainers.js      |  3 +-
 .../frame/containers/CypherResultContainers.js     |  5 ++-
 .../frame/presentations/CypherGraphResultFrame.jsx | 51 +++++++++++++++-------
 frontend/src/features/cypher/CypherSlice.js        | 17 +++++++-
 frontend/src/features/frame/FrameSlice.js          |  3 +-
 8 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/frontend/src/components/contents/containers/Editor.js b/frontend/src/components/contents/containers/Editor.js
index cf6adf9..95b5176 100644
--- a/frontend/src/components/contents/containers/Editor.js
+++ b/frontend/src/components/contents/containers/Editor.js
@@ -18,7 +18,7 @@
  */
 
 import { connect } from 'react-redux';
-import { addFrame, trimFrame } from '../../../features/frame/FrameSlice';
+import { addFrame, trimFrame, removeFrame } from '../../../features/frame/FrameSlice';
 import { addAlert } from '../../../features/alert/AlertSlice';
 import { getConnectionStatus } from '../../../features/database/DatabaseSlice';
 import { executeCypherQuery } from '../../../features/cypher/CypherSlice';
@@ -38,6 +38,7 @@ const mapDispatchToProps = {
   setCommand,
   addFrame,
   trimFrame,
+  removeFrame,
   addAlert,
   getConnectionStatus,
   executeCypherQuery,
diff --git a/frontend/src/components/contents/presentations/Editor.jsx b/frontend/src/components/contents/presentations/Editor.jsx
index 3c14533..4c66ac1 100644
--- a/frontend/src/components/contents/presentations/Editor.jsx
+++ b/frontend/src/components/contents/presentations/Editor.jsx
@@ -88,12 +88,9 @@ const Editor = ({
         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);
+      addFrame(command, 'CypherResultFrame', refKey);
+      dispatch(() => executeCypherQuery([refKey, command]).then((response) => {
+        if (response.type === 'cypher/executeCypherQuery/rejected') {
           dispatch(() => addAlert('ErrorCypherQuery'));
         }
       }));
diff --git a/frontend/src/components/contents/presentations/Frames.jsx b/frontend/src/components/contents/presentations/Frames.jsx
index 2f5485a..90139db 100644
--- a/frontend/src/components/contents/presentations/Frames.jsx
+++ b/frontend/src/components/contents/presentations/Frames.jsx
@@ -114,9 +114,8 @@ const Frames = ({
         );
       }
       if (frame.frameName === 'CypherResultFrame') {
-        if (Object.prototype.hasOwnProperty.call(queryResult, frame.frameProps.key)
-          && (queryResult[frame.frameProps.key].command !== null ? queryResult[frame.frameProps.key].command.toUpperCase() : 'NULL')
-            .match('(ERROR|GRAPH|CREATE|UPDATE|COPY|NULL).*')) {
+        if (queryResult[frame.frameProps.key].complete && (queryResult[frame.frameProps.key].command !== null ? queryResult[frame.frameProps.key].command.toUpperCase() : 'NULL')
+          .match('(ERROR|GRAPH|CREATE|UPDATE|COPY|NULL).*')) {
           return (
             <CypherResult
               key={frame.frameProps.key}
@@ -137,7 +136,7 @@ const Frames = ({
       }
       return '';
     }));
-  }, [frameList]);
+  }, [frameList, queryResult]);
 
   return (
     <div className="container-fluid frame-area pt-3">
diff --git a/frontend/src/components/frame/containers/CypherGraphResultContainers.js b/frontend/src/components/frame/containers/CypherGraphResultContainers.js
index 5b4e17e..d309c89 100644
--- a/frontend/src/components/frame/containers/CypherGraphResultContainers.js
+++ b/frontend/src/components/frame/containers/CypherGraphResultContainers.js
@@ -21,7 +21,8 @@ import { connect } from 'react-redux';
 import { pinFrame, removeFrame } from '../../../features/frame/FrameSlice';
 import CypherGraphResultFrame from '../presentations/CypherGraphResultFrame';
 
-const mapStateToProps = () => ({
+const mapStateToProps = (state, props) => ({
+  queryComplete: state.cypher.queryResult[props.refKey],
 });
 
 const mapDispatchToProps = { removeFrame, pinFrame };
diff --git a/frontend/src/components/frame/containers/CypherResultContainers.js b/frontend/src/components/frame/containers/CypherResultContainers.js
index 6319d4c..a8f57aa 100644
--- a/frontend/src/components/frame/containers/CypherResultContainers.js
+++ b/frontend/src/components/frame/containers/CypherResultContainers.js
@@ -21,8 +21,9 @@ import { connect } from 'react-redux';
 import { pinFrame, removeFrame } from '../../../features/frame/FrameSlice';
 import CypherResultFrame from '../presentations/CypherResultFrame';
 
-const mapStateToProps = () => ({
-});
+const mapStateToProps = () => (
+  {}
+);
 
 const mapDispatchToProps = { removeFrame, pinFrame };
 
diff --git a/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx b/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
index 8117a8c..9298dfa 100644
--- a/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
+++ b/frontend/src/components/frame/presentations/CypherGraphResultFrame.jsx
@@ -22,6 +22,7 @@ import uuid from 'react-uuid';
 import { saveAs } from 'file-saver';
 import { Parser } from 'json2csv';
 import PropTypes from 'prop-types';
+import { Spinner } from 'react-bootstrap';
 import CypherResultCytoscapeContainer from '../../cypherresult/containers/CypherResultCytoscapeContainer';
 import CypherResultTableContainer from '../../cypherresult/containers/CypherResultTableContainer';
 import GraphFilterModal from '../../cypherresult/components/GraphFilterModal';
@@ -29,6 +30,7 @@ import EdgeThicknessMenu from '../../cypherresult/components/EdgeThicknessMenu';
 import Frame from '../Frame';
 
 const CypherResultFrame = ({
+  queryComplete,
   refKey,
   isPinned,
   reqString,
@@ -74,6 +76,7 @@ const CypherResultFrame = ({
   }, [filterModalVisible, thicknessModalVisible, chartLegend]);
 
   useEffect(() => {
+    if (!chartAreaRef.current) return;
     if (globalFilter) {
       chartAreaRef.current.applyFilterOnCytoscapeElements(globalFilter);
     } else {
@@ -82,6 +85,7 @@ const CypherResultFrame = ({
   }, [globalFilter]);
 
   useEffect(() => {
+    if (!chartAreaRef.current) return;
     chartAreaRef.current.applyEdgeThicknessCytoscapeElements(globalThickness);
   }, [globalThickness]);
 
@@ -174,21 +178,33 @@ const CypherResultFrame = ({
         isPinned={isPinned}
         refKey={refKey}
       >
-        <div className="d-flex h-100">
-          <div style={{ height: '100%', width: '100%' }} id={`${refKey}-graph`} className="selected-frame-tab">
-            <CypherResultCytoscapeContainer
-              key={cytoscapeContainerKey}
-              ref={chartAreaRef}
-              refKey={refKey}
-              setChartLegend={setChartLegend}
-            />
-          </div>
-          <div style={{ height: '100%', width: '100%' }} id={`${refKey}-table`} className="deselected-frame-tab">
-            <CypherResultTableContainer
-              refKey={refKey}
-            />
-          </div>
-        </div>
+        {
+          queryComplete.complete
+            ? (
+              <div className="d-flex h-100">
+                <div style={{ height: '100%', width: '100%' }} id={`${refKey}-graph`} className="selected-frame-tab">
+                  <CypherResultCytoscapeContainer
+                    key={cytoscapeContainerKey}
+                    ref={chartAreaRef}
+                    refKey={refKey}
+                    setChartLegend={setChartLegend}
+                  />
+                </div>
+                <div style={{ height: '100%', width: '100%' }} id={`${refKey}-table`} className="deselected-frame-tab">
+                  <CypherResultTableContainer
+                    refKey={refKey}
+                  />
+                </div>
+              </div>
+            )
+            : (
+              <div style={{ alignContent: 'center' }}>
+                <div style={{ marginLeft: '50%', padding: '20px' }} id={`${refKey}-loading`}>
+                  <Spinner animation="border" />
+                </div>
+              </div>
+            )
+        }
       </Frame>
       <GraphFilterModal
         onSubmit={(filters) => {
@@ -205,6 +221,11 @@ const CypherResultFrame = ({
 };
 
 CypherResultFrame.propTypes = {
+  queryComplete: PropTypes.shape(
+    {
+      complete: PropTypes.bool.isRequired,
+    },
+  ).isRequired,
   refKey: PropTypes.string.isRequired,
   isPinned: PropTypes.bool.isRequired,
   reqString: PropTypes.string.isRequired,
diff --git a/frontend/src/features/cypher/CypherSlice.js b/frontend/src/features/cypher/CypherSlice.js
index 8edc9ad..78c2950 100644
--- a/frontend/src/features/cypher/CypherSlice.js
+++ b/frontend/src/features/cypher/CypherSlice.js
@@ -108,15 +108,28 @@ const CypherSlice = createSlice({
   },
   extraReducers: {
     [executeCypherQuery.fulfilled]: (state, action) => {
-      state.queryResult[action.payload.key] = {};
       // state.queryResult[action.payload.key].response = action.payload
-      Object.assign(state.queryResult[action.payload.key], action.payload);
+      Object.assign(state.queryResult[action.payload.key], {
+        ...action.payload,
+        complete: true,
+      });
+    },
+    [executeCypherQuery.pending]: (state, action) => {
+      const key = action.meta.arg[0];
+      const command = action.meta.arg[1];
+      state.queryResult[key] = {};
+      Object.assign(state.queryResult[key], {
+        command,
+        complete: false,
+        requestId: action.meta.requestId,
+      });
     },
     [executeCypherQuery.rejected]: (state, action) => {
       state.queryResult[action.meta.arg[0]] = {
         command: 'ERROR',
         query: action.meta.arg[1],
         key: action.meta.arg[0],
+        complete: true,
         message: action.error.message,
       };
     },
diff --git a/frontend/src/features/frame/FrameSlice.js b/frontend/src/features/frame/FrameSlice.js
index 9b46299..7495237 100644
--- a/frontend/src/features/frame/FrameSlice.js
+++ b/frontend/src/features/frame/FrameSlice.js
@@ -48,8 +48,7 @@ const FrameSlice = createSlice({
     removeFrame: {
       reducer: (state, action) => {
         const frameKey = action.payload.refKey;
-        state.splice(state.findIndex((frame) => (frame.frameProps.key === frameKey)), 1);
-        state.map((frame) => { if (frame.orgIndex) { frame.orgIndex -= 1; } return frame; });
+        return state.filter((frame) => frame.frameProps.key !== frameKey);
       },
       prepare: (refKey) => ({ payload: { refKey } }),