Skip to content

Commit

Permalink
191 fix missing UI edges (#195)
Browse files Browse the repository at this point in the history
* fix missing param-to-electron edges in UI graph

* update version/changelog

* clean up unused code
  • Loading branch information
valkostadinov authored Mar 16, 2022
1 parent 01b82a6 commit 38d8e2f
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 52 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.32.3] - 2022-03-16

### Fixed

- Fix missing UI graph edges between parameters and electrons in certain cases.
- Fix UI crashes in cases where legacy localStorage state was being loaded.

## [0.32.2] - 2022-03-16

### Added
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.32.2
0.32.3
57 changes: 32 additions & 25 deletions covalent_dispatcher/_db/dispatchdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def extract_graph_node(node):
# doc string
f = node.get("function")
if f is not None:
node["doc"] = node["function"].get_deserialized().__doc__
node["doc"] = f.get_deserialized().__doc__

# metadata
node["metadata"] = extract_metadata(node["metadata"])
Expand Down Expand Up @@ -80,14 +80,42 @@ def extract_graph(graph):
}


def encode_result(obj):
def result_encoder(obj):
if isinstance(obj, Status):
return obj.STATUS
if isinstance(obj, datetime):
return obj.isoformat()
return str(obj)


def encode_result(result_obj):
lattice = result_obj.lattice
((named_args, named_kwargs),) = (
get_named_params(lattice.workflow_function, lattice.args, lattice.kwargs),
)
result_dict = {
"dispatch_id": result_obj.dispatch_id,
"status": result_obj.status,
"result": result_obj.result,
"start_time": result_obj.start_time,
"end_time": result_obj.end_time,
"results_dir": result_obj.results_dir,
"error": result_obj.error,
"lattice": {
"function_string": lattice.workflow_function_string,
"doc": lattice.__doc__,
"name": lattice.__name__,
"inputs": encode_dict({**named_args, **named_kwargs}),
"metadata": extract_metadata(lattice.metadata),
},
"graph": extract_graph(result_obj.lattice.transport_graph._graph),
}

jsonified_result = simplejson.dumps(result_dict, default=result_encoder, ignore_nan=True)

return jsonified_result


class DispatchDB:
"""
Wrapper for the database of workflows.
Expand Down Expand Up @@ -163,29 +191,8 @@ def upsert(self, dispatch_id: str, result_obj: Result) -> None:
The Result is turned into a dictionary and stored as json.
"""
lattice = result_obj.lattice
((named_args, named_kwargs),) = (
get_named_params(lattice.workflow_function, lattice.args, lattice.kwargs),
)
result_dict = {
"dispatch_id": result_obj.dispatch_id,
"status": result_obj.status,
"result": result_obj.result,
"start_time": result_obj.start_time,
"end_time": result_obj.end_time,
"results_dir": result_obj.results_dir,
"error": result_obj.error,
"lattice": {
"function_string": lattice.workflow_function_string,
"doc": lattice.__doc__,
"name": lattice.__name__,
"kwargs": encode_dict(lattice.kwargs),
"metadata": extract_metadata(lattice.metadata),
},
"graph": extract_graph(result_obj.lattice.transport_graph._graph),
}

jsonified_result = simplejson.dumps(result_dict, default=encode_result, ignore_nan=True)

jsonified_result = encode_result(result_obj)

try:
sql = "INSERT INTO dispatches (dispatch_id, result_dict) VALUES (?, ?)"
Expand Down
12 changes: 11 additions & 1 deletion covalent_ui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from covalent._results_manager import results_manager as rm
from covalent._shared_files.config import get_config
from covalent._shared_files.util_classes import Status
from covalent_dispatcher._db.dispatchdb import DispatchDB
from covalent_dispatcher._db.dispatchdb import DispatchDB, encode_result
from covalent_dispatcher._service.app import bp

WEBHOOK_PATH = "/api/webhook"
Expand Down Expand Up @@ -74,6 +74,16 @@ def list_results():
return jsonify([simplejson.loads(r[1]) for r in res])


@app.route("/api/dev/results/<dispatch_id>")
def fetch_result_dev(dispatch_id):
results_dir = request.args["resultsDir"]
result = rm.get_result(dispatch_id, results_dir=results_dir)

jsonified_result = encode_result(result)

return app.response_class(jsonified_result, status=200, mimetype="application/json")


@app.route("/api/results/<dispatch_id>")
def fetch_result(dispatch_id):
with DispatchDB() as db:
Expand Down
8 changes: 7 additions & 1 deletion covalent_ui/result_webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from covalent._results_manager import Result
from covalent._shared_files import logger
from covalent._shared_files.config import get_config
from covalent._shared_files.utils import get_named_params
from covalent_dispatcher._db.dispatchdb import encode_dict, extract_graph, extract_metadata

