Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/app/assets/templates/alexander.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"label": "Label",
"help": "A short title for the node",
"duplicateWarning": "You’re entering a duplicate node. Do you want to View the Existing node, or Continue creating?",
"sourceNodeIsLockedMessage": "This node is currently being editted by someone else, please try again later.",
"_cmt4": "/// `Label` is always required and cannot be hidden"
},
"type": {
Expand Down
46 changes: 46 additions & 0 deletions build/app/unisys/server-database.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ let m_max_nodeID;
let m_dupe_set; // set of nodeIDs for determine whether there are duplicates
let NODES; // loki "nodes" collection
let EDGES; // loki "edges" collection
let m_locked_nodes;
let m_locked_edges;

/// API METHODS ///////////////////////////////////////////////////////////////
/// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Expand Down Expand Up @@ -60,6 +62,7 @@ DB.InitializeDatabase = function(options = {}) {
// add (and configure) them now.
NODES = m_db.getCollection("nodes");
if (NODES === null) NODES = m_db.addCollection("nodes");
m_locked_nodes = new Set();
EDGES = m_db.getCollection("edges");
if (EDGES === null) EDGES = m_db.addCollection("edges");

Expand Down Expand Up @@ -170,6 +173,49 @@ DB.PKT_GetNewEdgeID = function(pkt) {
if (DBG) console.log(PR, `PKT_GetNewEdgeID ${pkt.Info()} edgeID ${m_max_edgeID}`);
return { edgeID: m_max_edgeID };
};
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DB.PKT_RequestLockNode = function(pkt) {
let { nodeID } = pkt.Data();
let errcode = m_IsInvalidNode( nodeID );
if (errcode) return errcode;
// check if node is already locked
if (m_locked_nodes.has(nodeID)) return m_MakeLockError(`nodeID ${nodeID} is already locked`);
// SUCCESS
// single matching node exists and is not yet locked, so lock it
m_locked_nodes.add(nodeID);
return { nodeID, locked : true };
};
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DB.PKT_RequestUnlockNode = function(pkt) {
let { nodeID } = pkt.Data();
let errcode = m_IsInvalidNode( nodeID );
if (errcode) return errcode;
// check that node is already locked
if (m_locked_nodes.has(nodeID)) {
m_locked_nodes.delete(nodeID);
return { nodeID, unlocked:true };
}
// this is an error because nodeID wasn't in the lock table
return m_MakeLockError(`nodeID ${nodeID} was not locked so can't unlock`);
};
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function m_IsInvalidNode ( nodeID ) {
if (!nodeID) return m_MakeLockError(`undefined nodeID`);
nodeID = Number.parseInt(nodeID,10);
if (isNaN(nodeID)) return m_MakeLockError(`nodeID was not a number`);
if (nodeID<0) return m_MakeLockError(`nodeID ${nodeID} must be positive integer`);
if (nodeID>m_max_nodeID) return m_MakeLockError(`nodeID ${nodeID} is out of range`);
// find if the node exists
let matches = NODES.find({ id: nodeID });
if (matches.length===0) return m_MakeLockError(`nodeID ${nodeID} not found`);
if (matches.length>1) return m_MakeLockError(`nodeID ${nodeID} matches multiple entries...critical error!`);
// no retval is no error!
return undefined;
}
function m_MakeLockError( info ) {
return { NOP:`ERR`, INFO:info };
}

/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DB.PKT_Update = function(pkt) {
let { node, edge, nodeID, replacementNodeID, edgeID } = pkt.Data();
Expand Down
10 changes: 10 additions & 0 deletions build/app/unisys/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ var UNISYS = {};
return UDB.PKT_GetNewNodeID(pkt);
});

UNET.HandleMessage('SRV_DBLOCKNODE',function(pkt) {
if (DBG) console.log(PR,sprint_message(pkt));
return UDB.PKT_RequestLockNode(pkt);
});

UNET.HandleMessage('SRV_DBUNLOCKNODE',function(pkt) {
if (DBG) console.log(PR,sprint_message(pkt));
return UDB.PKT_RequestUnlockNode(pkt);
});

