From 156c6ee9ba88e854e140594bdfec0cb2884a1f00 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Mon, 21 Jun 2021 11:07:26 -0700 Subject: [PATCH 01/49] #1143 Detecting input on autocomplete and link from term info fix --- .../circuitBrowserConfiguration.js | 2 +- .../interface/VFBCircuitBrowser/Controls.js | 16 ++++++++++------ components/interface/VFBTermInfo/VFBTermInfo.js | 7 ++++--- reducers/generals.js | 8 +++++++- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js index 90767375d..6e8fe40e5 100644 --- a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js +++ b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js @@ -110,7 +110,7 @@ var styling = { } var restPostConfig = { - url: "https://pdb.virtualflybrain.org/db/neo4j/tx/commit", + url: "https://pdb-dev.virtualflybrain.org/db/neo4j/tx/commit", contentType: "application/json" }; diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 6eb154c34..c3f0ea519 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -143,6 +143,9 @@ class AutocompleteResults extends Component { */ handleResults (status, data, value){ let results = {}; + console.log("Status ", status) + console.log("Data ", data) + console.log("Value ", value) data?.map(result => { // Match results by short_form id if ( result?.short_form?.toLowerCase().includes(value?.toLowerCase()) ){ @@ -151,6 +154,8 @@ class AutocompleteResults extends Component { results[result?.label] = result; } }); + + console.log("Results ", results) this.setState({ filteredResults : results }); } @@ -330,19 +335,18 @@ class Controls extends Component { clearTimeout(this.typingTimeout); } // Create a setTimeout interval, to avoid performing searches on every stroke - setTimeout(this.typingTimeout, 500, event.target); + setTimeout(this.typingTimeout, 10, event.target); } /** * Handle SOLR result selection, activated by selecting from drop down menu under textfield */ - resultSelectedChanged (event, value) { + resultSelectedChanged (event, value, index) { // Copy neurons and add selection to correct array index let neurons = this.neuronFields; let textFieldId = event.target.id.toString().split("-")[0]; let shortForm = this.autocompleteRef[textFieldId].current.getFilteredResults()[value] && this.autocompleteRef[textFieldId].current.getFilteredResults()[value].short_form; - let index = neurons.findIndex(neuron => neuron.id === shortForm); - index > -1 ? neurons[index] = { id : shortForm, label : value } : null + neurons[indexx] = { id : shortForm, label : value }; // Keep track of query selected, and send an event to redux store that circuit has been updated this.circuitQuerySelected = neurons; @@ -467,7 +471,7 @@ class Controls extends Component { field={field} index={index} neuronTextfieldModified={this.neuronTextfieldModified} - resultSelectedChanged={this.resultSelectedChanged} + resultSelectedChanged={(event, value) => this.resultSelectedChanged(event, value, index)} ref={this.autocompleteRef[index.toString()]} /> @@ -580,7 +584,7 @@ function mapStateToProps (state) { } function mapDispatchToProps (dispatch) { - return { vfbCircuitBrowser: (type, path) => dispatch ( { type : type, data : { instance : path } }), } + return { vfbCircuitBrowser: (type, neurons) => dispatch ( { type : type, data : { instance : neurons } }), } } export default connect(mapStateToProps, mapDispatchToProps, null, { forwardRef : true } )(withStyles(styles)(Controls)); diff --git a/components/interface/VFBTermInfo/VFBTermInfo.js b/components/interface/VFBTermInfo/VFBTermInfo.js index 72381feaa..71284c585 100644 --- a/components/interface/VFBTermInfo/VFBTermInfo.js +++ b/components/interface/VFBTermInfo/VFBTermInfo.js @@ -336,7 +336,7 @@ class VFBTermInfo extends React.Component { let graphs = new Array(); for (var j = 0; j < values.length; j++) { graphs.push(
- + { "Show Circuit Browser for " + values[j].instance.parent.name }
@@ -723,10 +723,11 @@ class VFBTermInfoWidget extends React.Component { if (path.indexOf(CIRCUIT_BROWSER) === 0 ) { // Show Circuit Browser const { vfbCircuitBrowser } = this.props; + const selectedQuery = { label : path.split(',')[1] + "(" + path.split(',')[2] + ")" , id : path.split(',')[2] }; /* * Path contains the instancE ID passed to the circuit browser */ - vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, path.split(',')[1], true); + vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, path.split(',')[1], selectedQuery, true); // Notify VFBMain UI needs to be updated this.props.uiUpdated(); @@ -886,7 +887,7 @@ function mapStateToProps (state) { function mapDispatchToProps (dispatch) { return { - vfbCircuitBrowser: (type, path, visible) => dispatch ( { type : type, data : { instance : path, visible : visible } }), + vfbCircuitBrowser: (type, instance, visible) => dispatch ( { type : type, data : { instance : instance, visible : visible } }), vfbGraph: (type, path, index, visible, sync) => dispatch ( { type : type, data : { instance : path, queryIndex : index, visible : visible, sync : sync } }) } } diff --git a/reducers/generals.js b/reducers/generals.js index 207cf62b5..1c4777d5c 100644 --- a/reducers/generals.js +++ b/reducers/generals.js @@ -242,10 +242,16 @@ function generalReducer (state, action) { }; case UPDATE_CIRCUIT_QUERY: var newQueryMap = []; + // Instance is array if ( Array.isArray(action.data.instance) ) { newQueryMap = action.data.instance; } else { - !state.ui.circuitBrowser.circuitQuerySelected.includes(action.data.instance) ? newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected, action.data.instance] : newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected]; + // Instance is object + !state.ui.circuitBrowser.circuitQuerySelected.includes(action.data.instance) + ? + newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected, action.data.instance] + : + newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected]; } ui.circuitBrowser.circuitQuerySelected = newQueryMap; From 1b26f23c4a337e69491716c1862173d0e8ad4255 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 25 Jun 2021 12:53:13 -0700 Subject: [PATCH 02/49] #1143 Fixes autocomplete, #1144 fixes link from term info for circuit browser and adds test --- .../interface/VFBCircuitBrowser/Controls.js | 6 ++-- .../interface/VFBTermInfo/VFBTermInfo.js | 4 +-- reducers/generals.js | 9 +++--- .../jest/vfb/review/circuit-browser-tests.js | 28 +++++++++++++------ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index c3f0ea519..035dc9294 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -320,7 +320,6 @@ class Controls extends Component { neurons.push({ id : target.value, label : target.value }); } - // this.props.vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, neurons); this.neuronFields = neurons; getResultsSOLR( target.value, this.autocompleteRef[this.setInputValue].current.handleResults,searchConfiguration.sorter,datasourceConfiguration ); } @@ -346,7 +345,7 @@ class Controls extends Component { let neurons = this.neuronFields; let textFieldId = event.target.id.toString().split("-")[0]; let shortForm = this.autocompleteRef[textFieldId].current.getFilteredResults()[value] && this.autocompleteRef[textFieldId].current.getFilteredResults()[value].short_form; - neurons[indexx] = { id : shortForm, label : value }; + neurons[index] = { id : shortForm, label : value }; // Keep track of query selected, and send an event to redux store that circuit has been updated this.circuitQuerySelected = neurons; @@ -374,6 +373,7 @@ class Controls extends Component { while (this?.props?.circuitQuerySelected.length > 0) { this?.props?.circuitQuerySelected.pop(); } + this.props.vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, []) this.setState({ key: Math.random() }); } /** @@ -398,7 +398,7 @@ class Controls extends Component { } if ( this.props.circuitQuerySelected.length > neuronFields.length && !fieldExists && this.props.circuitQuerySelected?.[i]?.id != "") { - if ( neuronFields.length < configuration.maxNeurons && this.props.circuitQuerySelected !== "" ) { + if ( this.props.circuitQuerySelected !== "" ) { neuronFields.push({ id : this.props.circuitQuerySelected[i].id ? this.props.circuitQuerySelected[i].id : this.props.circuitQuerySelected[i], label : this.props.circuitQuerySelected[i].label ? this.props.circuitQuerySelected[i].label : this.props.circuitQuerySelected[i] }); } } diff --git a/components/interface/VFBTermInfo/VFBTermInfo.js b/components/interface/VFBTermInfo/VFBTermInfo.js index 71284c585..506621317 100644 --- a/components/interface/VFBTermInfo/VFBTermInfo.js +++ b/components/interface/VFBTermInfo/VFBTermInfo.js @@ -336,7 +336,7 @@ class VFBTermInfo extends React.Component { let graphs = new Array(); for (var j = 0; j < values.length; j++) { graphs.push(
- + { "Show Circuit Browser for " + values[j].instance.parent.name }
@@ -727,7 +727,7 @@ class VFBTermInfoWidget extends React.Component { /* * Path contains the instancE ID passed to the circuit browser */ - vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, path.split(',')[1], selectedQuery, true); + vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, selectedQuery, true); // Notify VFBMain UI needs to be updated this.props.uiUpdated(); diff --git a/reducers/generals.js b/reducers/generals.js index 1c4777d5c..b86d5f6a9 100644 --- a/reducers/generals.js +++ b/reducers/generals.js @@ -247,11 +247,10 @@ function generalReducer (state, action) { newQueryMap = action.data.instance; } else { // Instance is object - !state.ui.circuitBrowser.circuitQuerySelected.includes(action.data.instance) - ? - newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected, action.data.instance] - : - newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected]; + let match = state.ui.circuitBrowser.circuitQuerySelected?.find( query => query.id === action.data.instance.id ); + match + ? newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected] + : newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected, action.data.instance] } ui.circuitBrowser.circuitQuerySelected = newQueryMap; diff --git a/tests/jest/vfb/review/circuit-browser-tests.js b/tests/jest/vfb/review/circuit-browser-tests.js index 5bcc709ad..d6b8ea076 100644 --- a/tests/jest/vfb/review/circuit-browser-tests.js +++ b/tests/jest/vfb/review/circuit-browser-tests.js @@ -6,7 +6,7 @@ import { wait4selector, click, testLandingPage, flexWindowClick, findElementByTe import * as ST from '../selectors'; const baseURL = process.env.url || 'http://localhost:8080/org.geppetto.frontend'; -const projectURL = baseURL + "/geppetto"; +const projectURL = baseURL + "/geppetto?id=VFB_jrchjrch"; const ONE_SECOND = 1000; @@ -19,14 +19,13 @@ describe('VFB Circuit Browser Tests', () => { //increases timeout to ~8 minutes jest.setTimeout(60 * ONE_SECOND); await page.goto(projectURL); - }); //Tests opening term context and clicking on row buttons describe('Test Circuit Browser Component', () => { //Tests components in landing page are present it('Test Landing Page', async () => { - await testLandingPage(page, 'VFB_00101567'); + await testLandingPage(page, 'VFB_jrchjrch'); }) it('Open Circuit Browser', async () => { @@ -36,13 +35,22 @@ describe('VFB Circuit Browser Tests', () => { await wait4selector(page, 'div#VFBCircuitBrowser', { visible: true, timeout : 90 * ONE_SECOND }); }) - it('Set Neuron 1 , VFB_jrchjrch', async () => { - await page.waitFor(5 * ONE_SECOND); - await setTextFieldValue(".neuron1 input", "VFB_jrchjrch") - - await wait4selector(page, 'ul.MuiAutocomplete-listbox', { visible: true, timeout : 90 * ONE_SECOND }); + it('Open Term Info', async () => { + await selectTab(page, "Term Info"); + + // Check that the Tree Browser is visible + await wait4selector(page, 'div#vfbterminfowidget', { visible: true, timeout : 90 * ONE_SECOND }); + }) + + it('Open Circuit Browser from Term Info with ID : VFB_jrchjrch', async () => { + await page.click("#circuitBrowserLink"); + + // Check that the Tree Browser is visible + await wait4selector(page, 'div#VFBCircuitBrowser', { visible: true, timeout : 90 * ONE_SECOND }); - await page.click('ul.MuiAutocomplete-listbox li'); + await page.waitFor(ONE_SECOND); + const neuron1Input = await page.evaluate( () => document.querySelector(".neuron1 input").value) + expect(neuron1Input).toBe("5-HTPLP01_R (FlyEM-HB:1324365879)(VFB_jrchjrch)"); }) it('Set Neuron 2, VFB_jrchjsfu', async () => { @@ -69,6 +77,7 @@ describe('VFB Circuit Browser Tests', () => { await page.waitFor(ONE_SECOND); await page.click('#refreshCircuitBrowser'); + await wait4selector(page, '.MuiCircularProgress-svg', { visible: true, timeout : 10 * ONE_SECOND }); await page.waitFor(10 * ONE_SECOND); await wait4selector(page, '#circuitBrowserLegend', { visible: true, timeout : 240 * ONE_SECOND }); @@ -82,6 +91,7 @@ describe('VFB Circuit Browser Tests', () => { await page.waitFor(ONE_SECOND); await page.click('#refreshCircuitBrowser'); + await wait4selector(page, '.MuiCircularProgress-svg', { visible: true, timeout : 10 * ONE_SECOND }); await page.waitFor(10 * ONE_SECOND); await wait4selector(page, '#circuitBrowserLegend', { visible: true, timeout : 240 * ONE_SECOND }); From bd23883da54261155206f79affa74895dff5af9e Mon Sep 17 00:00:00 2001 From: jrmartin Date: Thu, 1 Jul 2021 15:11:27 -0700 Subject: [PATCH 03/49] #1143 circuit browser fixing --- .../interface/VFBCircuitBrowser/Controls.js | 39 ++++++++++++++----- .../VFBCircuitBrowser/VFBCircuitBrowser.js | 5 ++- reducers/generals.js | 20 ++++++++-- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index a544e1294..cddae10c7 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -186,6 +186,7 @@ class AutocompleteResults extends Component { key={this.props.field.id} className={label.replace(/ +/g, "").toLowerCase()} onChange={this.props.neuronTextfieldModified} + onDelete={this.props.neuronTextfieldModified} inputProps={{ ...params.inputProps, id: this.props.index, style: { height : "20px", color: "white" ,paddingLeft : "10px", border : "none", backgroundColor: "#80808040" } }} InputLabelProps={{ ...params.inputProps,style: { color: "white", paddingLeft : "10px" } }} /> @@ -328,13 +329,31 @@ class Controls extends Component { * Neuron text field has been modified. */ neuronTextfieldModified (event) { + console.log(event.key); this.resultsHeight = event.target.offsetTop + 15; // Remove old typing timeout interval if (this.state.typingTimeout) { clearTimeout(this.typingTimeout); } - // Create a setTimeout interval, to avoid performing searches on every stroke - setTimeout(this.typingTimeout, 10, event.target); + + this.setInputValue = event.target.id; + if ( event.target.id.id === "" ) { + this.setInputValue = event.target.parentElement.id; + } + let neurons = this.neuronFields; + + if ( neurons[parseInt(event.target.id)] ) { + neurons[parseInt(event.target.id)] = { id : event.target.value, label : event.target.value }; + } else { + neurons.push({ id : event.target.value, label : event.target.value }); + } + + if ( event?.nativeEvent?.inputType === "deleteContentBackward" && neurons?.find( (neuron, index) => neuron.id === "" && index.toString() === event.target.id )){ + this.props.vfbCircuitBrowser(UPDATE_CIRCUIT_QUERY, neurons); + } else { + getResultsSOLR( event.target.value, this.autocompleteRef[this.setInputValue].current.handleResults,searchConfiguration.sorter,datasourceConfiguration ); + } + this.neuronFields = neurons; } /** @@ -388,13 +407,15 @@ class Controls extends Component { ); if ( !fieldExists) { - for ( var j = 0 ; j < neuronFields.length ; j++ ) { - if ( neuronFields?.[j].id === "" ) { - neuronFields[j] = { id : this.props.circuitQuerySelected[i].id ? this.props.circuitQuerySelected[i].id : this.props.circuitQuerySelected[i], label : this.props.circuitQuerySelected[i].label ? this.props.circuitQuerySelected[i].label : this.props.circuitQuerySelected[i] }; - added = true; - fieldExists = true; - break; - } + const emptyIndex = neuronFields.findIndex( field => field.id === ""); + if ( emptyIndex >= 0 ) { + neuronFields[emptyIndex] = { id : this.props.circuitQuerySelected[i].id ? this.props.circuitQuerySelected[i].id : this.props.circuitQuerySelected[i], label : this.props.circuitQuerySelected[i].label ? this.props.circuitQuerySelected[i].label : this.props.circuitQuerySelected[i] }; + added = true; + fieldExists = true; + break; + } else { + neuronFields.pop(); + neuronFields.push({ id : this.props.circuitQuerySelected[i].id ? this.props.circuitQuerySelected[i].id : this.props.circuitQuerySelected[i], label : this.props.circuitQuerySelected[i].label ? this.props.circuitQuerySelected[i].label : this.props.circuitQuerySelected[i] }) } if ( this.props.circuitQuerySelected.length > neuronFields.length && !fieldExists && this.props.circuitQuerySelected?.[i]?.id != "") { diff --git a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js index 7e5cdb005..9ca228b9d 100644 --- a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js +++ b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js @@ -299,7 +299,7 @@ class VFBCircuitBrowser extends Component { this.circuitQuerySelected = circuitQuerySelected; let errorMessage = "Not enough input queries to create a graph, needs 2."; - if ( this.state.neurons?.[0].id != "" && this.state.neurons?.[1].id != "" ){ + if ( this.state.neurons?.[0]?.id != "" && this.state.neurons?.[1]?.id != "" ){ errorMessage = "Graph not available for " + this.state.neurons.map(a => `'${a.id}'`).join(","); } return ( @@ -321,11 +321,12 @@ class VFBCircuitBrowser extends Component { resetCamera={self.resetCamera} zoomIn={self.zoomIn} zoomOut={self.zoomOut} - circuitQuerySelected={this.circuitQuerySelected} + circuitQuerySelected={circuitQuerySelected} datasource="SOLR" legend = {self.state.legend} ref={self.controlsRef} clearGraph={self.clearGraph} + key="controls" />
: query.id === action.data.instance.id ); - match - ? newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected] - : newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected, action.data.instance] + if ( match ) { + newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected] + } else { + const maxedOut = state.ui.circuitBrowser?.circuitQuerySelected?.find( query => query.id === "" ); + const emptyIndex = state.ui.circuitBrowser?.circuitQuerySelected?.findIndex( field => field.id === ""); + if ( emptyIndex >= 0 ) { + newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected] + newQueryMap[emptyIndex] = action.data.instance; + } else { + newQueryMap = [...state.ui.circuitBrowser.circuitQuerySelected]; + newQueryMap.pop(); + newQueryMap.push(action.data.instance); + } + } } ui.circuitBrowser.circuitQuerySelected = newQueryMap; From d55caea726f7aba8661a03b321fcff339cf4afb1 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 2 Jul 2021 15:21:54 -0700 Subject: [PATCH 04/49] #728 Make template instance not selectable in 3D Viewer --- components/VFBMain.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index bfe37e536..9ab9de458 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -1058,7 +1058,7 @@ class VFBMain extends React.Component { if ( nextProps.generals.instanceOnFocus !== undefined && this.instanceOnFocus !== undefined) { if ( Object.keys(nextProps.generals.instanceOnFocus).length > 0 ) { if ( nextProps.generals.instanceOnFocus !== this.instanceOnFocus.getId() ){ - this.instanceOnFocus == nextProps.generals.instanceOnFocus; + this.instanceOnFocus = nextProps.generals.instanceOnFocus; } } } @@ -1380,6 +1380,13 @@ class VFBMain extends React.Component { GEPPETTO.on(GEPPETTO.Events.Instance_added, function (instance) { that.props.instanceAdded(instance); }); + + GEPPETTO.on(GEPPETTO.Events.Instances_created, function (instances) { + // Set template Instance to be not clickable in 3D viewer + if ( instances[0]?.id?.includes(window.templateID) ) { + that.canvasReference.engine.meshes ? that.canvasReference.engine.meshes[window.templateID + "." + instances[0]?.id].children[0].clickThrough = true : null; + } + }); GEPPETTO.on(GEPPETTO.Events.Instance_deleted, function (instancePath) { let id = instancePath.split(".")[0]; From 7a7b754fb2058d280b4409e536d48f1d18ca889d Mon Sep 17 00:00:00 2001 From: jrmartin Date: Wed, 7 Jul 2021 11:04:23 -0700 Subject: [PATCH 05/49] #484 Compound queries in URL --- components/VFBMain.js | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index 9ab9de458..54307a406 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -85,7 +85,7 @@ class VFBMain extends React.Component { this.instanceOnFocus = undefined; this.idFromURL = undefined; this.idsFromURL = []; - this.urlQueryLoader = undefined; + this.urlQueryLoader = []; this.quickHelpRender = undefined; this.firstLoad = true; this.quickHelpOpen = true; @@ -1342,10 +1342,15 @@ class VFBMain extends React.Component { } idsList = idList[list].replace("i=","") + idsList; } else if (idList[list].indexOf("q=") > -1) { - this.urlQueryLoader = idList[list].replace("q=","").replace("%20", " ").split(","); + const multipleQueries = idList[list].replace("q=","").replace("%20", " ").split(";"); + let that = this; + multipleQueries?.forEach((query) => { + const querySplit = query.split(","); + that.urlQueryLoader.push({ id : querySplit[0].trim(), selection : querySplit[1].trim() }); + }); // if no other ids are loaded the query target is added. if (idsList.length == 0 && this.urlQueryLoader.length > 1) { - idsList = this.urlQueryLoader[0]; + idsList = this.urlQueryLoader[0].id; } } } @@ -1397,10 +1402,19 @@ class VFBMain extends React.Component { that.addVfbId(that.idsFinalList); var callback = function () { + if ( that.urlQueryLoader.length == 0 && that.refs.querybuilderRef.props.model.count > 0) { + // runQuery if any results + that.refs.querybuilderRef.runQuery(); + } // check if any results with count flag - if (that.refs.querybuilderRef.props.model.count > 0) { - // runQuery if any results - that.refs.querybuilderRef.runQuery(); + else if (that.urlQueryLoader.length > 0 && that.refs.querybuilderRef.props.model.count > 0) { + that.urlQueryLoader.shift(); + const query = that.urlQueryLoader[0]; + query + ? window.fetchVariableThenRun(query.id, function () { + that.refs.querybuilderRef.addQueryItem({ term: "", id: query.id, queryObj: Model[query.selection] }, callback) + }) + : that.refs.querybuilderRef.runQuery(); } else { that.refs.querybuilderRef.switchView(false); } @@ -1410,14 +1424,15 @@ class VFBMain extends React.Component { GEPPETTO.trigger('stop_spin_logo'); }; + // Initial queries specified on URL if (that.urlQueryLoader !== undefined) { if (window[that.urlQueryLoader[0]] == undefined) { - window.fetchVariableThenRun(that.urlQueryLoader[0], function () { - that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0], queryObj: Model[that.urlQueryLoader[1]] }, callback) + window.fetchVariableThenRun(that.urlQueryLoader[0].id, function () { + that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0].id, queryObj: Model[that.urlQueryLoader[0].selection] }, callback) }); } else { setTimeout(function () { - that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0], queryObj: Model[that.urlQueryLoader[1]] }, callback); + that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0].id, queryObj: Model[that.urlQueryLoader[0].selection] }, callback); }, 100); } } From 9d71519171a28fb936a55d41367ba4784ff7b31f Mon Sep 17 00:00:00 2001 From: jrmartin Date: Wed, 7 Jul 2021 12:55:50 -0700 Subject: [PATCH 06/49] #484 eslint fix --- components/VFBMain.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index 54307a406..f2b247a4c 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -1344,7 +1344,7 @@ class VFBMain extends React.Component { } else if (idList[list].indexOf("q=") > -1) { const multipleQueries = idList[list].replace("q=","").replace("%20", " ").split(";"); let that = this; - multipleQueries?.forEach((query) => { + multipleQueries?.forEach( query => { const querySplit = query.split(","); that.urlQueryLoader.push({ id : querySplit[0].trim(), selection : querySplit[1].trim() }); }); @@ -1402,19 +1402,23 @@ class VFBMain extends React.Component { that.addVfbId(that.idsFinalList); var callback = function () { - if ( that.urlQueryLoader.length == 0 && that.refs.querybuilderRef.props.model.count > 0) { - // runQuery if any results - that.refs.querybuilderRef.runQuery(); - } - // check if any results with count flag - else if (that.urlQueryLoader.length > 0 && that.refs.querybuilderRef.props.model.count > 0) { + if ( that.urlQueryLoader.length == 0 && that.refs.querybuilderRef.props.model.count > 0 ) { + // runQuery if any results + that.refs.querybuilderRef.runQuery(); + } else if (that.urlQueryLoader.length > 0 && that.refs.querybuilderRef.props.model.count > 0) { + // Remove query from stack, and perform the next query that.urlQueryLoader.shift(); const query = that.urlQueryLoader[0]; + // Fetch variable and addQuery, if no more queries left then run query. query - ? window.fetchVariableThenRun(query.id, function () { + ? window[query.id] === undefined + ? window.fetchVariableThenRun(query.id, function () { that.refs.querybuilderRef.addQueryItem({ term: "", id: query.id, queryObj: Model[query.selection] }, callback) }) - : that.refs.querybuilderRef.runQuery(); + : that.refs.querybuilderRef.addQueryItem({ term: "", id: query.id, queryObj: Model[query.selection] }, callback) + : that.refs.querybuilderRef.props.model.count > 0 + ? that.refs.querybuilderRef.runQuery() + : null } else { that.refs.querybuilderRef.switchView(false); } From 51b32a575767ba4f282b0190eefcb41c4ffa3aec Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 9 Jul 2021 10:44:53 -0700 Subject: [PATCH 07/49] #484 Add query builder tests for compound queries --- tests/jest/vfb/review/query-builder-tests.js | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/jest/vfb/review/query-builder-tests.js diff --git a/tests/jest/vfb/review/query-builder-tests.js b/tests/jest/vfb/review/query-builder-tests.js new file mode 100644 index 000000000..8066d5498 --- /dev/null +++ b/tests/jest/vfb/review/query-builder-tests.js @@ -0,0 +1,53 @@ +const puppeteer = require('puppeteer'); +const { TimeoutError } = require('puppeteer/Errors'); + +import { getUrlFromProjectId } from '../cmdline.js'; +import { wait4selector, click, closeModalWindow, findElementByText } from '../utils'; +import * as ST from '../selectors'; + +const baseURL = process.env.url || 'http://localhost:8080/org.geppetto.frontend'; +const PROJECT_URL = baseURL + "/geppetto?id=VFB_00017894&q=VFB_00000001,SimilarMorphologyTo; VFBexp_FBal0276838,epFrag"; +const COMPOUND_QUERY_MATCHER = "53 Neurons with similar morphology to fru-M-200266 [NBLAST mean score] AND Images of fragments of Scer\\GAL4[fru.P1.D] expression pattern"; + +/** + * Query Builder component tests + */ +describe('VFB Query Builder Tests', () => { + beforeAll(async () => { + jest.setTimeout(1800000); + await page.goto(PROJECT_URL); + }); + + describe('Test landing page', () => { + it('Loading spinner goes away', async () => { + await wait4selector(page, ST.SPINNER_SELECTOR, { hidden: true, timeout : 120000 }) + // Close tutorial window + closeModalWindow(page); + }) + + it('VFB Title shows up', async () => { + const title = await page.title(); + expect(title).toMatch("Virtual Fly Brain"); + }) + + it('Zoom button for VFB_00017894 appears in button bar inside the term info component', async () => { + await wait4selector(page, 'button[id=VFB_00017894_zoom_buttonBar_btn]', { visible: true , timeout : 120000 }) + }) + + it('Term info component created after load', async () => { + await wait4selector(page, 'div#bar-div-vfbterminfowidget', { visible: true }) + }) + }) + + describe('Tests Compound Queries from URL', () => { + it('Wait for First Query', async () => { + await wait4selector(page, '#queryitem-fru-M-200266_0', { visible: true, timeout : 150000 }); + }) + + it('Griddle Results Loads 53 Results for Compounds QUeries', async () => { + await wait4selector(page, '#query-results-container', { visible: true, timeout : 150000 }); + const griddleResults = await page.evaluate(async () => document.getElementsByClassName("result-verbose-label")[0].textContent); + expect(griddleResults.trim()).toEqual(COMPOUND_QUERY_MATCHER); + }) + }) +}) From 4be6c81c30cc9843597fda2d0aa9cd0c8eb3f8c5 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 9 Jul 2021 11:18:18 -0700 Subject: [PATCH 08/49] #1158 Circuit Browser styling --- .../interface/VFBCircuitBrowser/Controls.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index cddae10c7..6fe5836fe 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -100,7 +100,17 @@ const styles = theme => ({ backgroundColor: "#80808040 !important", paddingLeft : "10px !important" }, - weightInputDiv : { width : "100% !important" } + weightInputDiv : { width : "100% !important" }, + refreshButton : { + backgroundColor : "#0AB7FE", + flexBasis: "100%", + fontWeight : 600 + }, + clearButton : { + backgroundColor : "#E53935", + flexBasis: "100%", + fontWeight : 600 + } }); /** @@ -572,18 +582,16 @@ class Controls extends Component { From bea6c0d8fa5c5f33e8dd53379bc108ac4f5bab46 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 9 Jul 2021 11:36:46 -0700 Subject: [PATCH 09/49] #1158 Styling circuit browser buttons --- components/interface/VFBCircuitBrowser/Controls.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 6fe5836fe..619acd271 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -104,12 +104,12 @@ const styles = theme => ({ refreshButton : { backgroundColor : "#0AB7FE", flexBasis: "100%", - fontWeight : 600 + fontWeight : 600, }, clearButton : { backgroundColor : "#E53935", flexBasis: "100%", - fontWeight : 600 + fontWeight : 600, } }); @@ -583,6 +583,7 @@ class Controls extends Component { From 1114c60f35742b10ccf6b1ad85da0e574397bc03 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Mon, 12 Jul 2021 12:02:30 +0100 Subject: [PATCH 11/49] swapping to paths --- components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js index 9ca228b9d..92c46388b 100644 --- a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js +++ b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js @@ -57,7 +57,7 @@ class VFBCircuitBrowser extends Component { queryLoaded : false, dropDownAnchorEl : null, neurons : [{ id : "", label : "" } , { id : "", label : "" }], - hops : Math.ceil((configuration.maxHops - configuration.minHops) / 2), + paths : Math.ceil((configuration.maxPaths - configuration.minPaths) / 2), weight : 0, reload : false } @@ -249,7 +249,7 @@ class VFBCircuitBrowser extends Component { results: response.data, configuration : configuration, styling : stylingConfiguration, - hops : self.state.hops, + paths : self.state.paths, NODE_WIDTH : NODE_WIDTH, NODE_HEIGHT : NODE_HEIGHT } From 50b1980e79f291a5daff5312133d08a677c99f57 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Mon, 12 Jul 2021 18:08:21 +0100 Subject: [PATCH 12/49] adding crude weight legend --- components/interface/VFBCircuitBrowser/Controls.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 6cd6b6fa2..ea70d4188 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -468,9 +468,10 @@ class Controls extends Component { { this.props.resultsAvailable() ?
    { this.props.legend.map((label, index) => ( -
  • {label}
  • +
  • {label}
  • )) } +
  • WEIGHT -Forward [Reverse]->