DEFAULT_PORT = get_config("user_interface.port")
Expand Down Expand Up @@ -81,6 +82,11 @@ def send_draw_request(lattice) -> None:
"""

graph = lattice.transport_graph.get_internal_graph_copy()

((named_args, named_kwargs),) = (
get_named_params(lattice.workflow_function, lattice.args, lattice.kwargs),
)

draw_request = json.dumps(
{
"event": "draw-request",
Expand All @@ -89,7 +95,7 @@ def send_draw_request(lattice) -> None:
"function_string": lattice.workflow_function_string,
"doc": lattice.__doc__,
"name": lattice.__name__,
"kwargs": encode_dict(lattice.kwargs),
"inputs": encode_dict({**named_args, **named_kwargs}),
"metadata": extract_metadata(lattice.metadata),
},
"graph": extract_graph(graph),
Expand Down
3 changes: 2 additions & 1 deletion covalent_ui/webapp/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@
}
}

/* TODO quick hack to disable handles */
/* don't show handles */
.react-flow__handle {
visibility: hidden;
}
/* adjust handle for edge positioning */
.react-flow__handle-bottom {
bottom: 0px !important;
}
Expand Down
68 changes: 68 additions & 0 deletions covalent_ui/webapp/src/components/common/LogOutput.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,74 @@ import { isDemo } from '../../utils/demo/setup'
const FETCH_INTERVAL_MS = 2000
const MAX_LINES = 80

/**
* Temporary solution to log output until backend file logs are sorted out. See
* LogOutput below.
*/
export const LatticeOutput = ({ dispatchId }) => {
const output = useSelector((state) => {
const result = state.results.cache[dispatchId]
return _.reduce(
_.get(result, 'graph.nodes'),
(logs, node) => {
_.each(
[{ key: 'stdout' }, { key: 'stderr', isErr: true }],
({ key, isErr }) => {
const text = node[key]
if (text) {
logs.push({
name: `${node.name} [${key}]`,
lines: _.split(text, '\n'),
isErr,
})
}
}
)
return logs
},
[]
)
})

return _.map(output, (node) => <NodeOutput node={node} />)
}

const NodeOutput = ({ node }) => {
const { name, lines, isErr } = node

// auto-scroll to last line on updates
const bottomRef = useRef(null)
useEffect(() => {
bottomRef.current.scrollIntoView({ behavoir: 'smooth' })
}, [lines])

return (
<div key={name}>
<Heading>{name}</Heading>
<Paper>
<Typography
sx={{
fontSize: 'small',
overflow: 'auto',
maxHeight: 200,
whiteSpace: 'nowrap',
color: isErr ? 'error.light' : 'inherit',
p: 1,
}}
>
{_.map(lines, (line, index) => (
<span key={index}>
{line}
<br />
</span>
))}
<div ref={bottomRef} />
</Typography>
</Paper>
</div>
)
}

const LogOutput = ({ dispatchId }) => {
const isRunning = useSelector(
(state) => _.get(state.results.cache[dispatchId], 'status') === 'RUNNING'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { ReactComponent as AtomSvg } from '../../assets/atom.svg'
import { selectResultProgress } from '../dispatches/ResultProgress'
import LatticeDispatchOverview from './LatticeDispatchOverview'
import { statusIcon, truncateMiddle } from '../../utils/misc'
import LogOutput from '../common/LogOutput'
import { LatticeOutput } from '../common/LogOutput'
import ErrorCard from '../common/ErrorCard'

const DispatchDrawerContents = () => {
Expand Down Expand Up @@ -84,7 +84,7 @@ const DispatchDrawerContents = () => {
</TabPanel>

<TabPanel value="output" sx={{ px: 0, py: 1 }}>
<LogOutput dispatchId={dispatchId} />
<LatticeOutput dispatchId={dispatchId} />
</TabPanel>
</TabContext>
</Box>
Expand Down
24 changes: 10 additions & 14 deletions covalent_ui/webapp/src/components/graph/ElectronNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,11 @@ const ElectronNode = ({
borderWidth: hasBorder ? 1 : 0,
}}
>
{!!data.inputs && (
<Handle
type="target"
position={targetPosition}
isConnectable={isConnectable}
/>
)}
<Handle
type="target"
position={targetPosition}
isConnectable={isConnectable}
/>
{(() => {
switch (data.status) {
case 'NEW_OBJECT':
Expand Down Expand Up @@ -107,13 +105,11 @@ const ElectronNode = ({
})()}

<Typography sx={{ fontSize: 12 }}>{data.label}</Typography>
{!!data.outputs && (
<Handle
type="source"
position={sourcePosition}
isConnectable={isConnectable}
/>
)}
<Handle
type="source"
position={sourcePosition}
isConnectable={isConnectable}
/>
</Paper>
</ElectronTooltip>
)
Expand Down
10 changes: 4 additions & 6 deletions covalent_ui/webapp/src/components/graph/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ const mapGraphToElements = (graph, direction, showParams) => {
}

const nodes = _.map(graph.nodes, (node) => {
const { inputs, outputs } = countEdges(node.id, graph.links)
const handlePositions = getHandlePositions(direction)
const isParam = isParameter(node)

Expand All @@ -66,8 +65,6 @@ const mapGraphToElements = (graph, direction, showParams) => {
fullName: name,
label: _.truncate(name, { length: 70 }),
status: node.status,
inputs,
outputs,
},
targetPosition: handlePositions.target,
sourcePosition: handlePositions.source,
Expand Down Expand Up @@ -103,8 +100,9 @@ const assignNodePositions = (elements, direction) => {
dagreGraph.setDefaultEdgeLabel(() => ({}))
dagreGraph.setGraph({
rankdir: direction,
nodesep: 75,
ranksep: 100,
nodesep: 50,
ranksep: 75,
edgesep: 10,
})

_.each(elements, (el) => {
Expand Down Expand Up @@ -157,7 +155,7 @@ const getHandlePositions = (direction) => {
}
}

const countEdges = (nodeId, edges) => {
export const countEdges = (nodeId, edges) => {
return _.reduce(
edges,
(res, edge) => {
Expand Down
4 changes: 3 additions & 1 deletion covalent_ui/webapp/src/redux/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export default function configureAppStore(preloadedState) {
preloadedState,
enhancers: [
// persist state across sessions except for demo
isDemo ? demoEnhancer : persistState(['latticePreview']),
isDemo
? demoEnhancer
: persistState(['latticePreview'], { key: 'cache' }),
],
})

Expand Down

0 comments on commit 38d8e2f

Please sign in to comment.