@@ -3,46 +3,168 @@ import React, { Component } from 'react';
33export class Options extends Component {
44 constructor ( props ) {
55 super ( props ) ;
6- this . state = { preOpts : { } , value : '' , method : '' } ;
7- this . updateBox = this . updateBox . bind ( this ) ;
8- this . optionsJSX = this . optionsJSX . bind ( this ) ;
9- this . showAdvancedOptions = this . showAdvancedOptions . bind ( this ) ;
6+
7+ this . state = {
8+ textValue : '' ,
9+ objectValue : this . defaultObjectValue ( ) ,
10+ paramsMode : 'advanced'
11+ } ;
12+
13+ this . onTextValueChanged = this . onTextValueChanged . bind ( this ) ;
14+ this . optionsPresetsJSX = this . optionsPresetsJSX . bind ( this ) ;
15+ this . advancedParamsJSX = this . advancedParamsJSX . bind ( this ) ;
16+ this . showAdvancedOptionsHelp = this . showAdvancedOptionsHelp . bind ( this ) ;
17+ }
18+
19+
20+ defaultObjectValue ( ) {
21+ return {
22+ max_target_seqs : '' ,
23+ evalue : '' ,
24+ task : ''
25+ } ;
26+ } ;
27+
28+ componentDidUpdate ( prevProps ) {
29+ if ( prevProps . predefinedOptions !== this . props . predefinedOptions ) {
30+ let defaultOptions = this . props . predefinedOptions . default || { attributes : [ ] } ;
31+ let initialTextValue = ( this . props . predefinedOptions [ 'last search' ] ||
32+ defaultOptions . attributes || [ ] ) . join ( ' ' ) . trim ( ) ;
33+ let parsedOptions = this . parsedOptions ( initialTextValue ) ;
34+ this . setState ( { textValue : initialTextValue , objectValue : parsedOptions } ) ;
35+ }
1036 }
1137
12- updateBox ( value ) {
13- this . setState ( { value : value } ) ;
38+ onTextValueChanged ( textValue ) {
39+ let parsedOptions = this . parsedOptions ( textValue . toString ( ) ) ;
40+
41+ this . setState ( {
42+ textValue : textValue . toString ( ) ,
43+ objectValue : parsedOptions
44+ } ) ;
1445 }
1546
47+ parsedOptions ( textValue ) {
48+ const words = textValue . split ( " " ) ;
49+ let parsedOptions = this . defaultObjectValue ( ) ;
50+ // Iterate through the words in steps of 2, treating each pair as an option and its potential value
51+ for ( let i = 0 ; i < words . length ; i += 2 ) {
52+ // Ensure there is a pair available
53+ if ( words [ i ] ) {
54+ if ( words [ i ] . startsWith ( "-" ) ) {
55+ const optionName = words [ i ] . substring ( 1 ) . trim ( ) ;
1656
17- optionsJSX ( ) {
18- return < div id = "advanced-params-dropdown" className = "relative -ml-4 group" >
19- < button className = "h-full border border-gray-300 rounded-r p-1 px-2 bg-white hover:bg-gray-200" type = "button" >
20- < i className = "fa fa-caret-down h-4 w-4" > </ i >
21- < span className = "sr-only" > Advanced parameters</ span >
22- </ button >
23- < div className = 'z-20 group-hover:block hidden absolute top-full right-0 min-w-fit lg:min-w-[40rem]' >
24- < ul className = "font-mono my-1 border rounded divide-y" >
25- {
26- Object . entries ( this . state . preOpts ) . map (
27- ( [ key , value ] , index ) => {
28- value = value . join ( ' ' ) ;
29- var bgClass = 'bg-white' ;
30- if ( value . trim ( ) === this . state . value . trim ( ) )
31- bgClass = 'bg-yellow-100' ;
32- return < li key = { index } className = { `px-2 py-1 hover:bg-gray-200 cursor-pointer ${ bgClass } ` }
33- onClick = { ( ) => this . updateBox ( value ) } >
34- < strong > { key } :</ strong > { value }
35- </ li > ;
36- }
37- )
57+ if ( words [ i + 1 ] ) {
58+ // Use the second word as the value for this option
59+ parsedOptions [ optionName ] = words [ i + 1 ] ;
60+ } else {
61+ // No value found for this option, set it to null or a default value
62+ parsedOptions [ optionName ] = null ;
3863 }
39- </ ul >
64+ }
65+ }
66+ }
67+
68+ return parsedOptions ;
69+ }
70+
71+ optionsPresetsJSX ( ) {
72+ return (
73+ < div id = "options-presets" className = "w-full" >
74+ { Object . keys ( this . props . predefinedOptions ) . length > 1 && < >
75+ < h3 className = "w-full font-medium border-b border-seqorange mb-2" > Settings</ h3 >
76+
77+ < p className = "text-sm" > Choose a predefined setting or customize BLAST parameters.</ p >
78+ { this . presetListJSX ( ) }
79+ </ > }
4080 </ div >
41- </ div > ;
81+ ) ;
4282 }
43- showAdvancedOptions ( e ) {
83+
84+ presetListJSX ( ) {
85+ return (
86+ < ul className = "text-sm my-1" >
87+ {
88+ Object . entries ( this . props . predefinedOptions ) . map (
89+ ( [ key , config ] , index ) => {
90+ let textValue = config . attributes . join ( ' ' ) . trim ( ) ;
91+ let description = config . description || textValue ;
92+
93+ return (
94+ < label key = { index } className = { `block w-full px-2 py-1 hover:bg-gray-200 cursor-pointer` } >
95+ < input
96+ type = "radio"
97+ name = "predefinedOption"
98+ value = { textValue }
99+ checked = { textValue === this . state . textValue }
100+ onChange = { ( ) => this . onTextValueChanged ( textValue ) }
101+ />
102+ < strong className = "ml-2" > { key } :</ strong > { description }
103+ </ label >
104+ ) ;
105+ }
106+ )
107+ }
108+ </ ul >
109+ )
110+ }
111+
112+ advancedParamsJSX ( ) {
113+ if ( this . state . paramsMode !== 'advanced' ) {
114+ return null ;
115+ }
116+
117+ let classNames = 'flex-grow block px-4 py-1 text-gray-900 border border-gray-300 rounded-lg bg-gray-50 text-base' ;
118+
119+ if ( this . state . textValue ) {
120+ classNames += ' bg-yellow-100' ;
121+ }
122+
123+ return (
124+ < div className = "w-full" >
125+ < div className = "flex items-end" >
126+ < label className = "flex items-center" htmlFor = "advanced" >
127+ Advanced parameters
128+ </ label >
129+
130+ { this . props . blastMethod &&
131+ < button
132+ className = "text-seqblue ml-2"
133+ type = "button"
134+ onClick = { this . showAdvancedOptionsHelp }
135+ data-toggle = "modal" data-target = "#help" >
136+ See available options
137+ < i className = "fa fa-question-circle ml-1 w-3 h-4 fill-current" > </ i >
138+ </ button >
139+ }
140+
141+ { ! this . props . blastMethod &&
142+ < span className = "text-gray-600 ml-2 text-sm hidden sm:block" >
143+ Select databases and fill in the query to see options.
144+ </ span >
145+ }
146+ </ div >
147+
148+ < div className = 'flex-grow flex w-full' >
149+ < input type = "text" className = { classNames }
150+ onChange = { e => this . onTextValueChanged ( e . target . value ) }
151+ id = "advanced"
152+ name = "advanced"
153+ value = { this . state . textValue }
154+ placeholder = "eg: -evalue 1.0e-5 -num_alignments 100"
155+ title = "View, and enter advanced parameters."
156+ />
157+ </ div >
158+ < div className = "text-sm text-gray-600 mt-2" >
159+ Options as they would appear in a command line when calling BLAST eg: < i > -evalue 1.0e-5 -num_alignments 100</ i >
160+ </ div >
161+ </ div >
162+ )
163+ }
164+
165+ showAdvancedOptionsHelp ( e ) {
44166 const ids = [ 'blastn' , 'tblastn' , 'blastp' , 'blastx' , 'tblastx' ] ;
45- const method = this . state . method . toLowerCase ( ) ;
167+ const method = this . props . blastMethod . toLowerCase ( ) ;
46168 // hide options for other algorithms and only show for selected algorithm
47169 for ( const id of ids ) {
48170 if ( id === method ) {
@@ -53,33 +175,13 @@ export class Options extends Component {
53175 }
54176 document . querySelector ( '[data-help-modal]' ) . classList . remove ( 'hidden' )
55177 }
178+
56179 render ( ) {
57- var classNames = 'flex-grow block px-4 py-1 text-gray-900 border border-gray-300 rounded-lg bg-gray-50 text-base' ;
58- if ( this . state . value . trim ( ) ) {
59- classNames += ' bg-yellow-100' ;
60- }
61180 return (
62- < div className = "flex-grow flex flex-col sm:flex-row items-start sm:items-center" >
63- < label className = "flex items-center mx-2" htmlFor = "advanced" >
64- Advanced parameters:
65- { /* only show link to advanced parameters if blast method is known */ }
66- { this . state . method && < sup className = "mx-1 text-seqblue" >
67- < a href = ''
68- onClick = { this . showAdvancedOptions }
69- data-toggle = "modal" data-target = "#help" >
70- < i className = "fa fa-question-circle w-3 h-4 fill-current" > </ i >
71- </ a >
72- </ sup > }
73- </ label >
74- < div className = 'flex-grow flex w-full sm:w-auto' >
75- < input type = "text" className = { classNames }
76- onChange = { e => this . updateBox ( e . target . value ) }
77- id = "advanced" name = "advanced" value = { this . state . value }
78- placeholder = "eg: -evalue 1.0e-5 -num_alignments 100"
79- title = "View, and enter advanced parameters."
80- />
81- { Object . keys ( this . state . preOpts ) . length > 1 && this . optionsJSX ( ) }
82- </ div >
181+ < div className = "flex-grow flex flex-col items-start sm:items-center space-y-4" >
182+ { this . optionsPresetsJSX ( ) }
183+
184+ { this . advancedParamsJSX ( ) }
83185 </ div >
84186 ) ;
85187 }
0 commit comments