From d45b23c7dc39d22133cd98c7430aabaafeaf7732 Mon Sep 17 00:00:00 2001 From: mary-martin Date: Mon, 22 May 2023 18:08:54 -0600 Subject: [PATCH 1/8] add drawer to updated dev code --- app.py | 47 +++----------------- static/src/App.js | 8 +++- static/src/template/Canvas.jsx | 6 --- static/src/template/GraphEdit.jsx | 2 +- static/src/template/MuiDrawer.jsx | 4 -- static/src/template/Viewer.jsx | 72 +++++++------------------------ 6 files changed, 29 insertions(+), 110 deletions(-) diff --git a/app.py b/app.py index 6fd646b..ea10af1 100644 --- a/app.py +++ b/app.py @@ -276,8 +276,6 @@ def get_nodes_and_edges(schema_json): entity_id = participant['entity'] if entity_id == '': entity_id = "Entities/20000/" - elif not entity_id.startswith("Entities/"): - entity_id = "Entities/" + entity_id edge = create_edge(event_id, entity_id, _label, _edge_type='step_participant') edge['data']['@id'] = participant['@id'] edges.append(edge) @@ -322,7 +320,7 @@ def get_nodes_and_edges(schema_json): # find root node(s) parentless_edge = {} for edge in edges: - if 'source' in edge['data'] and edge['data']['source'] in nodes: + if edge['data']['source'] not in parentless_edge: if nodes[edge['data']['source']]['data']['_type'] == 'entity': parentless_edge[edge['data']['source']] = False else: @@ -543,16 +541,17 @@ def add_entity_to_event(): event_id = data.get('event_id') entity_data = data.get('entity_data') + # Remove the 'event' and 'entity' values from entity_data + del entity_data['event'] + print('entity_data', entity_data) + # Find the event with the given ID and add the entity to its entities list for event in schema_json['events']: if event['@id'] == event_id: - # Ensure the 'entities' key exists in the event dictionary - if 'entities' not in event: - event['entities'] = [] event['entities'].append(entity_data) # Print the updated schema for confirmation - # print(json.dumps(schema_json, indent=2)) + print(json.dumps(schema_json, indent=2)) # Return a success response return schema_json @@ -569,7 +568,7 @@ def add_participant_to_event(): event['participants'].append(participant_data) # Print the updated schema for confirmation - # print(json.dumps(schema_json, indent=2)) + print(json.dumps(schema_json, indent=2)) # Return a success response return schema_json @@ -694,38 +693,6 @@ def upload(): 'schemaJson': schema_json }) -@app.route('/delete_entity', methods=['DELETE']) -def delete_entity(): - entity_id = request.json.get('entity_id') - - # Remove the entity from the schema_json['events']['entities'] - for event in schema_json['events']: - if 'entities' in event: - event['entities'] = [entity for entity in event['entities'] if entity.get('@id') != entity_id] - - # Remove the entity from the participants' 'entity' field - for event in schema_json['events']: - if 'participants' in event: - event['participants'] = [ - participant for participant in event['participants'] if participant.get('entity') != entity_id - ] - - # Remove relations with matching relationSubject or relationObject - for event in schema_json['events']: - if 'relations' in event: - event['relations'] = [ - relation for relation in event['relations'] - if relation.get('relationSubject') != entity_id and relation.get('relationObject') != entity_id - ] - - # Reload the schema to update the nodes and edges - nodes, edges = get_nodes_and_edges(schema_json) - - return jsonify({ - 'nodes': nodes, - 'edges': edges - }) - # TODO: get_subtree_or_update_node not accessed @app.route('/node', methods=['GET', 'POST']) def get_subtree_or_update_node(): diff --git a/static/src/App.js b/static/src/App.js index 8aae724..a36c9f5 100644 --- a/static/src/App.js +++ b/static/src/App.js @@ -122,11 +122,15 @@ export default function App() { - } /> - } /> + } + /> ); diff --git a/static/src/template/Canvas.jsx b/static/src/template/Canvas.jsx index 7f9f346..c6c78ff 100644 --- a/static/src/template/Canvas.jsx +++ b/static/src/template/Canvas.jsx @@ -81,7 +81,6 @@ constructor(props) { }; this.state.topTree = treeData; - this.showSidebar = this.showSidebar.bind(this); this.showSubTree = this.showSubTree.bind(this); this.removeSubTree = this.removeSubTree.bind(this); this.runLayout = this.runLayout.bind(this); @@ -289,10 +288,6 @@ handleDeleteEntity = (entityId) => { } }; -showSidebar(data) { - this.props.sidebarCallback(data); -} - saveGraphState() { this.graphHistory.push(this.cy.json()); } @@ -840,7 +835,6 @@ render() { isOpen={this.state.isGraphEditOpen} handleOpen={this.handleOpen} handleSubmit={this.handleSubmit} - sideEditorCallback={this.props.sideEditorCallback} addChapterEvent={this.props.addChapterEvent} /> { // Add outlink to selected element } else { // Update element fields - props.sideEditorCallback(node_data); + // props.sideEditorCallback(node_data); // Update the events list in the schema JSON with the new chapter event if (node_data.updatedFields.name) { diff --git a/static/src/template/MuiDrawer.jsx b/static/src/template/MuiDrawer.jsx index e56bc26..4c8a4cd 100644 --- a/static/src/template/MuiDrawer.jsx +++ b/static/src/template/MuiDrawer.jsx @@ -6,10 +6,6 @@ import JsonEdit from './JsonEdit'; const MuiDrawer = (props) => { const theme = useTheme(); - const [drawerOpen, setDrawerOpen] = useState(false); - const handleDrawerToggle = () => { - setDrawerOpen(!drawerOpen); - }; const handleJsonEditCallback = (json) => { console.log('JSON passed to MuiDrawer:', json); diff --git a/static/src/template/Viewer.jsx b/static/src/template/Viewer.jsx index 9bb885f..2260388 100644 --- a/static/src/template/Viewer.jsx +++ b/static/src/template/Viewer.jsx @@ -10,8 +10,6 @@ import axios from 'axios'; import UploadModal from './UploadModal'; import MuiDrawer from './MuiDrawer'; import Canvas from './Canvas'; -import SideEditor from './SideEditor'; -import JsonEdit from './JsonEdit'; /* Viewer page for the schema interface. */ class Viewer extends Component { @@ -32,8 +30,6 @@ class Viewer extends Component { this.callbackFunction = this.callbackFunction.bind(this); this.jsonEditorCallback = this.jsonEditorCallback.bind(this); - this.sidebarCallback = this.sidebarCallback.bind(this); - this.sideEditorCallback = this.sideEditorCallback.bind(this); this.download = this.download.bind(this); } @@ -90,74 +86,42 @@ class Viewer extends Component { }); } - sidebarCallback(data) { - /* Opens / closes the sidebar */ - if (isEmpty(data)) { - this.setState({ - isOpen: false, - nodeData: data - }); - } else { - this.setState({ - isOpen: true, - nodeData: data - }); - } - } - - sideEditorCallback(data) { - /* Handles changes through the sidebar */ - axios.post("/node", data) - .then(res => { - this.jsonEditorCallback(res.data); - }) - .catch(err => { - let error = err.response.data; - let error_title = error.slice(error.indexOf("") + 7, error.lastIndexOf("")); - let error_notif = error_title.slice(0, error_title.indexOf("//")); - toast.error(error_notif); - return false; - }); - } - render() { let canvas = ""; let schemaHeading = ""; - let jsonEdit = ""; - let sidebarClassName = this.state.isOpen ? "sidebar-open" : "sidebar-closed"; + let muiDrawer = ""; let canvasClassName = this.state.isOpen ? "canvas-shrunk" : "canvas-wide"; - + // a schema exists if (this.state.schemaResponse !== '') { // title of schema schemaHeading =