: null } From 88bd6aaf04e211b2546330dffa9009646b3b06e5 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Mon, 12 Jul 2021 14:06:17 -0700 Subject: [PATCH 13/49] #484 Fixing console errors --- components/VFBMain.js | 6 +++--- tests/jest/vfb/review/circuit-browser-tests.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index f2b247a4c..c60ba3d08 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -1431,12 +1431,12 @@ class VFBMain extends React.Component { // Initial queries specified on URL if (that.urlQueryLoader !== undefined) { if (window[that.urlQueryLoader[0]] == undefined) { - window.fetchVariableThenRun(that.urlQueryLoader[0].id, function () { - that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0].id, queryObj: Model[that.urlQueryLoader[0].selection] }, callback) + that.urlQueryLoader[0]?.id && window.fetchVariableThenRun(that.urlQueryLoader[0]?.id, function () { + that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0]?.id, queryObj: Model[that.urlQueryLoader[0]?.selection] }, callback) }); } else { setTimeout(function () { - that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0].id, queryObj: Model[that.urlQueryLoader[0].selection] }, callback); + that.refs.querybuilderRef.addQueryItem({ term: "", id: that.urlQueryLoader[0]?.id, queryObj: Model[that.urlQueryLoader[0]?.selection] }, callback); }, 100); } } diff --git a/tests/jest/vfb/review/circuit-browser-tests.js b/tests/jest/vfb/review/circuit-browser-tests.js index d6b8ea076..4ae1be1ab 100644 --- a/tests/jest/vfb/review/circuit-browser-tests.js +++ b/tests/jest/vfb/review/circuit-browser-tests.js @@ -39,7 +39,7 @@ describe('VFB Circuit Browser Tests', () => { await selectTab(page, "Term Info"); // Check that the Tree Browser is visible - await wait4selector(page, 'div#vfbterminfowidget', { visible: true, timeout : 90 * ONE_SECOND }); + await wait4selector(page, '#circuitBrowserLink', { visible: true, timeout : 150 * ONE_SECOND }); }) it('Open Circuit Browser from Term Info with ID : VFB_jrchjrch', async () => { @@ -50,7 +50,7 @@ describe('VFB Circuit Browser Tests', () => { await page.waitFor(ONE_SECOND); const neuron1Input = await page.evaluate( () => document.querySelector(".neuron1 input").value) - expect(neuron1Input).toBe("5-HTPLP01_R (FlyEM-HB:1324365879)(VFB_jrchjrch)"); + expect(neuron1Input).toBe("5-HTPLP01_R (FlyEM-HB:1324365879) (VFB_jrchjrch)"); }) it('Set Neuron 2, VFB_jrchjsfu', async () => { From 4849951a2d08ff00477a9c1b1a3717fea976f7c7 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 13 Jul 2021 10:58:01 +0100 Subject: [PATCH 14/49] tidying arrow --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index ea70d4188..fcee89aba 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -471,7 +471,7 @@ class Controls extends Component {
  • {label}
  • )) } -
  • WEIGHT -Forward [Reverse]->
  • +
  • WEIGHT -Forward [Reverse]&#rarr;
  • : null } From 23c912d91a7b7547dd827c7c06f2d03fb0d395e9 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 13 Jul 2021 12:34:54 +0100 Subject: [PATCH 15/49] character fix --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index fcee89aba..044b1ead5 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -471,7 +471,7 @@ class Controls extends Component {
  • {label}
  • )) } -
  • WEIGHT -Forward [Reverse]&#rarr;
  • +
  • WEIGHT -Forward [Reverse]→
  • : null } From 5e86e520c473c206258c4abbc0b1f50fc94778fd Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 13 Jul 2021 15:12:15 +0100 Subject: [PATCH 16/49] adding Split filter --- components/configuration/VFBMain/searchConfiguration.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/configuration/VFBMain/searchConfiguration.js b/components/configuration/VFBMain/searchConfiguration.js index 1ddf7d1fb..4432956fe 100644 --- a/components/configuration/VFBMain/searchConfiguration.js +++ b/components/configuration/VFBMain/searchConfiguration.js @@ -138,6 +138,11 @@ var searchConfiguration = { "filter_name": "Anatomy", "enabled": "disabled", }, + { + "key": "Split", + "filter_name": "Split", + "enabled": "disabled", + }, { "key": "Expression_pattern", "filter_name": "Expression Pattern", From 1602784873200e129d5b81b66ac54c511ad44276 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Thu, 15 Jul 2021 14:48:32 +0100 Subject: [PATCH 17/49] sorting order and adding more facets --- .../VFBMain/searchConfiguration.js | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/components/configuration/VFBMain/searchConfiguration.js b/components/configuration/VFBMain/searchConfiguration.js index 4432956fe..e0eea803d 100644 --- a/components/configuration/VFBMain/searchConfiguration.js +++ b/components/configuration/VFBMain/searchConfiguration.js @@ -138,9 +138,19 @@ var searchConfiguration = { "filter_name": "Anatomy", "enabled": "disabled", }, + { + "key": "Neuron", + "filter_name": "Neuron", + "enabled": "disabled", + }, + { + "key": "has_image", + "filter_name": "Image", + "enabled": "disabled", + }, { "key": "Split", - "filter_name": "Split", + "filter_name": "Split Expression", "enabled": "disabled", }, { @@ -149,23 +159,28 @@ var searchConfiguration = { "enabled": "disabled", }, { - "key": "has_image", - "filter_name": "Image", + "key": "Expression_pattern_fragment", + "filter_name": "Expression Pattern Fragment", "enabled": "disabled", }, { "key": "has_neuron_connectivity", - "filter_name": "Neurons with Connectivity", + "filter_name": "Neuron with Connectivity", "enabled": "disabled", }, { - "key": "Synaptic_neuropil_domain", - "filter_name": "Synaptic Neuropil", + "key": "NBLAST", + "filter_name": "Neuron Similarity (NBLAST)", "enabled": "disabled", }, { - "key": "Neuron", - "filter_name": "Neuron", + "key": "NBLASTexp", + "filter_name": "Expression Similarity (NBLAST)", + "enabled": "disabled", + }, + { + "key": "Synaptic_neuropil_domain", + "filter_name": "Synaptic Neuropil", "enabled": "disabled", }, { From afca49d8fbd4989bd3c498d1a1ae1876e3586286 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Thu, 15 Jul 2021 17:47:55 +0100 Subject: [PATCH 18/49] sorting order --- components/VFBMain.js | 4 +++- .../configuration/VFBTermInfo/VFBTermInfoConfiguration.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index 9ab9de458..1052fbef3 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -934,7 +934,9 @@ class VFBMain extends React.Component { 'Related Individuals', 'Relationships', 'Query for', - 'Graph for', + 'Graphs For', + 'Graphs for', + 'Add Neuron to Circuit Browser Query', 'Circuit Browser for', 'Description', 'Cross References', diff --git a/components/configuration/VFBTermInfo/VFBTermInfoConfiguration.js b/components/configuration/VFBTermInfo/VFBTermInfoConfiguration.js index 93841525d..91b2d2aec 100644 --- a/components/configuration/VFBTermInfo/VFBTermInfoConfiguration.js +++ b/components/configuration/VFBTermInfo/VFBTermInfoConfiguration.js @@ -136,13 +136,13 @@ const buttonBarControls = { const linksConfiguration = { // Graph Links configuration, name of key "Graph" must not be changed "Graph": { - "title": "Graphs For", + "title": "Graphs for", "visibility": true, "superType": "Anatomy" }, // CircuitBrowser Links configuration, name of key "CircuitBrowser" must not be changed "CircuitBrowser": { - "title": "Add Neuron to Circuit Browser", + "title": "Add Neuron to Circuit Browser Query", "visibility": true, "superType": "has_neuron_connectivity" } From efc1eb47e820a81dfa3d016c2c2d36111a42b591 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Thu, 15 Jul 2021 18:09:36 +0100 Subject: [PATCH 19/49] tweaking query label --- components/interface/VFBTermInfo/VFBTermInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBTermInfo/VFBTermInfo.js b/components/interface/VFBTermInfo/VFBTermInfo.js index cb1d79b5b..83be5455a 100644 --- a/components/interface/VFBTermInfo/VFBTermInfo.js +++ b/components/interface/VFBTermInfo/VFBTermInfo.js @@ -337,7 +337,7 @@ class VFBTermInfo extends React.Component { for (var j = 0; j < values.length; j++) { graphs.push( From ae4a41bb0e835f60a752bfcf528a248351f6dfa0 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Thu, 15 Jul 2021 15:26:49 -0700 Subject: [PATCH 20/49] #531 Fix shift key bug getting stuck --- components/interface/VFBTermInfo/VFBTermInfo.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/interface/VFBTermInfo/VFBTermInfo.js b/components/interface/VFBTermInfo/VFBTermInfo.js index 83be5455a..c8066a6f6 100644 --- a/components/interface/VFBTermInfo/VFBTermInfo.js +++ b/components/interface/VFBTermInfo/VFBTermInfo.js @@ -787,6 +787,14 @@ class VFBTermInfoWidget extends React.Component { $('#add-new-query-container')[0].hidden = true; $('#query-builder-items-container')[0].hidden = true; } + + /** + * Fire event to set the Shift key as not pressed, this is needed since the presence of the + * confirm() dialog prevents the DOM to un-set the 'shift' key. + */ + var e = new KeyboardEvent('keyup', {bubbles : true, cancelable : true, shiftKey : false}); + document.querySelector("body").dispatchEvent(e); + $("body").css("cursor", "progress"); From 515232cbcca14ab2a2a9955fe8ef427ae7a01a5b Mon Sep 17 00:00:00 2001 From: jrmartin Date: Thu, 15 Jul 2021 16:19:59 -0700 Subject: [PATCH 21/49] #531 Fix eslint --- components/interface/VFBTermInfo/VFBTermInfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBTermInfo/VFBTermInfo.js b/components/interface/VFBTermInfo/VFBTermInfo.js index c8066a6f6..e5ff6ea32 100644 --- a/components/interface/VFBTermInfo/VFBTermInfo.js +++ b/components/interface/VFBTermInfo/VFBTermInfo.js @@ -792,7 +792,7 @@ class VFBTermInfoWidget extends React.Component { * Fire event to set the Shift key as not pressed, this is needed since the presence of the * confirm() dialog prevents the DOM to un-set the 'shift' key. */ - var e = new KeyboardEvent('keyup', {bubbles : true, cancelable : true, shiftKey : false}); + var e = new KeyboardEvent('keyup', { bubbles : true, cancelable : true, shiftKey : false }); document.querySelector("body").dispatchEvent(e); $("body").css("cursor", "progress"); From 429d67850218f0d33910a458482eb696a7059111 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 16 Jul 2021 17:49:05 +0100 Subject: [PATCH 22/49] limiting neurons included in the explored graph --- .../VFBCircuitBrowser/circuitBrowserConfiguration.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js index 456b5dda7..e3c3e4eae 100644 --- a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js +++ b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js @@ -3,10 +3,10 @@ var locationCypherQuery = ( instances, paths, weight ) => ({ { "statement" : "WITH [" + instances + "] AS neurons" + " WITH neurons[0] as a, neurons[1] AS b" - + " MATCH (source:has_neuron_connectivity {short_form: a}), (target:Neuron {short_form: b})" + + " MATCH (source:Neuron:has_neuron_connectivity {short_form: a}), (target:Neuron:has_neuron_connectivity {short_form: b})" + " CALL gds.beta.shortestPath.yens.stream({" - + " nodeQuery: 'MATCH (n:Neuron) RETURN id(n) AS id'," - + " relationshipQuery: 'MATCH (a:Neuron:has_neuron_connectivity)-[r:synapsed_to]->(b:Neuron) WHERE exists(r.weight) AND r.weight[0] >= " + + " nodeQuery: 'MATCH (n:Neuron:has_neuron_connectivity) RETURN id(n) AS id'," + + " relationshipQuery: 'MATCH (a:Neuron:has_neuron_connectivity)-[r:synapsed_to]->(b:Neuron:has_neuron_connectivity) WHERE exists(r.weight) AND r.weight[0] >= " + weight?.toString() + " RETURN id(a) AS source, id(b) AS target, type(r) as type, 5000-r.weight[0] as weight_p'," + " sourceNode: id(source)," + " targetNode: id(target)," From 77b6793254b83b2af21e1f7c6f75768a1d820212 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 16 Jul 2021 17:50:56 +0100 Subject: [PATCH 23/49] adding link to explantion --- .../VFBCircuitBrowser/circuitBrowserConfiguration.js | 1 + 1 file changed, 1 insertion(+) diff --git a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js index e3c3e4eae..2aa7eb14e 100644 --- a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js +++ b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js @@ -24,6 +24,7 @@ var locationCypherQuery = ( instances, paths, weight ) => ({ } ] }); +// See query explanation on https://github.com/VirtualFlyBrain/graph_queries/blob/main/weighted_path.md var configuration = { resultsMapping: From a25b5e9236a98c9473a4a2d0f3f6715617807c7a Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 16 Jul 2021 19:23:40 +0100 Subject: [PATCH 24/49] limiting forward paths --- .../VFBCircuitBrowser/circuitBrowserConfiguration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js index 2aa7eb14e..44edec18d 100644 --- a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js +++ b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js @@ -18,7 +18,7 @@ var locationCypherQuery = ( instances, paths, weight ) => ({ + " YIELD index, sourceNode, targetNode, nodeIds, path" + " WITH * ORDER BY index DESC" + " UNWIND relationships(path) as sr" - + " OPTIONAL MATCH cp=(x)-[:synapsed_to]-(y) WHERE x=apoc.rel.startNode(sr) AND y=apoc.rel.endNode(sr) OPTIONAL MATCH fp=(x)-[r:synapsed_to]->(y)" + + " OPTIONAL MATCH cp=(x)-[:synapsed_to]-(y) WHERE x=apoc.rel.startNode(sr) AND y=apoc.rel.endNode(sr) OPTIONAL MATCH fp=(x)-[r:synapsed_to]->(y) WHERE r.weight[0] >= " + weight?.toString() + " RETURN distinct a as root, collect(distinct fp) as pp, collect(distinct cp) as p, collect(distinct id(r)) as fr, sourceNode as source, targetNode as target, max(length(path)) as maxHops, collect(distinct toString(id(r))+':'+toString(index)) as relationshipY ", "resultDataContents": ["row", "graph"] } From 60d36dbbb8e8b44342597bb8142f5c1b47107230 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 16 Jul 2021 19:57:02 +0100 Subject: [PATCH 25/49] limiting matches --- .../VFBCircuitBrowser/circuitBrowserConfiguration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js index 44edec18d..66339c535 100644 --- a/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js +++ b/components/configuration/VFBCircuitBrowser/circuitBrowserConfiguration.js @@ -18,7 +18,7 @@ var locationCypherQuery = ( instances, paths, weight ) => ({ + " YIELD index, sourceNode, targetNode, nodeIds, path" + " WITH * ORDER BY index DESC" + " UNWIND relationships(path) as sr" - + " OPTIONAL MATCH cp=(x)-[:synapsed_to]-(y) WHERE x=apoc.rel.startNode(sr) AND y=apoc.rel.endNode(sr) OPTIONAL MATCH fp=(x)-[r:synapsed_to]->(y) WHERE r.weight[0] >= " + weight?.toString() + + " OPTIONAL MATCH cp=(x:Neuron:has_neuron_connectivity)-[:synapsed_to]-(y:Neuron:has_neuron_connectivity) WHERE x=apoc.rel.startNode(sr) AND y=apoc.rel.endNode(sr) OPTIONAL MATCH fp=(x)-[r:synapsed_to]->(y) WHERE r.weight[0] >= " + weight?.toString() + " RETURN distinct a as root, collect(distinct fp) as pp, collect(distinct cp) as p, collect(distinct id(r)) as fr, sourceNode as source, targetNode as target, max(length(path)) as maxHops, collect(distinct toString(id(r))+':'+toString(index)) as relationshipY ", "resultDataContents": ["row", "graph"] } From 5ed9a9c67af31fe34fca2feb30a4bc5155a6fe06 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 16 Jul 2021 17:34:54 -0700 Subject: [PATCH 26/49] #531 Make slider in circuit browser match blue color of theme --- components/interface/VFBCircuitBrowser/Controls.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 044b1ead5..37acea4b3 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -110,7 +110,8 @@ const styles = theme => ({ backgroundColor : "#E53935", flexBasis: "100%", fontWeight : 600, - } + }, + slider : { color: '#0AB7FE' } }); /** @@ -571,6 +572,7 @@ class Controls extends Component { valueLabelDisplay="auto" min={configuration.minPaths} max={configuration.maxPaths} + classes={{ root : classes.slider }} />
    From 9a560336413addd9e6ad49edfe0ac535f4921cbc Mon Sep 17 00:00:00 2001 From: Rob Court Date: Mon, 19 Jul 2021 17:23:57 +0100 Subject: [PATCH 27/49] testing download file metadata additions --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 01dc133d1..a82f3095b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ ARG geppettoDatasourceRelease=vfb_20200604_a ARG geppettoModelSwcRelease=v1.0.1 ARG geppettoFrontendRelease=development ARG geppettoClientRelease=VFBv2.2.0.7 -ARG ukAcVfbGeppettoRelease=pipeline2 +ARG ukAcVfbGeppettoRelease=download ARG mvnOpt="-Dhttps.protocols=TLSv1.2 -DskipTests --quiet -Pmaster" From e826b3b693f7238196480e61ffed6e3d915c7127 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 20 Jul 2021 17:49:32 +0100 Subject: [PATCH 28/49] excluding DownloadMeta --- components/VFBMain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index 1052fbef3..b385f2759 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -914,7 +914,7 @@ class VFBMain extends React.Component { self.setState({ UIUpdated: true }) }} focusTermRef={this.focusTermReference} - exclude={["ClassQueriesFrom", "Debug"]} + exclude={["ClassQueriesFrom", "Debug", "DownloadMeta"]} order={['Symbol', 'Title', 'Name', From 67565b607e259dc25aa3eb7456f1ad9c95784db3 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Wed, 21 Jul 2021 11:49:05 -0700 Subject: [PATCH 29/49] #1161 Fix bugs with query parser --- .../VFBCircuitBrowser/QueryParser.js | 45 +++++++------------ .../VFBCircuitBrowser/VFBCircuitBrowser.js | 3 +- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/components/interface/VFBCircuitBrowser/QueryParser.js b/components/interface/VFBCircuitBrowser/QueryParser.js index 3b657930c..fa9549181 100644 --- a/components/interface/VFBCircuitBrowser/QueryParser.js +++ b/components/interface/VFBCircuitBrowser/QueryParser.js @@ -5,6 +5,7 @@ export function queryParser (e) { // The nodes and links arrays used for the graph let nodes = [], links = []; let graphData = e.data.params.results; + let weight = e.data.params.weight; console.log("Results ", e); // Reads graph data let data = graphData?.results[0]?.data; @@ -129,6 +130,7 @@ export function queryParser (e) { let hopsMap = hopAssignment(sourceNodeID, targetNodeID, allRelationships, 0, {}); maxHops = Math.max.apply(null, Object.keys(hopsMap)?.map( key => parseInt(hopsMap[key]))); + let positionArray = []; // Loop through nodes and assign X position based on hops nodes.forEach( sourceNode => { let id = sourceNode.id; @@ -152,24 +154,27 @@ export function queryParser (e) { positionX = (maxHops * (-1 * spaceBetween) ) + space sourceNode.positionX = positionX; } + + + if ( positionArray.some(row => row[0] == sourceNode.level && row[1] == sourceNode.hop ) ) { + sourceNode.level = sourceNode.level + 1 ; + } else { + positionArray.push([sourceNode.level, sourceNode.hop]); + } }); + // Creates links map from Relationships, avoid duplicates data.forEach(({ graph, row }) => { graph.relationships.forEach(({ startNode, endNode, properties, id }) => { let matchingStartNode = nodes.find(node => node.id === parseInt(startNode)); let matchingEndNode = nodes.find(node => node.id === parseInt(endNode)); - let reverseLink = false; - if ( matchingStartNode.positionX >= matchingEndNode.positionX ){ - reverseLink = true - } - - if ( !reverseLink ) { + if ( row[3].includes(parseInt(id)) ) { if (linksMap.get(startNode) === undefined) { linksMap.set(startNode, new Array()); } - + let newLink = true; linksMap.get(startNode).find( ele => { if ( ele.target !== endNode ) { @@ -178,7 +183,7 @@ export function queryParser (e) { newLink = false; } }); - + // Only keep track of new links, avoid duplicates if ( newLink ) { linksMap.get(startNode).push( { target : endNode, label : properties[e.data.params.configuration.resultsMapping.link.label], weight : properties[e.data.params.configuration.resultsMapping.link.weight] }); @@ -188,30 +193,11 @@ export function queryParser (e) { if (reverseMap.get(startNode) === undefined) { reverseMap.set(startNode, new Array()); } - reverseMap.get(startNode).push( { target : endNode, label : properties[e.data.params.configuration.resultsMapping.link.label], weight : properties[e.data.params.configuration.resultsMapping.link.weight] }); - } + } }); }); - // Loop through reverse map and find reverse links - reverseMap.forEach( (value, key) => { - let linkInMap = value.find( valueNode => { - let found = linksMap?.get(valueNode.target)?.find( ele => { - if ( ele.target === key ) { - return ele; - } - }); - - if ( !found ) { - if (linksMap.get(key) === undefined) { - linksMap.set(key, new Array()); - } - linksMap?.get(key)?.push( { target : valueNode?.target, label : valueNode?.label, weight : valueNode?.weight }); - } - }) - }); - // Creates Links array with nodes, assign node neighbors that are connected by links nodes.forEach( sourceNode => { let id = sourceNode.id; @@ -227,7 +213,8 @@ export function queryParser (e) { let reverse = reverseMap.get(targetNode.id.toString())?.find( node => node.target === sourceNode.id.toString()); if ( !match ) { // Create tooltip label for link and weight - const tooltip = "Label : " + n[i].label + '
    ' + const labelWeight = n[i].weight >= weight ? n[i].weight : 0; + const tooltip = "Label : " + n[i].label + '
    ' + "Weight : " + (reverse ? n[i].weight + " [" + reverse.weight + "]" : n[i].weight + "[0]"); const weightLabel = reverse ? n[i].weight + " [" + reverse.weight + "]" : n[i].weight + "[0]"; // Create new link for graph diff --git a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js index 92c46388b..04bd523ba 100644 --- a/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js +++ b/components/interface/VFBCircuitBrowser/VFBCircuitBrowser.js @@ -250,6 +250,7 @@ class VFBCircuitBrowser extends Component { configuration : configuration, styling : stylingConfiguration, paths : self.state.paths, + weight : self.state.weight, NODE_WIDTH : NODE_WIDTH, NODE_HEIGHT : NODE_HEIGHT } @@ -455,7 +456,7 @@ class VFBCircuitBrowser extends Component { dagMode="lr" nodeVal = { node => { node.fx = node.positionX; - node.fy = node.level > 0 ? -100 * node.level : node.fy ? node.fy : 0 ; + node.fy = -100 * node.level }} dagLevelDistance = {25} onDagError={loopNodeIds => {}} From 46492b77bcbe2a2958fea9594c55c94700d972ae Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 27 Jul 2021 14:26:36 +0100 Subject: [PATCH 30/49] typing in parts --- tests/jest/vfb/batch2/slice-viewer-tests.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/jest/vfb/batch2/slice-viewer-tests.js b/tests/jest/vfb/batch2/slice-viewer-tests.js index 726e153aa..56180c0e1 100644 --- a/tests/jest/vfb/batch2/slice-viewer-tests.js +++ b/tests/jest/vfb/batch2/slice-viewer-tests.js @@ -69,7 +69,8 @@ describe('VFB Slice Viewer Component Tests', () => { it('Typing medu in the query builder search bar', async () => { await page.focus('input#query-typeahead'); - await page.keyboard.type('medu'); + await page.keyboard.type('med'); + await page.keyboard.type('ulla'); await page.keyboard.press(String.fromCharCode(13)) await wait4selector(page, 'div.tt-suggestion', { visible: true , timeout : 10000}) From 06382aae7593e60f469ca74a9fcba731621f476e Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 30 Jul 2021 09:16:24 +0100 Subject: [PATCH 31/49] Revert "excluding DownloadMeta" This reverts commit e826b3b693f7238196480e61ffed6e3d915c7127. --- components/VFBMain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index b385f2759..1052fbef3 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -914,7 +914,7 @@ class VFBMain extends React.Component { self.setState({ UIUpdated: true }) }} focusTermRef={this.focusTermReference} - exclude={["ClassQueriesFrom", "Debug", "DownloadMeta"]} + exclude={["ClassQueriesFrom", "Debug"]} order={['Symbol', 'Title', 'Name', From 0a48398f74ccd699e16c0572938d3bac9bb7f239 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 30 Jul 2021 09:48:47 +0100 Subject: [PATCH 32/49] Revert "Revert "excluding DownloadMeta"" This reverts commit 06382aae7593e60f469ca74a9fcba731621f476e. --- components/VFBMain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/VFBMain.js b/components/VFBMain.js index 1052fbef3..b385f2759 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -914,7 +914,7 @@ class VFBMain extends React.Component { self.setState({ UIUpdated: true }) }} focusTermRef={this.focusTermReference} - exclude={["ClassQueriesFrom", "Debug"]} + exclude={["ClassQueriesFrom", "Debug", "DownloadMeta"]} order={['Symbol', 'Title', 'Name', From b5e82ecf60bfe9c11d0124fe2125fc493d161582 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 10 Aug 2021 11:05:15 +0100 Subject: [PATCH 33/49] adding Adult Head template --- .../VFBToolbar/vfbtoolbarMenuConfiguration.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js b/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js index 67169b050..7d07aeefd 100644 --- a/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js +++ b/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js @@ -447,6 +447,14 @@ var toolbarMenu = { parameters: ["undefinedAction"] }, list: [ + { + label: "Adult Head (McKellar)", + icon: "", + action: { + handlerAction: "openNewTab", + parameters: ["/org.geppetto.frontend/geppetto?i=VFB_00110000"] + } + }, { label: "Adult Brain (JFRC2/2010)", icon: "", @@ -560,6 +568,14 @@ var toolbarMenu = { parameters: ["undefinedAction"] }, list: [ + { + label: "Adult Head (McKellar)", + icon: "", + action: { + handlerAction: "triggerRunQuery", + parameters: ["AlignedDatasets,VFB_00110000,adult head template McKellar"] + } + }, { label: "Adult Brain (JFRC2/2010)", icon: "", From 9fd48c7f9fa31602d89634f3fb84e63370255763 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Thu, 12 Aug 2021 17:45:14 -0700 Subject: [PATCH 34/49] #1172 NBLAST Uploader component implementation --- components/VFBMain.js | 6 ++++++ .../VFBToolbar/vfbtoolbarMenuConfiguration.js | 8 ++++++++ components/configuration/VFBUploader/configuration.json | 7 +++++++ package.json | 1 + 4 files changed, 22 insertions(+) create mode 100644 components/configuration/VFBUploader/configuration.json diff --git a/components/VFBMain.js b/components/VFBMain.js index 23aac443e..e16e44f06 100644 --- a/components/VFBMain.js +++ b/components/VFBMain.js @@ -9,6 +9,7 @@ import VFBTermInfoWidget from './interface/VFBTermInfo/VFBTermInfo'; import Logo from '@geppettoengine/geppetto-client/components/interface/logo/Logo'; import Canvas from '@geppettoengine/geppetto-client/components/interface/3dCanvas/Canvas'; import QueryBuilder from '@geppettoengine/geppetto-client/components/interface/query/queryBuilder'; +import VFBUploader from './interface/VFBUploader/VFBUploader'; import HTMLViewer from '@geppettoengine/geppetto-ui/html-viewer/HTMLViewer'; import VFBListViewer from './interface/VFBListViewer/VFBListViewer'; import * as FlexLayout from '@geppettoengine/geppetto-ui/flex-layout/src/index'; @@ -51,6 +52,7 @@ class VFBMain extends React.Component { quickHelpVisible: undefined, UIUpdated: true, wireframeVisible: false, + uploaderContentsVisible : true }; this.addVfbId = this.addVfbId.bind(this); @@ -525,6 +527,9 @@ class VFBMain extends React.Component { case 'triggerSetTermInfo': this.handlerInstanceUpdate(click.value[0]); break; + case 'uploaderContentsVisible': + this.refs.uploaderContentsRef?.openDialog(); + break; case 'triggerRunQuery': GEPPETTO.trigger('spin_logo'); var that = this; @@ -1747,6 +1752,7 @@ class VFBMain extends React.Component { searchConfiguration={this.searchConfiguration} datasourceConfiguration={this.datasourceConfiguration} /> + {this.htmlToolbarRender}
    ); diff --git a/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js b/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js index 7d07aeefd..a85df3499 100644 --- a/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js +++ b/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.js @@ -253,6 +253,14 @@ var toolbarMenu = { parameters: ["circuitBrowserVisible"] } }, + { + label: "NBLAST Uploader", + icon: "fa fa-upload", + action: { + handlerAction: "uploaderContentsVisible", + parameters: [] + } + }, { label: "NBLAST", icon: "", diff --git a/components/configuration/VFBUploader/configuration.json b/components/configuration/VFBUploader/configuration.json new file mode 100644 index 000000000..7f8b32090 --- /dev/null +++ b/components/configuration/VFBUploader/configuration.json @@ -0,0 +1,7 @@ +{ + "nblastURL" : "https://zip.virtualflybrain.org/download", + "templates" : [ + { "VFB_00101567" : "VFB_00101567 Template" }, + { "VFB_00000001" : "VFB_00000001 Template" } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index a64b64f55..eb74472e6 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "jest-image-snapshot": "^4.1.0", "jest-puppeteer": "^4.3.0", "less-loader": "^5.0.0", + "material-ui-dropzone": "^3.5.0", "mini-css-extract-plugin": "^0.7.0", "puppeteer": "^1.17.0", "react-collapsible": "^2.3.1", From b9117b550bae6abc6a35eb0fef7591a62010eb36 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Thu, 12 Aug 2021 17:45:53 -0700 Subject: [PATCH 35/49] #1172 NBLAST Uploader component --- .../interface/VFBUploader/VFBUploader.js | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 components/interface/VFBUploader/VFBUploader.js diff --git a/components/interface/VFBUploader/VFBUploader.js b/components/interface/VFBUploader/VFBUploader.js new file mode 100644 index 000000000..813456065 --- /dev/null +++ b/components/interface/VFBUploader/VFBUploader.js @@ -0,0 +1,183 @@ +import React from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import FormControl from '@material-ui/core/FormControl'; +import Typography from '@material-ui/core/Typography'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import InputLabel from '@material-ui/core/InputLabel'; +import Select from '@material-ui/core/Select'; +import ChevronRightIcon from "@material-ui/icons/ChevronRight"; +import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; +import Checkbox from '@material-ui/core/Checkbox'; +import { withStyles } from '@material-ui/styles'; +import axios from 'axios'; +import { DropzoneArea } from 'material-ui-dropzone' + +const PERMISSIONS = "Permissions to store"; +const styles = theme => ({ + listItemText: { fontSize:'1em' }, + templateSelection: { + float: "right !important", + width : "20% !important", + fontSize : "1 rem !important" + } +}); + +class VFBUploader extends React.Component { + constructor (props) { + super(props); + + this.state = { + open: false, + uploading : false, + files : [], + template : "" + } + + this.configuration = require('../../configuration/VFBUploader/configuration'); + this.handleCloseDialog = this.handleCloseDialog.bind(this); + this.openDialog = this.openDialog.bind(this); + this.handlePermissionsCheck = this.handlePermissionsCheck.bind(this); + this.handleUpload = this.handleUpload.bind(this); + this.requestUpload = this.requestUpload.bind(this); + } + + handleCloseDialog () { + this.setState({ open : false }); + } + + handleChange (files){ + this.setState({ files: files }); + } + + openDialog () { + this.setState({ open : true }); + } + + handleUpload () { + let json = { "entries" : [] }; + + this.state.selectedVariables.map( variable => { + const filemeta = this.extractVariableFileMeta(variable); + json.entries = json.entries.concat(filemeta); + }); + + json.entries.length > 0 ? this.requestZipDownload(json) : this.setState( { downloadError : true }); + } + + /** + * Make axios call to download the zip + */ + requestUpload (jsonRequest) { + let self = this; + + this.setState( { downloadEnabled : false, downloading : true } ); + // Axios HTTP Post request with post query + axios({ + method: 'post', + url: this.configuration.blastURL, + headers: { 'content-type': this.configuration.contentType }, + data: jsonRequest, + responseType: "arraybuffer" + }).then( function (response) { + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', self.configuration.zipName); + document.body.appendChild(link); + link.click(); + setTimeout( () => self.setState( { downloadEnabled : true, downloading : false, open : false } ), 500); + }).catch( function (error) { + self.downloadErrorMessage = error?.message; + self.setState( { downloadEnabled : true, dowloadError : true, downloading : false } ); + }) + } + + /** + * Handle checkbox selection of different types to download + */ + handlePermissionsCheck (value) { + const currentIndex = this.state.typesChecked.indexOf(value); + const newTypesChecked = [...this.state.typesChecked]; + + if (currentIndex === -1) { + newTypesChecked.push(value); + } else { + newTypesChecked.splice(currentIndex, 1); + } + + this.setState({ typesChecked : newTypesChecked, downloadEnabled : newTypesChecked.length > 0 , downloadError : false }); + } + + render () { + let self = this; + const { classes } = this.props; + + return ( + +

    NBLAST Uploader

    + + + Choose Template: + + + + + + self.handlePermissionsCheck()} + /> + } + label={{PERMISSIONS}} + /> + { + this.state.downloading ? : null + } + { + this.state.downloadError ? { self.dowloadErrorMessage } : null + } + + +
    + ) + } +} + +export default (withStyles(styles)(VFBUploader)); \ No newline at end of file From 244fbe37ce42bb86dc1c6237dfec3ad7931b1165 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 13 Aug 2021 07:39:31 -0700 Subject: [PATCH 36/49] #1174 Add own SOLR configuration files to circuit browser component --- .../datasources/SOLRclient.tsx | 196 ++++++++++++++++++ .../datasources/datasources.tsx | 4 + .../interface/VFBCircuitBrowser/Controls.js | 4 +- 3 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx create mode 100644 components/configuration/VFBCircuitBrowser/datasources/datasources.tsx diff --git a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx new file mode 100644 index 000000000..cfbcbff6d --- /dev/null +++ b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx @@ -0,0 +1,196 @@ +import axios from 'axios'; + +const globalConfiguration:any = { + "url": "https://solr-dev.virtualflybrain.org/solr/ontology/select", + "query_settings": + { + "q": "$SEARCH_TERM$ OR $SEARCH_TERM$* OR *$SEARCH_TERM$*", + "defType": "edismax", + "qf": "label synonym label_autosuggest_ws label_autosuggest_e label_autosuggest synonym_autosuggest_ws synonym_autosuggest_e synonym_autosuggest shortform_autosuggest has_narrow_synonym_annotation has_broad_synonym_annotation", + "indent": "true", + "fl": "short_form,label,synonym,id,type,has_narrow_synonym_annotation,has_broad_synonym_annotation,facets_annotation", + "start": "0", + "fq": [ + "type:class OR type:individual OR type:property", + "ontology_name:(vfb)", + "shortform_autosuggest:VFB* OR shortform_autosuggest:FB* OR is_defining_ontology:true" + ], + "rows": "100", + "wt": "json", + "bq": "is_obsolete:false^100.0 shortform_autosuggest:VFB*^110.0 shortform_autosuggest:FBbt*^100.0 is_defining_ontology:true^100.0 label_s:\"\"^2 synonym_s:\"\" in_subset_annotation:BRAINNAME^3 short_form:FBbt_00003982^2" + } +}; + +let solrConfiguration:any = { + params: { + json: { + params: globalConfiguration.query_settings + } + } +} + +export function getResultsSOLR ( searchString: string, returnResults: Function, sorter: Function, configuration?: any) { + var url:string = configuration.url; + + if (configuration.url === undefined) { + url = globalConfiguration.url; + } + if (configuration.query_settings !== undefined) { + solrConfiguration.params.json.params = configuration.query_settings; + } + + // hack to clone the object + let tempConfig:any = JSON.parse(JSON.stringify(solrConfiguration)); + tempConfig.params.json.params.q = solrConfiguration.params.json.params.q.replace(/\$SEARCH_TERM\$/g, searchString); + + axios.get(`${url}`, tempConfig) + .then(function(response) { + var blob = new Blob(["onmessage = " + refineResults]); + var blobUrl = window.URL.createObjectURL(blob); + + var worker = new Worker(blobUrl); + worker.onmessage = function (e) { + switch(e.data.resultMessage) { + case "OK": + returnResults("OK", e.data.params.results, searchString); + window.URL.revokeObjectURL(blobUrl); + break; + } + }; + worker.postMessage({message: "refine", params: {results: response.data.response.docs, value: searchString}}); + + // refineResults(searchString, response.data.response.docs, returnResults); + }) + .catch(function(error) { + console.log('%c --- SOLR datasource error --- ', 'background: black; color: red'); + console.log(error); + returnResults("ERROR", undefined, searchString); + }) +}; + +function refineResults(e) { + const sorter = function (a, b) { + var InputString = self.spotlightString; + + // move exact matches to top + if (InputString == a.label) { + return -1; + } + if (InputString == b.label) { + return 1; + } + // close match without case matching + if (InputString.toLowerCase() == a.label.toLowerCase()) { + return -1; + } + if (InputString.toLowerCase() == b.label.toLowerCase()) { + return 1; + } + // match ignoring joinging nonwords + if (InputString.toLowerCase().split(/\W+/).join(' ') == a.label.toLowerCase().split(/\W+/).join(' ')) { + return -1; + } + if (InputString.toLowerCase().split(/\W+/).join(' ') == b.label.toLowerCase().split(/\W+/).join(' ')) { + return 1; + } + // match against id + if (InputString.toLowerCase() == a.id.toLowerCase()) { + return -1; + } + if (InputString.toLowerCase() == b.id.toLowerCase()) { + return 1; + } + // pick up any match without nonword join character match + if (a.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) < 0 && b.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) > -1) { + return 1; + } + if (b.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) < 0 && a.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) > -1) { + return -1; + } + // also with underscores ignored + if (a.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) < 0 && b.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) > -1) { + return 1; + } + if (b.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) < 0 && a.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) > -1) { + return -1; + } + // if not found in one then advance the other + if (a.label.toLowerCase().indexOf(InputString.toLowerCase()) < 0 && b.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1) { + return 1; + } + if (b.label.toLowerCase().indexOf(InputString.toLowerCase()) < 0 && a.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1) { + return -1; + } + // if the match is closer to start than the other move up + if (a.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && a.label.toLowerCase().indexOf(InputString.toLowerCase()) < b.label.toLowerCase().indexOf(InputString.toLowerCase())) { + return -1; + } + if (b.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && b.label.toLowerCase().indexOf(InputString.toLowerCase()) < a.label.toLowerCase().indexOf(InputString.toLowerCase())) { + return 1; + } + // if the match in the id is closer to start then move up + if (a.id.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && a.id.toLowerCase().indexOf(InputString.toLowerCase()) < b.id.toLowerCase().indexOf(InputString.toLowerCase())) { + return -1; + } + if (b.id.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && b.id.toLowerCase().indexOf(InputString.toLowerCase()) < a.id.toLowerCase().indexOf(InputString.toLowerCase())) { + return 1; + } + // move the shorter synonyms to the top + if (a.label < b.label) { + return -1; + } else if (a.label > b.label) { + return 1; + } else { + return 0; + } // if nothing found then do nothing. + }; + + self.spotlightString = e.data.params.value; + var refinedResults:Array = []; + e.data.params.results.map(item => { + if (item.hasOwnProperty("synonym")) { + item.synonym.map(innerItem => { + let newRecord:any = {} + if (innerItem !== item.label) { + Object.keys(item).map(key => { + switch(key) { + case "label": + newRecord[key] = innerItem + " (" + item.label + ")"; + break; + case "synonym": + break; + default: + newRecord[key] = item[key]; + } + }); + refinedResults.push(newRecord); + } + }); + let newRecord:any = {} + Object.keys(item).map(key => { + if (key !== "synonym") { + if (key === "label") { + newRecord[key] = item[key] + " (" + item["short_form"] + ")"; + } else { + newRecord[key] = item[key]; + } + } + }); + refinedResults.push(newRecord); + } else { + let newRecord:any = {} + Object.keys(item).map(key => { + if (key === "label") { + newRecord[key] = item[key] + " (" + item["short_form"] + ")"; + } else { + newRecord[key] = item[key]; + } + }); + refinedResults.push(newRecord); + } + }); + + var sortedResults: Array = refinedResults.sort(sorter); + this.postMessage({resultMessage: "OK", params: {results: sortedResults}}); + self.close(); +} diff --git a/components/configuration/VFBCircuitBrowser/datasources/datasources.tsx b/components/configuration/VFBCircuitBrowser/datasources/datasources.tsx new file mode 100644 index 000000000..1b5496503 --- /dev/null +++ b/components/configuration/VFBCircuitBrowser/datasources/datasources.tsx @@ -0,0 +1,4 @@ +export enum DatasourceTypes { + CUSTOM = 'CUSTOM', + SOLRClient = 'SOLR' +} \ No newline at end of file diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 37acea4b3..285eceb08 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -27,8 +27,8 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; import { connect } from "react-redux"; import { UPDATE_CIRCUIT_QUERY } from './../../../actions/generals'; -import { DatasourceTypes } from '@geppettoengine/geppetto-ui/search/datasources/datasources'; -import { getResultsSOLR } from "@geppettoengine/geppetto-ui/search/datasources/SOLRclient"; +import { DatasourceTypes } from '../../configuration/VFBCircuitBrowser/datasources/datasources'; +import { getResultsSOLR } from "../../configuration/VFBCircuitBrowser/datasources/SOLRclient"; /** * Create a local theme to override some default values in material-ui components From c733206dac6932728df521809c0084fc52a7c178 Mon Sep 17 00:00:00 2001 From: jrmartin Date: Fri, 13 Aug 2021 11:50:15 -0700 Subject: [PATCH 37/49] #1172 Uploader configuration --- .../VFBUploader/configuration.json | 7 +- .../interface/VFBUploader/VFBUploader.js | 119 ++++++++---------- 2 files changed, 60 insertions(+), 66 deletions(-) diff --git a/components/configuration/VFBUploader/configuration.json b/components/configuration/VFBUploader/configuration.json index 7f8b32090..a6d1a1091 100644 --- a/components/configuration/VFBUploader/configuration.json +++ b/components/configuration/VFBUploader/configuration.json @@ -1,7 +1,12 @@ { "nblastURL" : "https://zip.virtualflybrain.org/download", + "contentType" : "", "templates" : [ { "VFB_00101567" : "VFB_00101567 Template" }, { "VFB_00000001" : "VFB_00000001 Template" } - ] + ], + "acceptedFiles" : [".swc"], + "filesLimit" : 10, + "maxFileSize" : 3000000, + "dropZoneMessage" : "Drag and drop a SWC file here or click" } \ No newline at end of file diff --git a/components/interface/VFBUploader/VFBUploader.js b/components/interface/VFBUploader/VFBUploader.js index 813456065..020486f0d 100644 --- a/components/interface/VFBUploader/VFBUploader.js +++ b/components/interface/VFBUploader/VFBUploader.js @@ -19,14 +19,15 @@ import { withStyles } from '@material-ui/styles'; import axios from 'axios'; import { DropzoneArea } from 'material-ui-dropzone' -const PERMISSIONS = "Permissions to store"; +const PERMISSIONS = "Permissions to store URL in browser history"; const styles = theme => ({ listItemText: { fontSize:'1em' }, templateSelection: { - float: "right !important", - width : "20% !important", - fontSize : "1 rem !important" - } + width : "30% !important", + height : "5rem" + }, + templateContent : { fontSize : "14px" }, + dialogActions : { justifyContent : "space-evenly" } }); class VFBUploader extends React.Component { @@ -36,15 +37,17 @@ class VFBUploader extends React.Component { this.state = { open: false, uploading : false, + nblastEnabled : false, files : [], - template : "" + permissionsChecked : false, + templateSelected : "" } this.configuration = require('../../configuration/VFBUploader/configuration'); this.handleCloseDialog = this.handleCloseDialog.bind(this); this.openDialog = this.openDialog.bind(this); this.handlePermissionsCheck = this.handlePermissionsCheck.bind(this); - this.handleUpload = this.handleUpload.bind(this); + this.handleNBLASTAction = this.handleNBLASTAction.bind(this); this.requestUpload = this.requestUpload.bind(this); } @@ -52,23 +55,20 @@ class VFBUploader extends React.Component { this.setState({ open : false }); } - handleChange (files){ + handleDropZoneChange (files){ this.setState({ files: files }); } + handleTemplateChange (event) { + this.setState({ templateSelected : event.target.value }) + } + openDialog () { this.setState({ open : true }); } - handleUpload () { - let json = { "entries" : [] }; - - this.state.selectedVariables.map( variable => { - const filemeta = this.extractVariableFileMeta(variable); - json.entries = json.entries.concat(filemeta); - }); - - json.entries.length > 0 ? this.requestZipDownload(json) : this.setState( { downloadError : true }); + handleNBLASTAction () { + this.requestUpload({}); } /** @@ -77,42 +77,28 @@ class VFBUploader extends React.Component { requestUpload (jsonRequest) { let self = this; - this.setState( { downloadEnabled : false, downloading : true } ); + this.setState( { uploading : true } ); // Axios HTTP Post request with post query axios({ method: 'post', - url: this.configuration.blastURL, + url: this.configuration.nblastURL, headers: { 'content-type': this.configuration.contentType }, data: jsonRequest, responseType: "arraybuffer" }).then( function (response) { const url = window.URL.createObjectURL(new Blob([response.data])); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', self.configuration.zipName); - document.body.appendChild(link); - link.click(); - setTimeout( () => self.setState( { downloadEnabled : true, downloading : false, open : false } ), 500); + setTimeout( () => self.setState( { nblastEnabled : true, uploading : false } ), 500); }).catch( function (error) { self.downloadErrorMessage = error?.message; - self.setState( { downloadEnabled : true, dowloadError : true, downloading : false } ); + self.setState( { nblastEnabled : true, uploading : false } ); }) } /** * Handle checkbox selection of different types to download */ - handlePermissionsCheck (value) { - const currentIndex = this.state.typesChecked.indexOf(value); - const newTypesChecked = [...this.state.typesChecked]; - - if (currentIndex === -1) { - newTypesChecked.push(value); - } else { - newTypesChecked.splice(currentIndex, 1); - } - - this.setState({ typesChecked : newTypesChecked, downloadEnabled : newTypesChecked.length > 0 , downloadError : false }); + handlePermissionsCheck (event) { + this.setState({ permissionsChecked : event.target.checked }); } render () { @@ -123,55 +109,58 @@ class VFBUploader extends React.Component { -

    NBLAST Uploader

    +

    NBLAST Uploader

    - Choose Template: + Choose Template: - - self.handlePermissionsCheck()} - /> - } - label={{PERMISSIONS}} - /> - { - this.state.downloading ? : null - } + +
    + --- NBLAST Text Updates --- + self.handlePermissionsCheck(event)} + /> + } + label={{PERMISSIONS}} + /> +
    { - this.state.downloadError ? { self.dowloadErrorMessage } : null + self.state.uploading ? : null } -
    From 63f3cbea7afa74a036de73f8251bf0528415eb3f Mon Sep 17 00:00:00 2001 From: Rob Court Date: Mon, 23 Aug 2021 12:10:10 +0100 Subject: [PATCH 38/49] fix for any pdb server --- dockerFiles/startup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerFiles/startup.sh b/dockerFiles/startup.sh index b3bc4f5da..78b0cce02 100755 --- a/dockerFiles/startup.sh +++ b/dockerFiles/startup.sh @@ -17,8 +17,8 @@ then grep -rls url $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/VFBGraph/graphConfiguration.js grep -rls url $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/VFBGraph/graphConfiguration.js | xargs sed -i "s@https://pdb.*virtualflybrain.org@$VFB_TREE_PDB_SERVER@g" echo "Server PDB: $VFB_PDB_SERVER" - grep -rls http://pdb.virtualflybrain.org $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi - grep -rls http://pdb.virtualflybrain.org $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi | xargs sed -i "s@http://pdb.*virtualflybrain.org@$VFB_PDB_SERVER@g" + grep -rls "http://pdb.*virtualflybrain.org" $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi + grep -rls "http://pdb.*virtualflybrain.org" $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi | xargs sed -i "s@http://pdb.*virtualflybrain.org@$VFB_PDB_SERVER@g" echo "Server OWL: $VFB_OWL_SERVER" grep -rls http://owl.virtualflybrain.org/kbs/vfb/ $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi grep -rls http://owl.virtualflybrain.org/kbs/vfb/ $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi | xargs sed -i "s@http://owl.*virtualflybrain.org/kbs/vfb/@$VFB_OWL_SERVER@g" From 56524f19faaa3054757991cef3ba0adb55f5324f Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 31 Aug 2021 11:15:06 +0100 Subject: [PATCH 39/49] filtering for only has_neuron_connectivity --- .../configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx index cfbcbff6d..7164ab895 100644 --- a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx +++ b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx @@ -13,6 +13,7 @@ const globalConfiguration:any = { "fq": [ "type:class OR type:individual OR type:property", "ontology_name:(vfb)", + "facets_annotation:has_neuron_connectivity", "shortform_autosuggest:VFB* OR shortform_autosuggest:FB* OR is_defining_ontology:true" ], "rows": "100", From 544fb0d25ca14c4ae86a1834c67e5906541380bd Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 31 Aug 2021 12:52:23 +0100 Subject: [PATCH 40/49] moving datasourceConfiguration to custom --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 285eceb08..a72f285bc 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -123,7 +123,7 @@ const cypherQuery = require('../../configuration/VFBCircuitBrowser/circuitBrowse const stylingConfiguration = require('../../configuration/VFBCircuitBrowser/circuitBrowserConfiguration').styling; const searchConfiguration = require('./../../configuration/VFBMain/searchConfiguration').searchConfiguration; -const datasourceConfiguration = require('./../../configuration/VFBMain/searchConfiguration').datasourceConfiguration; +const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').datasourceConfiguration; /** * Create custom marks for Paths slider. From 56d7d09b0dc9001ecfae139cf97bc1da94c687b7 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Tue, 31 Aug 2021 14:13:00 +0100 Subject: [PATCH 41/49] swapping to globalConfiguration:any --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index a72f285bc..b718f8488 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -123,7 +123,7 @@ const cypherQuery = require('../../configuration/VFBCircuitBrowser/circuitBrowse const stylingConfiguration = require('../../configuration/VFBCircuitBrowser/circuitBrowserConfiguration').styling; const searchConfiguration = require('./../../configuration/VFBMain/searchConfiguration').searchConfiguration; -const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').datasourceConfiguration; +const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').globalConfiguration:any; /** * Create custom marks for Paths slider. From d53ad11a749a506c57ac5735b9f334aff3786944 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Wed, 1 Sep 2021 17:55:37 +0100 Subject: [PATCH 42/49] removing any --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index b718f8488..7acc2b906 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -123,7 +123,7 @@ const cypherQuery = require('../../configuration/VFBCircuitBrowser/circuitBrowse const stylingConfiguration = require('../../configuration/VFBCircuitBrowser/circuitBrowserConfiguration').styling; const searchConfiguration = require('./../../configuration/VFBMain/searchConfiguration').searchConfiguration; -const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').globalConfiguration:any; +const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').globalConfiguration; /** * Create custom marks for Paths slider. From 790c36da1a40ba2ee7e8703d96df09808cef18fd Mon Sep 17 00:00:00 2001 From: jrmartin Date: Wed, 1 Sep 2021 10:22:34 -0700 Subject: [PATCH 43/49] Fix configuration file issues for circuit browser, not pointing to correct configuration. --- .../datasources/SOLRclient.tsx | 241 ++++++++++++++++++ .../interface/VFBCircuitBrowser/Controls.js | 5 +- 2 files changed, 243 insertions(+), 3 deletions(-) diff --git a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx index 7164ab895..2c84230c4 100644 --- a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx +++ b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx @@ -195,3 +195,244 @@ function refineResults(e) { this.postMessage({resultMessage: "OK", params: {results: sortedResults}}); self.close(); } + +export const datasourceConfiguration = { + "url": "https://solr.virtualflybrain.org/solr/ontology/select", + "query_settings": + { + "q": "$SEARCH_TERM$ OR $SEARCH_TERM$* OR *$SEARCH_TERM$*", + "defType": "edismax", + "qf": "label^100 synonym^100 label_autosuggest_ws label_autosuggest_e label_autosuggest synonym_autosuggest_ws synonym_autosuggest shortform_autosuggest", + "indent": "true", + "fl": "short_form,label,synonym,id,facets_annotation", + "start": "0", + "pf":"true", + "fq": [ + "shortform_autosuggest:VFB* OR shortform_autosuggest:FB*" + ], + "rows": "100", + "wt": "json", + "bq": "shortform_autosuggest:VFB*^110.0 shortform_autosuggest:FBbt*^100.0 label_s:\"\"^2 synonym_s:\"\" short_form:FBbt_00003982^2 facets_annotation:Deprecated^0.001" + } +}; + +export const searchConfiguration = { + "resultsMapping": + { + "name": "label", + "id": "short_form" + }, + "filters_expanded": true, + "filters": [ + { + "key": "facets_annotation", + "filter_name": "Filters", + "type": "array", + "enabled": "disabled", + "disableGlobal": true, + "values": [ + { + "key": "Adult", + "filter_name": "Adult", + "enabled": "disabled", + }, + { + "key": "Larva", + "filter_name": "Larva", + "enabled": "disabled", + }, + { + "key": "Nervous_system", + "filter_name": "Nervous System", + "enabled": "disabled", + }, + { + "key": "Anatomy", + "filter_name": "Anatomy", + "enabled": "disabled", + }, + { + "key": "Neuron", + "filter_name": "Neuron", + "enabled": "disabled", + }, + { + "key": "has_image", + "filter_name": "Image", + "enabled": "disabled", + }, + { + "key": "Split", + "filter_name": "Split Expression", + "enabled": "disabled", + }, + { + "key": "Expression_pattern", + "filter_name": "Expression Pattern", + "enabled": "disabled", + }, + { + "key": "Expression_pattern_fragment", + "filter_name": "Expression Pattern Fragment", + "enabled": "disabled", + }, + { + "key": "has_neuron_connectivity", + "filter_name": "Neuron with Connectivity", + "enabled": "disabled", + }, + { + "key": "NBLAST", + "filter_name": "Neuron Similarity (NBLAST)", + "enabled": "disabled", + }, + { + "key": "NBLASTexp", + "filter_name": "Expression Similarity (NBLAST)", + "enabled": "disabled", + }, + { + "key": "Synaptic_neuropil_domain", + "filter_name": "Synaptic Neuropil", + "enabled": "disabled", + }, + { + "key": "DataSet", + "filter_name": "Dataset", + "enabled": "disabled", + }, + { + "key": "Deprecated", + "filter_name": "Deprecated", + "enabled": "negative", + } + ] + }, + ], + "sorter": function (a, b) { + var InputString = window.spotlightString; + // move exact matches to top + if (InputString == a.label) { + return -1; + } + if (InputString == b.label) { + return 1; + } + // close match without case matching + if (InputString.toLowerCase() == a.label.toLowerCase()) { + return -1; + } + if (InputString.toLowerCase() == b.label.toLowerCase()) { + return 1; + } + // match ignoring joinging nonwords + if (InputString.toLowerCase().split(/\W+/).join(' ') == a.label.toLowerCase().split(/\W+/).join(' ')) { + return -1; + } + if (InputString.toLowerCase().split(/\W+/).join(' ') == b.label.toLowerCase().split(/\W+/).join(' ')) { + return 1; + } + // match against id + if (InputString.toLowerCase() == a.id.toLowerCase()) { + return -1; + } + if (InputString.toLowerCase() == b.id.toLowerCase()) { + return 1; + } + // pick up any match without nonword join character match + if (a.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) < 0 && b.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) > -1) { + return 1; + } + if (b.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) < 0 && a.label.toLowerCase().split(/\W+/).join(' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ')) > -1) { + return -1; + } + // also with underscores ignored + if (a.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) < 0 && b.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) > -1) { + return 1; + } + if (b.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) < 0 && a.label.toLowerCase().split(/\W+/).join(' ').replace('_', ' ').indexOf(InputString.toLowerCase().split(/\W+/).join(' ').replace('_', ' ')) > -1) { + return -1; + } + // find all matching spaced words + if (InputString.toLowerCase().indexOf(' ') > -1) { + var lcInputStingFac = InputString.toLowerCase().split(' '); + var compare = (a1, a2) => a1.filter(v => a2.includes(v)).length; + var cA = compare(lcInputStingFac, a.label.toLowerCase().split(' ')); + var cB = compare(lcInputStingFac, b.label.toLowerCase().split(' ')); + if (cA > 0 || cB > 0) { + if (cA > cB) { + return -1; + } + if (cA < cB) { + return 1; + } + } + } + // find all tokenised word matches + if (InputString.split(/\W+/).length > 1) { + var lcInputStingFac = InputString.toLowerCase().split(/\W+/); + var compare = (a1, a2) => a1.filter(v => a2.includes(v)).length; + var cA = compare(lcInputStingFac, a.label.toLowerCase().split(/\W+/)); + var cB = compare(lcInputStingFac, b.label.toLowerCase().split(/\W+/)); + if (cA > 0 || cB > 0) { + if (cA > cB) { + return -1; + } + if (cA < cB) { + return 1; + } + } + } + // prioritise matches in the primary label + if (InputString.split(/\W+/).length > 1) { + var lcInputStingFac = InputString.toLowerCase().split(/\W+/); + var compare = (a1, a2) => a1.filter(v => a2.includes(v)).length; + var aLabel = a.label.split(' ('); + var aEnd = aLabel.pop(aLabel.length); + aLabel = aLabel.join(' ('); + var bLabel = b.label.split(' ('); + var bEnd = bLabel.pop(bLabel.length); + bLabel = bLabel.join(' ('); + var cA = compare(lcInputStingFac, aLabel.toLowerCase().split(/\W+/)); + var cB = compare(lcInputStingFac, bLabel.toLowerCase().split(/\W+/)); + if (cA > 0 || cB > 0) { + if (cA > cB) { + return -1; + } + if (cA < cB) { + return 1; + } + } + } + // if not found in one then advance the other + if (a.label.toLowerCase().indexOf(InputString.toLowerCase()) < 0 && b.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1) { + return 1; + } + if (b.label.toLowerCase().indexOf(InputString.toLowerCase()) < 0 && a.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1) { + return -1; + } + // if the match is closer to start than the other move up + if (a.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && a.label.toLowerCase().indexOf(InputString.toLowerCase()) < b.label.toLowerCase().indexOf(InputString.toLowerCase())) { + return -1; + } + if (b.label.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && b.label.toLowerCase().indexOf(InputString.toLowerCase()) < a.label.toLowerCase().indexOf(InputString.toLowerCase())) { + return 1; + } + // if the match in the id is closer to start then move up + if (a.id.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && a.id.toLowerCase().indexOf(InputString.toLowerCase()) < b.id.toLowerCase().indexOf(InputString.toLowerCase())) { + return -1; + } + if (b.id.toLowerCase().indexOf(InputString.toLowerCase()) > -1 && b.id.toLowerCase().indexOf(InputString.toLowerCase()) < a.id.toLowerCase().indexOf(InputString.toLowerCase())) { + return 1; + } + // move the shorter synonyms to the top + if (a.label < b.label) { + return -1; + } else if (a.label > b.label) { + return 1; + } else { + return 0; + } // if nothing found then do nothing. + } +}; + diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 7acc2b906..7fa8b5571 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -27,7 +27,6 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; import { connect } from "react-redux"; import { UPDATE_CIRCUIT_QUERY } from './../../../actions/generals'; -import { DatasourceTypes } from '../../configuration/VFBCircuitBrowser/datasources/datasources'; import { getResultsSOLR } from "../../configuration/VFBCircuitBrowser/datasources/SOLRclient"; /** @@ -122,8 +121,8 @@ const restPostConfig = require('../../configuration/VFBCircuitBrowser/circuitBro const cypherQuery = require('../../configuration/VFBCircuitBrowser/circuitBrowserConfiguration').locationCypherQuery; const stylingConfiguration = require('../../configuration/VFBCircuitBrowser/circuitBrowserConfiguration').styling; -const searchConfiguration = require('./../../configuration/VFBMain/searchConfiguration').searchConfiguration; -const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').globalConfiguration; +const searchConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').searchConfiguration; +const datasourceConfiguration = require('./../../configuration/VFBCircuitBrowser/datasources/SOLRclient').datasourceConfiguration; /** * Create custom marks for Paths slider. From c3c4aa2d300a0eead6678440202956605ad8b889 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Thu, 2 Sep 2021 16:39:17 +0100 Subject: [PATCH 44/49] applying filtering --- .../configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx index 2c84230c4..54afb424f 100644 --- a/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx +++ b/components/configuration/VFBCircuitBrowser/datasources/SOLRclient.tsx @@ -208,6 +208,7 @@ export const datasourceConfiguration = { "start": "0", "pf":"true", "fq": [ + "facets_annotation:has_neuron_connectivity", "shortform_autosuggest:VFB* OR shortform_autosuggest:FB*" ], "rows": "100", From 7aafe1ad2e0b316cd5afa7af46da098d56b99d15 Mon Sep 17 00:00:00 2001 From: Rob Court Date: Fri, 3 Sep 2021 16:07:36 +0100 Subject: [PATCH 45/49] finding all solr refs --- dockerFiles/startup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerFiles/startup.sh b/dockerFiles/startup.sh index 78b0cce02..218201639 100755 --- a/dockerFiles/startup.sh +++ b/dockerFiles/startup.sh @@ -26,8 +26,8 @@ then grep -rls http://r.virtualflybrain.org/ocpu/library/vfbr/R/vfb_nblast $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi grep -rls http://r.virtualflybrain.org/ocpu/library/vfbr/R/vfb_nblast $HOME/workspace/org.geppetto.frontend/src/main/webapp/model/vfb.xmi | xargs sed -i "s@http://r.virtualflybrain.org/ocpu/library/vfbr/R/vfb_nblast@$VFB_R_SERVER@g" echo "Client SOLR Server: $SOLR_SERVER" - grep -rls https://solr.virtualflybrain.org/solr/ontology/select $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/VFBMain/ - grep -rls https://solr.virtualflybrain.org/solr/ontology/select $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/VFBMain/ | xargs sed -i "s@https://solr.*virtualflybrain.org/solr/ontology/select@$SOLR_SERVER@g" + grep -rls https://solr.*virtualflybrain.org/solr/ontology/select $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/ + grep -rls https://solr.*virtualflybrain.org/solr/ontology/select $HOME/workspace/org.geppetto.frontend/src/main/webapp/components/configuration/ | xargs sed -i "s@https://solr.*virtualflybrain.org/solr/ontology/select@$SOLR_SERVER@g" echo "Google Analytics code: ${googleAnalyticsSiteCode}" grep -rls "ga('create', 'UA-" $HOME/workspace/org.geppetto.frontend/ grep -rls "ga('create', 'UA-" $HOME/workspace/org.geppetto.frontend/ | xargs sed -i "s@ga('create', 'UA-[0-9]*-[0-9]'@ga('create', '${googleAnalyticsSiteCode}'@g" From 09fda4c8a97cc9cabf6e1e3a700afacd2b0bd2be Mon Sep 17 00:00:00 2001 From: Rob Court Date: Mon, 6 Sep 2021 09:29:38 +0100 Subject: [PATCH 46/49] changing refresh button name --- components/interface/VFBCircuitBrowser/Controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/interface/VFBCircuitBrowser/Controls.js b/components/interface/VFBCircuitBrowser/Controls.js index 7fa8b5571..220e1de53 100644 --- a/components/interface/VFBCircuitBrowser/Controls.js +++ b/components/interface/VFBCircuitBrowser/Controls.js @@ -589,7 +589,7 @@ class Controls extends Component { classes={{ root : classes.refreshButton }} id="refreshCircuitBrowser" onClick={() => this.props.updateGraph(this.neuronFields, this.paths, this.weight)} - >Refresh + >Run Query