UNET.HandleMessage('SRV_DBGETEDGEID',function(pkt) {
if (DBG) console.log(PR,sprint_message(pkt));
return UDB.PKT_GetNewEdgeID(pkt);
Expand Down
98 changes: 78 additions & 20 deletions build/app/view/netcreate/components/NodeSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@

isEditable If true, form fields are enabled for editing
If false, form is readonly

sourceNodeIsLocked
If someone else has selected the node for editing,
this flag will cause the sourceNodeIsLockedMessage
to be displayed. This is only checked when
the user clicks "Edit".


## TESTING
Expand Down Expand Up @@ -144,6 +150,7 @@ class NodeSelector extends UNISYS.Component {
},
edges: [],
isLocked: true,
sourceNodeIsLocked: false,
isEditable: false,
isValid: false,
isDuplicateNodeLabel: false,
Expand All @@ -167,6 +174,7 @@ class NodeSelector extends UNISYS.Component {
this.onNewNodeButtonClick = this.onNewNodeButtonClick.bind(this);
this.onDeleteButtonClick = this.onDeleteButtonClick.bind(this);
this.onEditButtonClick = this.onEditButtonClick.bind(this);
this.editNode = this.editNode.bind(this);
this.onAddNewEdgeButtonClick = this.onAddNewEdgeButtonClick.bind(this);
this.onCancelButtonClick = this.onCancelButtonClick.bind(this);
this.onEditOriginal = this.onEditOriginal.bind(this);
Expand Down Expand Up @@ -213,6 +221,7 @@ class NodeSelector extends UNISYS.Component {
isNewNode: true
},
edges: [],
sourceNodeIsLocked: false,
isEditable: false,
isValid: false,
isDuplicateNodeLabel: false,
Expand Down Expand Up @@ -346,13 +355,15 @@ class NodeSelector extends UNISYS.Component {
// This is a case insensitive search
let isDuplicateNodeLabel = false;
let duplicateNodeID;
if (formData.label !== '' &&
this.AppState('D3DATA').nodes.find(node => {
if (
formData.label !== '' &&
this.AppState('D3DATA').nodes.find(node => {
if ((node.id !== formData.id) &&
(node.label.localeCompare(formData.label, 'en', { usage: 'search', sensitivity: 'base' })) === 0) {
duplicateNodeID = node.id;
return true;
}
return false;
})) {
isDuplicateNodeLabel = true;
}
Expand Down Expand Up @@ -394,6 +405,7 @@ class NodeSelector extends UNISYS.Component {
id: node.id,
isNewNode: false
},
sourceNodeIsLocked: false,
isEditable: false,
isDuplicateNodeLabel: false
});
Expand Down Expand Up @@ -517,24 +529,46 @@ class NodeSelector extends UNISYS.Component {
replacementNodeID: replacementNodeID
});
}
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*/
/*/ onEditButtonClick (event) {
event.preventDefault();
this.setState({ isEditable: true });
// Add ID if one isn't already defined
let formData = this.state.formData;
if (formData.id==='') {
throw Error('NodeSelector.onEditButtonClick trying to edit a node with no id! This shouldn\'t happen!');
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*/
/*/
onEditButtonClick(event) {
event.preventDefault();

// nodeID needs to be a Number. It should have been set in loadFormFromNode
let nodeID = this.state.formData.id;

this.NetCall('SRV_DBLOCKNODE', { nodeID: nodeID })
.then((data)=>{
if (data.NOP) {
console.log(`SERVER SAYS: ${data.NOP} ${data.INFO}`);
this.setState({ sourceNodeIsLocked: true });
} else if (data.locked) {
console.log(`SERVER SAYS: lock success! you can edit Node ${data.nodeID}`);
console.log(`SERVER SAYS: unlock the node after successful DBUPDATE`);
this.setState({ sourceNodeIsLocked: false });
this.editNode();
}
this.AppCall('AUTOCOMPLETE_SELECT',{id:thisIdentifier}).then(()=>{
// Set AutoComplete field to current data, otherwise, previously canceled label
// might be displayed
this.AppCall('SOURCE_SEARCH', { searchString: formData.label });
});
this.setState({ formData });
this.validateForm();
} // onEditButtonClick
});
} // onEditButtonClick
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*/
/*/
editNode() {
this.setState({ isEditable: true });
// Add ID if one isn't already defined
let formData = this.state.formData;
if (formData.id==='') {
throw Error('NodeSelector.onEditButtonClick trying to edit a node with no id! This shouldn\'t happen!');
}
this.AppCall('AUTOCOMPLETE_SELECT',{id:thisIdentifier}).then(()=>{
// Set AutoComplete field to current data, otherwise, previously canceled label
// might be displayed
this.AppCall('SOURCE_SEARCH', { searchString: formData.label });
});
this.setState({ formData });
this.validateForm();
} // editNode
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*/
/*/ onAddNewEdgeButtonClick (event) {
Expand Down Expand Up @@ -575,6 +609,16 @@ class NodeSelector extends UNISYS.Component {
// restore original node
this.loadFormFromNode( originalNode );
this.setState({ isEditable: false });
// unlock
this.NetCall('SRV_DBUNLOCKNODE', { nodeID: this.state.formData.id })
.then((data) => {
if (data.NOP) {
console.log(`SERVER SAYS: ${data.NOP} ${data.INFO}`);
} else if (data.unlocked) {
console.log(`SERVER SAYS: unlock success! you have released Node ${data.nodeID}`);
this.setState({ sourceNodeIsLocked: false });
}
});
}
this.AppCall('AUTOCOMPLETE_SELECT', {id:'search'});
}
Expand Down Expand Up @@ -626,7 +670,20 @@ class NodeSelector extends UNISYS.Component {
// write data to database
// setting dbWrite to true will distinguish this update
// from a remote one
this.AppCall('DB_UPDATE', { node });
this.AppCall('DB_UPDATE', { node })
.then(()=>{
this.NetCall('SRV_DBUNLOCKNODE', { nodeID: formData.id })
.then((data) => {
if (data.NOP) {
console.log(`SERVER SAYS: ${data.NOP} ${data.INFO}`);
} else if (data.unlocked) {
console.log(`SERVER SAYS: unlock success! you have released Node ${data.nodeID}`);
this.setState({ sourceNodeIsLocked: false });
}
});
});
// probably should unlock the node:

} // onSubmit


Expand Down Expand Up @@ -712,6 +769,7 @@ class NodeSelector extends UNISYS.Component {
hidden={this.state.isLocked || this.state.isEditable || (this.state.formData.id==='') }
onClick={this.onEditButtonClick}
>Edit Node</Button>
<p hidden={!this.state.sourceNodeIsLocked} className="small text-danger">{nodePrompts.label.sourceNodeIsLockedMessage}</p>
<Button outline size="sm"
hidden={!this.state.isEditable}
onClick={this.onCancelButtonClick}
Expand Down