{this.state.schemaName}

; - + // graph (cytoscape) canvas = ; - - jsonEdit = + + muiDrawer = ; + } - + return ( ) From 8812a31a799895cb44f1c0678329a182020a8515 Mon Sep 17 00:00:00 2001 From: Reece Suchocki Date: Mon, 17 Jul 2023 03:02:41 -0600 Subject: [PATCH 2/8] fix onSubmit button --- .gitignore | 2 +- app.py | 75 +++++++++--------- static/src/template/Canvas.jsx | 83 +++++++++++++++++--- static/src/template/GraphEdit.jsx | 122 ++++++++++++++++++++---------- static/src/template/Viewer.jsx | 71 +++++++++++++---- 5 files changed, 248 insertions(+), 105 deletions(-) diff --git a/.gitignore b/.gitignore index b812ce3..d1a3b2d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ __pycache__ node_modules venv env -dist +# dist temp.txt \ No newline at end of file diff --git a/app.py b/app.py index ea10af1..165140e 100644 --- a/app.py +++ b/app.py @@ -23,35 +23,6 @@ 'relation': ['name', 'wd_node', 'wd_label', 'modality', 'wd_description', 'ta1ref', 'relationSubject', 'relationObject', 'relationPredicate'] } -# # def transform_version() - -# def is_ta2_format(data): -# return '@context' in data and 'instances' in data - -# def convert_ta2_to_ta1_format(ta2): -# ta1 = { -# 'events': [], -# 'entities': [], -# 'relations': [], -# } - -# if ta2['instances'] and len(ta2['instances']) > 0: -# instance = ta2['instances'][0] - -# for event in instance['events']: -# new_event = event.copy() -# if 'entities' in event: -# for entity in event['entities']: -# ta1['entities'].append(entity) -# del new_event['entities'] -# if 'relations' in event: -# for relation in event['relations']: -# ta1['relations'].append(relation) -# del new_event['relations'] -# ta1['events'].append(new_event) - -# return ta1 - def create_node(_id, _label, _type, _shape=''): """Creates a node. @@ -334,8 +305,6 @@ def get_nodes_and_edges(schema_json): # Zoey wants an entity-first view, so all entities are shown, with groups of events around them in clusters # Q: are we able to make a tab on the viewer itself to switch between views? - # print("\nnodes from get_nodes_and_edges:", nodes) - # print("\nedges from get_nodes_and_edges:", edges) return nodes, edges # NOTE: These are new?? @@ -482,6 +451,7 @@ def append_node(): """ global schema_json new_event = request.get_json() + print('Received data:', new_event) selected_element = new_event['parent_id'] #request.args.get('selected_element') del new_event['parent_id'] @@ -541,17 +511,16 @@ def add_entity_to_event(): event_id = data.get('event_id') entity_data = data.get('entity_data') - # Remove the 'event' and 'entity' values from entity_data - del entity_data['event'] - print('entity_data', entity_data) - # Find the event with the given ID and add the entity to its entities list for event in schema_json['events']: if event['@id'] == event_id: + # Ensure the 'entities' key exists in the event dictionary + if 'entities' not in event: + event['entities'] = [] event['entities'].append(entity_data) # Print the updated schema for confirmation - print(json.dumps(schema_json, indent=2)) + # print(json.dumps(schema_json, indent=2)) # Return a success response return schema_json @@ -568,7 +537,7 @@ def add_participant_to_event(): event['participants'].append(participant_data) # Print the updated schema for confirmation - print(json.dumps(schema_json, indent=2)) + # print(json.dumps(schema_json, indent=2)) # Return a success response return schema_json @@ -693,6 +662,38 @@ def upload(): 'schemaJson': schema_json }) +@app.route('/delete_entity', methods=['DELETE']) +def delete_entity(): + entity_id = request.json.get('entity_id') + + # Remove the entity from the schema_json['events']['entities'] + for event in schema_json['events']: + if 'entities' in event: + event['entities'] = [entity for entity in event['entities'] if entity.get('@id') != entity_id] + + # Remove the entity from the participants' 'entity' field + for event in schema_json['events']: + if 'participants' in event: + event['participants'] = [ + participant for participant in event['participants'] if participant.get('entity') != entity_id + ] + + # Remove relations with matching relationSubject or relationObject + for event in schema_json['events']: + if 'relations' in event: + event['relations'] = [ + relation for relation in event['relations'] + if relation.get('relationSubject') != entity_id and relation.get('relationObject') != entity_id + ] + + # Reload the schema to update the nodes and edges + nodes, edges = get_nodes_and_edges(schema_json) + + return jsonify({ + 'nodes': nodes, + 'edges': edges + }) + # TODO: get_subtree_or_update_node not accessed @app.route('/node', methods=['GET', 'POST']) def get_subtree_or_update_node(): diff --git a/static/src/template/Canvas.jsx b/static/src/template/Canvas.jsx index c6c78ff..d5673a1 100644 --- a/static/src/template/Canvas.jsx +++ b/static/src/template/Canvas.jsx @@ -1,5 +1,6 @@ import React from 'react'; import axios from 'axios'; +import { ToastContainer, toast } from 'react-toastify'; import templates from './templates'; import GraphEdit from './GraphEdit'; @@ -28,8 +29,8 @@ import DeleteIcon from '@mui/icons-material/Delete'; import CloseIcon from '@material-ui/icons/Close'; import Button from '@material-ui/core/Button'; import IconButton from '@mui/material/IconButton'; +import EditIcon from '@mui/icons-material/Edit'; import Typography from '@mui/material/Typography'; -import FileCopyIcon from '@mui/icons-material/FileCopy' import 'cytoscape-context-menus/cytoscape-context-menus.css'; import "cytoscape-navigator/cytoscape.js-navigator.css"; @@ -42,7 +43,6 @@ cytoscape.use(cytoscapeNavigator); let event_counter = 20000; let entity_counter = 10000; let relation_counter = 30000; -let participant_counter = 20000; class Canvas extends React.Component { constructor(props) { @@ -61,6 +61,7 @@ constructor(props) { dialogContent: null, event_counter: 20000, entity_counter: 10000, + participant_counter: 20000, isAddEntityDialogOpen: false, isAddParticipantDialogOpen: false, addRelationDialogOpen: false, @@ -81,6 +82,7 @@ constructor(props) { }; this.state.topTree = treeData; + this.showSidebar = this.showSidebar.bind(this); this.showSubTree = this.showSubTree.bind(this); this.removeSubTree = this.removeSubTree.bind(this); this.runLayout = this.runLayout.bind(this); @@ -125,23 +127,46 @@ handleCloseAddParticipantDialog = () => { handleAddParticipant = ({ participantName, participantRoleName, selectedEntity }) => { if (participantName) { + const newCounter = this.state.participant_counter + 1; + const participant = { ...templates.participant, - '@id': `Participants/${participant_counter++}/${participantName}`, + '@id': `Participants/${newCounter}/${participantName}`, 'roleName': participantRoleName, 'entity': selectedEntity }; + this.setState(prevState => ({ + participant_counter: prevState.participant_counter + 1 + })); + axios.post("/add_participant", { event_id: this.state.selectedElementForAddParticipant['@id'], participant_data: participant }) .then(res => { console.log("Response from server: ", res.data); - this.props.updateCallback(res.data); + + // Increment participant_counter in the .then callback + this.setState({ participant_counter: this.state.participant_counter + 1 }); + + const newSchema = res.data; + this.setState({ + canvasElements: CytoscapeComponent.normalizeElements(newSchema.events) + }, () => this.reloadCanvas()); // refresh the graph right after updating the state + + if (this.props.callbackFunction) { + this.props.callbackFunction(res.data); + } + + // Display success toast + toast.success('Participant added successfully!'); }) .catch(err => { console.error(err); + + // Display error toast + toast.error('Failed to add participant.'); }); this.handleCloseAddParticipantDialog(); @@ -168,10 +193,22 @@ onSubmitEvent = (newEvent) => { }) .then(res => { console.log("Response from server: ", res.data); - this.props.updateCallback(res.data); + + // Update the state with the new schema + const newSchema = res.data; + this.setState({ + canvasElements: CytoscapeComponent.normalizeElements(newSchema.events) + }, () => this.reloadCanvas()); // refresh the graph right after updating the state + + if (this.props.callbackFunction) { + this.props.callbackFunction(res.data); + } + + toast.success('Event added successfully!'); // Display success toast }) .catch(err => { console.error(err); + toast.error('Failed to add event.'); // Display error toast }); }; @@ -208,8 +245,8 @@ handleAddRelation = ({ relationName, wdNode, wdLabel, wdDescription, selectedEnt }) .then(res => { console.log("Response from server: ", res.data); - if (this.props.updateCallback) { - this.props.updateCallback(res.data); + if (this.props.callbackFunction) { + this.props.callbackFunction(res.data); } }) .catch(err => { @@ -246,12 +283,26 @@ handleAddEntity = (newEntity) => { console.log("Response from server: ", res.data); // increment entity_counter in the .then callback this.setState({ entity_counter: this.state.entity_counter + 1 }); - if (this.props.updateCallback) { - this.props.updateCallback(res.data); + + // Update the state with the new schema + // This assumes that `canvasElements` represents the current schema + const newSchema = res.data; + this.setState({ + canvasElements: CytoscapeComponent.normalizeElements(newSchema.events) + }, () => this.reloadCanvas()); // refresh the graph right after updating the state + + if (this.props.callbackFunction) { + this.props.callbackFunction(res.data); } + + // Display success toast + toast.success('Entity added successfully!'); }) .catch(err => { console.error(err); + + // Display error toast + toast.error('Failed to add entity.'); }); }; @@ -288,6 +339,10 @@ handleDeleteEntity = (entityId) => { } }; +showSidebar(data) { + this.props.sidebarCallback(data); +} + saveGraphState() { this.graphHistory.push(this.cy.json()); } @@ -798,6 +853,13 @@ render() { onClick={this.reloadCanvas} /> + + + ); diff --git a/static/src/template/GraphEdit.jsx b/static/src/template/GraphEdit.jsx index 6c3e8bf..97af8b7 100644 --- a/static/src/template/GraphEdit.jsx +++ b/static/src/template/GraphEdit.jsx @@ -15,7 +15,8 @@ import { Typography, Paper, Box, - makeStyles + makeStyles, + Slider } from "@material-ui/core"; import _ from "lodash"; import Draggable from 'react-draggable'; @@ -30,21 +31,22 @@ function PaperComponent(props) { const useStyles = makeStyles((theme) => ({ halfWidthDialog: { - width: '50%', // Change the width of the dialog to 50% + width: '50%', }, dialogTitle: { fontSize: '3rem', - color: blue[900], // Change color to darker blue + color: blue[900], }, header: { - fontSize: '1rem', // normal size - fontWeight: 'bold', // make the font bold - color: blue[900], // Change color to darker blue + fontSize: '1rem', + fontWeight: 'bold', + color: blue[900], + marginTop: theme.spacing(1), }, multilineInput: { - minHeight: '3em', // Set the minimum height to accommodate 3 lines - maxHeight: '6em', // Set the maximum height to accommodate 3 lines - overflow: 'hidden', // Clip text to the last line + minHeight: '3em', + maxHeight: '6em', + overflow: 'hidden', }, })); @@ -60,7 +62,20 @@ const GraphEdit = React.forwardRef((props, ref) => { const [data, setData] = useState(initData); const [edit, setEdit] = useState(""); const [open, setOpen] = useState(!!props.selectedElement); - const refFocus = useRef(null); + // const refFocus = useRef(null); + + const handleSliderChange = (e, value) => { + setData(prevData => { + const newSelectedElement = { + ...prevData.selectedElement, + 'importance': [Math.round(value * 100)], + }; + return { + ...prevData, + selectedElement: newSelectedElement, + }; + }); + }; // Add a useEffect hook to fetch entity names from the server useEffect(() => { @@ -118,19 +133,19 @@ const GraphEdit = React.forwardRef((props, ref) => { }); }; - const handleSwitchChange = (e) => { - // update data state with the new value - setData(prevData => { - const newSelectedElement = { - ...prevData.selectedElement, - [e.target.name]: e.target.checked, - }; - return { - ...prevData, - selectedElement: newSelectedElement, - }; - }); - }; + // const handleSwitchChange = (e) => { + // // update data state with the new value + // setData(prevData => { + // const newSelectedElement = { + // ...prevData.selectedElement, + // [e.target.name]: e.target.checked, + // }; + // return { + // ...prevData, + // selectedElement: newSelectedElement, + // }; + // }); + // }; const handleBooleanChange = (e) => { const targetName = e.target.name; @@ -148,20 +163,23 @@ const GraphEdit = React.forwardRef((props, ref) => { }); }; - const addChapterEventIdToChildren = (newEventId, selectedElementId) => { - schema_json['events'].forEach(element => { - if (element['@id'] === selectedElementId) { - if (!element.children) { - element.children = [newEventId]; - } else { - element.children.push(newEventId); - } - } - }); - }; + // const addChapterEventIdToChildren = (newEventId, selectedElementId) => { + // schema_json['events'].forEach(element => { + // if (element['@id'] === selectedElementId) { + // if (!element.children) { + // element.children = [newEventId]; + // } else { + // element.children.push(newEventId); + // } + // } + // }); + // }; const handleSubmit = (e) => { // create data to pass up + if (data.selectedElement['importance']) { + data.selectedElement['importance'] = [Math.round(data.selectedElement['importance'][0] * 100)]; + } const node_data = { id: data.selectedElement['id'], updatedFields: {}, @@ -175,13 +193,13 @@ const GraphEdit = React.forwardRef((props, ref) => { } }); - // console.log("\n(GRAPHEDIT.JSX) The node data from handleSubmit:\n", node_data); + console.log("(GRAPHEDIT.JSX) The node data from handleSubmit:\n", node_data); // change sidebar internal id if the id is changed if (e.target.id === '@id') { data.selectedElement['id'] = e.target.value; setData({ ...data }); - // console.log("(GRAPHEDIT.JSX) Selected element id updated to:", data.selectedElement['id']); + console.log("(GRAPHEDIT.JSX) Selected element id updated to:", data.selectedElement['id']); } // Determine which action to take based on the props @@ -189,15 +207,15 @@ const GraphEdit = React.forwardRef((props, ref) => { // Add outlink to selected element } else { // Update element fields - // props.sideEditorCallback(node_data); + props.sideEditorCallback(node_data); // Update the events list in the schema JSON with the new chapter event if (node_data.updatedFields.name) { - // console.log("(GRAPHEDIT.JSX) Sending chapter event to server:", data.selectedElement); + console.log("(GRAPHEDIT.JSX) Sending chapter event to server:", data.selectedElement); axios.post("/add_event", data.selectedElement) .then(res => { console.log("Response from server: ", res.data); - props.updateCallback(res.data); + props.callbackFunction(res.data); // or props.updateCallback(res.data); }) .catch(err => { console.error(err); @@ -208,6 +226,7 @@ const GraphEdit = React.forwardRef((props, ref) => { handleClose(); }; + const handleClose = () => { // close the dialog // console.log("Closing dialog"); @@ -217,12 +236,13 @@ const GraphEdit = React.forwardRef((props, ref) => { let i = 0; const excluded_ids = ['id', '_label', '_type', '_shape', '_edge_type', 'child','outlinks', 'relations', 'children_gate', 'key', 'modality'] - const selectedElement = data.selectedElement || {}; + // const selectedElement = data.selectedElement || {}; return ( {isEmpty(data) ? "" : data.selectedElement?.["_label"]} + {/* */} {isEmpty(data) ? ( "" ) : ( @@ -233,6 +253,25 @@ const GraphEdit = React.forwardRef((props, ref) => {
{data.selectedElement && Object.entries(data.selectedElement).map(([key, val]) => { + // Add a slider for the 'importance' field + if (key === 'importance') { + return ( + + + Importance + + + + ); + } if (excluded_ids.includes(key) || ['participants', 'children', 'entities'].includes(key)) return null; return ( @@ -274,7 +313,7 @@ const GraphEdit = React.forwardRef((props, ref) => { if (val && val.length > 0) { return ( - {_.capitalize(key)} + {_.capitalize(key)} {val.map(v => (v["@id"] || v["name"]) ? (v["name"] || data.entityNames[v["@id"]] || data.eventNames[v["@id"]] || v["@id"]) : v).join(", ")} ); @@ -292,4 +331,5 @@ const GraphEdit = React.forwardRef((props, ref) => {
); }); + export default GraphEdit; \ No newline at end of file diff --git a/static/src/template/Viewer.jsx b/static/src/template/Viewer.jsx index 2260388..d167b5d 100644 --- a/static/src/template/Viewer.jsx +++ b/static/src/template/Viewer.jsx @@ -4,12 +4,13 @@ import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import IconButton from '@mui/material/IconButton'; import DownloadIcon from '@mui/icons-material/CloudDownload'; -import Tooltip from '@mui/material/Tooltip'; import axios from 'axios'; import UploadModal from './UploadModal'; import MuiDrawer from './MuiDrawer'; import Canvas from './Canvas'; +import SideEditor from './SideEditor'; +import JsonEdit from './JsonEdit'; /* Viewer page for the schema interface. */ class Viewer extends Component { @@ -30,6 +31,8 @@ class Viewer extends Component { this.callbackFunction = this.callbackFunction.bind(this); this.jsonEditorCallback = this.jsonEditorCallback.bind(this); + this.sidebarCallback = this.sidebarCallback.bind(this); + this.sideEditorCallback = this.sideEditorCallback.bind(this); this.download = this.download.bind(this); } @@ -86,42 +89,72 @@ class Viewer extends Component { }); } + sidebarCallback(data) { + /* Opens / closes the sidebar */ + if (isEmpty(data)) { + this.setState({ + isOpen: false, + nodeData: data + }); + } else { + this.setState({ + isOpen: true, + nodeData: data + }); + } + } + + sideEditorCallback(data) { + /* Handles changes through the sidebar */ + axios.post("/node", data) + .then(res => { + this.jsonEditorCallback(res.data); + }) + .catch(err => { + let error = err.response.data; + let error_title = error.slice(error.indexOf("") + 7, error.lastIndexOf("")); + let error_notif = error_title.slice(0, error_title.indexOf("//")); + toast.error(error_notif); + return false; + }); + } + render() { let canvas = ""; let schemaHeading = ""; - let muiDrawer = ""; + let jsonEdit = ""; + let sidebarClassName = this.state.isOpen ? "sidebar-open" : "sidebar-closed"; let canvasClassName = this.state.isOpen ? "canvas-shrunk" : "canvas-wide"; - + // a schema exists if (this.state.schemaResponse !== '') { // title of schema schemaHeading =

{this.state.schemaName}

; - + // graph (cytoscape) canvas = ; - - muiDrawer = ; - + + jsonEdit = } - + return (
) From 2f621954081e6665983107f27537e24305f7fa20 Mon Sep 17 00:00:00 2001 From: mary-martin Date: Mon, 17 Jul 2023 21:44:10 -0600 Subject: [PATCH 3/8] redo fixes --- static/src/template/Viewer.jsx | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/static/src/template/Viewer.jsx b/static/src/template/Viewer.jsx index d167b5d..ca7b1a8 100644 --- a/static/src/template/Viewer.jsx +++ b/static/src/template/Viewer.jsx @@ -122,7 +122,7 @@ class Viewer extends Component { render() { let canvas = ""; let schemaHeading = ""; - let jsonEdit = ""; + let muiDrawer = ""; let sidebarClassName = this.state.isOpen ? "sidebar-open" : "sidebar-closed"; let canvasClassName = this.state.isOpen ? "canvas-shrunk" : "canvas-wide"; @@ -141,11 +141,12 @@ class Viewer extends Component { className={canvasClassName} />; - jsonEdit = + muiDrawer = ; } return ( @@ -165,14 +166,8 @@ class Viewer extends Component {
{schemaHeading}
{/* {console.log("Testing from Viewer.jsx", this.state.schemaJson)} */} - - + {muiDrawer} {canvas} - {jsonEdit}
) From 72233c7ae7c4bc9976d59145c7a557620117e56f Mon Sep 17 00:00:00 2001 From: mary-martin Date: Mon, 17 Jul 2023 21:44:45 -0600 Subject: [PATCH 4/8] redo fixes --- static/src/template/Viewer.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/src/template/Viewer.jsx b/static/src/template/Viewer.jsx index ca7b1a8..cdbc6b2 100644 --- a/static/src/template/Viewer.jsx +++ b/static/src/template/Viewer.jsx @@ -9,8 +9,6 @@ import axios from 'axios'; import UploadModal from './UploadModal'; import MuiDrawer from './MuiDrawer'; import Canvas from './Canvas'; -import SideEditor from './SideEditor'; -import JsonEdit from './JsonEdit'; /* Viewer page for the schema interface. */ class Viewer extends Component { From 5aca67d4a16c95e5444dba0b42f78924f10f9a3c Mon Sep 17 00:00:00 2001 From: Reece Suchocki Date: Tue, 18 Jul 2023 00:05:35 -0600 Subject: [PATCH 5/8] importance slider and dialog close --- .gitignore | 2 +- static/src/template/AddEntity.jsx | 1 + static/src/template/AddEvent.jsx | 57 ++++++++++++++++--------------- static/src/template/GraphEdit.jsx | 7 ++-- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index d1a3b2d..b812ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ __pycache__ node_modules venv env -# dist +dist temp.txt \ No newline at end of file diff --git a/static/src/template/AddEntity.jsx b/static/src/template/AddEntity.jsx index 45fd195..ea80d05 100644 --- a/static/src/template/AddEntity.jsx +++ b/static/src/template/AddEntity.jsx @@ -38,6 +38,7 @@ function AddEntityDialog({ open, onClose, onSubmit, selectedElementForAddEntity, setEntityWdNode(''); setEntityWdLabel(''); setEntityWdDescription(''); + onClose(); // Added onClose here }; return ( diff --git a/static/src/template/AddEvent.jsx b/static/src/template/AddEvent.jsx index 3921898..ffcb932 100644 --- a/static/src/template/AddEvent.jsx +++ b/static/src/template/AddEvent.jsx @@ -35,39 +35,40 @@ function AddEventDialog({ open, onClose, onSubmit }) { onSubmit(newEvent); setEventName(''); setIsChapterEvent(false); + onClose(); // Added onClose here }; return ( - Add Event - - - Please enter event name. - - setEventName(e.target.value)} - /> - setIsChapterEvent(e.target.checked)} />} - label="Event Type" - /> - - - - - + Add Event + + + Please enter event name. + + setEventName(e.target.value)} + /> + setIsChapterEvent(e.target.checked)} />} + label="Event Type" + /> + + + + + ); } -export default AddEventDialog; +export default AddEventDialog; \ No newline at end of file diff --git a/static/src/template/GraphEdit.jsx b/static/src/template/GraphEdit.jsx index 97af8b7..ac8c399 100644 --- a/static/src/template/GraphEdit.jsx +++ b/static/src/template/GraphEdit.jsx @@ -68,7 +68,7 @@ const GraphEdit = React.forwardRef((props, ref) => { setData(prevData => { const newSelectedElement = { ...prevData.selectedElement, - 'importance': [Math.round(value * 100)], + 'importance': [value], }; return { ...prevData, @@ -177,9 +177,6 @@ const GraphEdit = React.forwardRef((props, ref) => { const handleSubmit = (e) => { // create data to pass up - if (data.selectedElement['importance']) { - data.selectedElement['importance'] = [Math.round(data.selectedElement['importance'][0] * 100)]; - } const node_data = { id: data.selectedElement['id'], updatedFields: {}, @@ -261,7 +258,7 @@ const GraphEdit = React.forwardRef((props, ref) => { Importance Date: Tue, 18 Jul 2023 12:27:35 -0600 Subject: [PATCH 6/8] Update run_standalone_server.sh --- run_standalone_server.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/run_standalone_server.sh b/run_standalone_server.sh index 5cf7f51..ae2ca61 100755 --- a/run_standalone_server.sh +++ b/run_standalone_server.sh @@ -6,6 +6,7 @@ PATH=$APP_DIR/venv/bin:$PATH echo "Creating bundle.js" cd "$APP_DIR"/static +npm install npm run build cd "$APP_DIR" From f5a2feba78a6554fd0332ea4898a961cec5e611b Mon Sep 17 00:00:00 2001 From: Reece Suchocki Date: Mon, 21 Aug 2023 14:01:17 -0600 Subject: [PATCH 7/8] fix selectedElement bug --- static/src/template/Canvas.jsx | 5 +++++ static/src/template/GraphEdit.jsx | 1 + 2 files changed, 6 insertions(+) diff --git a/static/src/template/Canvas.jsx b/static/src/template/Canvas.jsx index d5673a1..8f3302f 100644 --- a/static/src/template/Canvas.jsx +++ b/static/src/template/Canvas.jsx @@ -97,6 +97,10 @@ constructor(props) { // console.log('canvasElements:', this.state.canvasElements); } +resetSelectedElement = () => { + this.setState({ selectedElement: null }); +}; + handleNavigatorToggle = () => { this.setState((prevState) => ({ isNavigatorVisible: !prevState.isNavigatorVisible @@ -899,6 +903,7 @@ render() { handleSubmit={this.handleSubmit} sideEditorCallback={this.props.sideEditorCallback} addChapterEvent={this.props.addChapterEvent} + resetSelectedElement={this.resetSelectedElement} /> { // console.log("Closing dialog"); // console.log("Type of onClose: ", typeof props.onClose); setOpen(false); + props.resetSelectedElement(); }; let i = 0; From 966b259e0cd78903ccf893776ac5632443d43c35 Mon Sep 17 00:00:00 2001 From: Reece Suchocki Date: Sun, 26 Nov 2023 22:11:43 -0700 Subject: [PATCH 8/8] merge schema-interface/master --- static/src/App.js | 16 +---------- static/src/App.scss | 2 +- static/src/template/Canvas.jsx | 44 +++++++++++++++++++++++++------ static/src/template/GraphEdit.jsx | 1 + static/src/template/Home.jsx | 2 +- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/static/src/App.js b/static/src/App.js index a36c9f5..78b42b7 100644 --- a/static/src/App.js +++ b/static/src/App.js @@ -79,7 +79,7 @@ export default function App() { sx={{ flexGrow: 1, display: { xs: 'none', sm: 'block' } }} >
- - - - - diff --git a/static/src/App.scss b/static/src/App.scss index 3c7686c..9922eec 100644 --- a/static/src/App.scss +++ b/static/src/App.scss @@ -66,7 +66,7 @@ a { background: white !important; height: 25vh !important; width: 25vw !important; - margin-bottom: 24px; + margin-bottom: 45px; margin-right: 45px; z-index: 1; } diff --git a/static/src/template/Canvas.jsx b/static/src/template/Canvas.jsx index 8f3302f..d8e79a0 100644 --- a/static/src/template/Canvas.jsx +++ b/static/src/template/Canvas.jsx @@ -87,6 +87,7 @@ constructor(props) { this.removeSubTree = this.removeSubTree.bind(this); this.runLayout = this.runLayout.bind(this); this.reloadCanvas = this.reloadCanvas.bind(this); + this.updateGraph = this.updateGraph.bind(this); this.removeObject = this.removeObject.bind(this); this.restore = this.restore.bind(this); this.fitCanvas = this.fitCanvas.bind(this); @@ -419,14 +420,37 @@ runLayout() { } reloadCanvas() { - this.setState({ - canvasElements: CytoscapeComponent.normalizeElements(this.props.elements), - hasSubtree: false, - showParticipants: true - }); - this.cy.elements().remove(); - this.cy.add(this.state.canvasElements); - this.runLayout(); + this.setState({ + canvasElements: CytoscapeComponent.normalizeElements(this.props.elements), + hasSubtree: false, + showParticipants: true + }); + this.cy.elements().remove(); + this.cy.add(this.state.canvasElements); + this.runLayout(); +} + +updateGraph() { + // Store current positions + let nodePositions = {}; + this.cy.nodes().forEach(node => { + nodePositions[node.id()] = node.position(); + }); + + this.setState({ + canvasElements: CytoscapeComponent.normalizeElements(this.props.elements) + }); + + this.cy.elements().remove(); + this.cy.add(this.state.canvasElements); + + // Set the positions back to their original values + for (let nodeId in nodePositions) { + const node = this.cy.getElementById(nodeId); + if (node) { + node.position(nodePositions[nodeId]); + } + } } removeObject(event) { @@ -456,6 +480,8 @@ handleOpen() { handleClose = () => { this.setState({ isGraphEditOpen: false }); + selectedElement: null + this.reloadCanvas } fitCanvas() { @@ -904,6 +930,7 @@ render() { sideEditorCallback={this.props.sideEditorCallback} addChapterEvent={this.props.addChapterEvent} resetSelectedElement={this.resetSelectedElement} + updateGraph={this.updateGraph} /> { // console.log("Type of onClose: ", typeof props.onClose); setOpen(false); props.resetSelectedElement(); + props.updateGraph(); }; let i = 0; diff --git a/static/src/template/Home.jsx b/static/src/template/Home.jsx index 26b95b4..3ce72d1 100644 --- a/static/src/template/Home.jsx +++ b/static/src/template/Home.jsx @@ -5,7 +5,7 @@ class Home extends Component { render() { return ( -
SCI 3.0 is a web application designed to visualize complex events and curate them for research purposes.
+
CAI 1.0 is a web application designed to facilitate annotator adjudication for research purposes.
); }