Skip to content

Commit

Permalink
Move gm methods (#307)
Browse files Browse the repository at this point in the history
* Removes graphics method initialization function from backend. Begins creating GM creation modal

* Moves template and graphics method state around. Adds a ui model to seperate vcs state from ui state.

* Fixes a couple old references to local state. Fixes a typo.

* Adds functions to remove GMs.

* Adds code to remove temporary Gms and templates on load. Prevents users from making GMs with 2 underscores

* Adds more validation to Template creator. Checks if name starts with 2 underscores

* Adds toast when a user clicks edit with nothing selected for GMList

* Adds tests for GraphicsMethodCreator. Fixes a couple small issues.
  • Loading branch information
James-Crean authored Jun 1, 2018
1 parent 878c40c commit 1a9b20f
Show file tree
Hide file tree
Showing 15 changed files with 731 additions and 168 deletions.
19 changes: 0 additions & 19 deletions backend/vcdat/GraphicsMethods.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,10 @@
import numpy

_ = vcs.init()
_methods = {}
_2d_methods = ('scatter', 'vector', 'xvsy', 'stream', 'glyph', '3d_vector', '3d_dual_scalar')
_primitives = ('line', 'marker', 'fillarea', 'text')


def get_gm():
for t in vcs.graphicsmethodlist():
_methods[t] = {}
for m in vcs.elements[t].keys():
gm = vcs.elements[t][m]
_methods[t][m] = vcs.dumpToDict(gm)[0]
if hasattr(gm, "levels"):
arr = numpy.array(gm.levels)
if numpy.allclose(arr, 1e20) and arr.shape[-1] == 2:
_methods[t][m]["levels"] = [1e20, 1e20]
return _methods

def get_default_gms():
_defaults = {}
for t in vcs.graphicsmethodlist():
_defaults[t] = vcs.elements[t].keys()
return _defaults

def detect_nvars(g_type, g_method, g_obj):
"""Try to return the number of variables required for the plot method.
Returns the number of variables required by the plot type.
Expand Down
8 changes: 0 additions & 8 deletions backend/vcdat/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import cdms2
import json
from flask import Flask, send_from_directory, request, send_file, Response, jsonify
from GraphicsMethods import get_gm, get_default_gms
from Templates import templ_from_json
from Files import getFilesObject
from Colormaps import get_cmaps
Expand Down Expand Up @@ -120,13 +119,6 @@ def plot_template():
return resp


@app.route("/getGraphicsMethods")
@jsonresp
def get_graphics_methods():
graphics_methods = get_gm()
return json.dumps(graphics_methods)


@app.route("/getDefaultMethods")
@jsonresp
def get_default_methods():
Expand Down
4 changes: 4 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"description": "Front-end GUI for CDAT",
"main": "src/js/app.js",
"private": true,
"prettier": {
"printWidth": 150,
"tabWidth": 4
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"bootstrap-slider": "git://github.com/matthewma7/bootstrap-slider",
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/js/Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import GraphicsMethodModel from './models/GraphicsMethods.js';
import TemplateModel from './models/Templates.js';
import VariableModel from './models/Variables.js';
import SpreadsheetModel from './models/Spreadsheet.js';
import UIModel from './models/UI.js';

/* global $ */

Expand All @@ -16,7 +17,8 @@ const reducers = combineReducers({
graphics_methods: GraphicsMethodModel.reduce,
templates: TemplateModel.reduce,
sheets_model: SpreadsheetModel.reduce,
colormaps: ColormapModel.reduce
colormaps: ColormapModel.reduce,
ui: UIModel.reduce,
});

const undoableReducer = undoable(reducers,{
Expand All @@ -31,20 +33,21 @@ var store = null;
const configureStore = (initialState = {}) => {
let state = Promise.resolve(initialState);
if (Object.keys(initialState).length === 0) {
const models = [CachedFileModel, VariableModel, GraphicsMethodModel, TemplateModel, SpreadsheetModel, ColormapModel]
const models = [CachedFileModel, VariableModel, GraphicsMethodModel, TemplateModel, SpreadsheetModel, ColormapModel, UIModel]
const initialStates = models.map((m) => {
return m.getInitialState();
});
state = Promise.all(initialStates).then((values) => {
const cached_files = values[0], variables = values[1], graphics_methods = values[2], templates = values[3], sheets_model = values[4], colormaps = values[5];
const cached_files = values[0], variables = values[1], graphics_methods = values[2], templates = values[3], sheets_model = values[4], colormaps = values[5], ui = values[6];
return {
present: {
cached_files,
variables,
graphics_methods,
templates,
sheets_model,
colormaps
colormaps,
ui,
},
};
});
Expand Down
148 changes: 122 additions & 26 deletions frontend/src/js/components/GMList.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Actions from '../constants/Actions.js'
import PropTypes from 'prop-types'
import Dialog from 'react-bootstrap-dialog'
import AddEditRemoveNav from './AddEditRemoveNav/AddEditRemoveNav.jsx'
import GraphicsMethodCreator from './modals/GraphicsMethodCreator.jsx'
import GraphicsMethodEditor from './modals/GraphicsMethodEditor.jsx'
import Tree from './Tree.jsx'
import DragAndDropTypes from '../constants/DragAndDropTypes.js'
Expand Down Expand Up @@ -29,43 +33,97 @@ class GMList extends Component {
constructor(props){
super(props)
this.state = {
activeGM: false,
activeGMParent: false,
showModal: false
show_edit_modal: false,
show_create_modal: false,
}
this.clickedAdd = this.clickedAdd.bind(this)
this.clickedEdit = this.clickedEdit.bind(this)
this.closedModal = this.closedModal.bind(this)
this.confirmRemove = this.confirmRemove.bind(this)
this.removeGM = this.removeGM.bind(this)
this.closeEditModal = this.closeEditModal.bind(this)
this.selectedChild = this.selectedChild.bind(this)
}

clickedAdd() {
this.setState({show_create_modal: true})
}

clickedEdit() {
const gm = this.props.graphicsMethods[this.state.activeGMParent][this.state.activeGM]
if (SUPPORTED_GM_EDITORS && !SUPPORTED_GM_EDITORS.includes(gm.g_name)) {
if(!this.props.selected_graphics_type || !this.props.selected_graphics_method) {
toast.info("A Graphics Method must be selected to edit", { position: toast.POSITION.BOTTOM_CENTER })
return
}

const gm = this.props.graphics_methods[this.props.selected_graphics_type][this.props.selected_graphics_method]
if(SUPPORTED_GM_EDITORS && !SUPPORTED_GM_EDITORS.includes(gm.g_name)) {
toast.warn("This graphics method does not have an editor yet.", { position: toast.POSITION.BOTTOM_CENTER })
}
else {
this.setState({showModal: true})
this.setState({show_edit_modal: true})
}
}

confirmRemove() {
const type = this.props.selected_graphics_type
const name = this.props.selected_graphics_method
if( type && name ) {
this.dialog.show({
body: `Are you sure you want to delete "${name}"?`,
actions: [
Dialog.DefaultAction(
'Delete',
() => {
this.removeGM(type, name)
},
'btn-danger'
),
Dialog.CancelAction()
]
})
}
else {
toast.info("A Graphics Method must be selected to delete", { position: toast.POSITION.BOTTOM_CENTER })
}
}

removeGM(type, name) {
try {
vcs.removegraphicsmethod(type, name).then(() => {
this.props.removeGraphicsMethod(type, name)
},
(error) => {
console.warn(error)
try {
toast.error(error.data.exception, { position: toast.POSITION.BOTTOM_CENTER })
}
catch(e){
toast.error("An error occurred while attempting to delete a graphics method.", { position: toast.POSITION.BOTTOM_CENTER })
}
})
}
catch(e){
console.warn(e)
if(e instanceof ReferenceError) {
toast.error("VCS is not loaded. Try restarting vCDAT", { position: toast.POSITION.BOTTOM_CENTER })
}
}
}

closedModal() {
this.setState({showModal: false})
closeEditModal() {
this.setState({show_edit_modal: false})
}

selectedChild(path) {
if (path.length === 2) {
let gm = path[1]
let gm_parent = path[0]
this.setState({
activeGM: gm,
activeGMParent: gm_parent,
})
this.props.selectGraphicsMethod(gm_parent, gm)
}
}

render() {
const gmModel = Object.keys(this.props.graphicsMethods).sort().map((gmType) => {
const gms = Object.keys(this.props.graphicsMethods[gmType]).sort().map((gmname) => {
const gmModel = Object.keys(this.props.graphics_methods).sort().map((gmType) => {
const gms = Object.keys(this.props.graphics_methods[gmType]).sort().map((gmname) => {
return {
'title': gmname,
'gmType': gmType
Expand All @@ -82,27 +140,30 @@ class GMList extends Component {
<div className='left-side-list scroll-area-list-parent gm-list-container'>
<AddEditRemoveNav
title='Graphics Methods'
addAction={this.clickedAdd}
addText="Create a new Graphics Method"
editAction={this.clickedEdit}
addText="Creating a graphics method is not supported yet"
editText="Edit a selected graphics method"
removeAction={this.confirmRemove}
removeText="Removing a graphics method is not supported yet"
/>
{
(this.state && this.state.activeGM) ?
{(this.props.selected_graphics_type &&
this.props.selected_graphics_method &&
this.props.graphics_methods[this.props.selected_graphics_type][this.props.selected_graphics_method]) ?
<GraphicsMethodEditor
colormaps={this.props.colormaps}
graphicsMethod={this.props.graphicsMethods[this.state.activeGMParent][this.state.activeGM]}
graphicsMethod={this.props.graphics_methods[this.props.selected_graphics_type][this.props.selected_graphics_method]}
updateGraphicsMethod={this.props.updateGraphicsMethod}
show={this.state.showModal}
onHide={this.closedModal}
show={this.state.show_edit_modal}
onHide={this.closeEditModal}
/>
:
""
}
<div className='scroll-area'>
<Tree
activeLeaf={this.state.activeGM}
activeParent={this.state.activeGMParent}
activeLeaf={this.props.selected_graphics_method}
activeParent={this.props.selected_graphics_type}
dragSource={gmSource}
dragCollect={collect}
dragType={DragAndDropTypes.GM}
Expand All @@ -112,15 +173,50 @@ class GMList extends Component {
}}
/>
</div>
{ this.state.show_create_modal &&
<GraphicsMethodCreator
show={this.state.show_create_modal}
close={()=>{this.setState({show_create_modal: false})}}
graphics_methods={this.props.graphics_methods}
selectGM={this.props.selectGraphicsMethod}
/>
}
<Dialog ref={/* istanbul ignore next */ (el) => {this.dialog = el}} />
</div>
)
}
}

GMList.propTypes = {
graphicsMethods: PropTypes.object,
updateGraphicsMethod: PropTypes.func,
graphics_methods: PropTypes.object,
colormaps: PropTypes.object,
updateGraphicsMethod: PropTypes.func,
selectGraphicsMethod: PropTypes.func,
removeGraphicsMethod: PropTypes.func,
selected_graphics_method: PropTypes.string,
selected_graphics_type: PropTypes.string,
}

const mapStateToProps = (state) => {
return {
graphics_methods: state.present.graphics_methods,
selected_graphics_method: state.present.ui.selected_graphics_method,
selected_graphics_type: state.present.ui.selected_graphics_type,
}
}

const mapDispatchToProps = (dispatch) => {
return {
updateGraphicsMethod: (graphics_method) => {
dispatch(Actions.updateGraphicsMethod(graphics_method))
},
selectGraphicsMethod: (type, name) => {
dispatch(Actions.selectGraphicsMethod(type, name))
},
removeGraphicsMethod: (type, name) => {
dispatch(Actions.removeGraphicsMethod(type, name))
}
}
}

export default GMList
export default connect(mapStateToProps, mapDispatchToProps)(GMList)
10 changes: 9 additions & 1 deletion frontend/src/js/components/TemplateList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,15 @@ class TemplateList extends Component {
else{
this.setState({showTemplateEditor: true, template_data: "loading"})
return vcs.gettemplate(this.props.selected_template).then((data)=>{ // return promise for testing purposes
this.setState({template_data: data})
if(data) {
this.setState({template_data: data})
}
else { // data will be null if the selected template doesnt exist
// We can probably do more error handling here. Refresh the names, and deselect the selected template
toast.error(`${this.props.selected_template} doesn't exist on the server. Try refreshing the browser window.`,
{ position: toast.POSITION.BOTTOM_CENTER }
)
}
},
(error) => {
console.warn(error)
Expand Down
Loading

0 comments on commit 1a9b20f

Please sign in to comment.