public/js/options.js in sequenceserver-3.0.1 vs public/js/options.js in sequenceserver-3.1.0
- old
+ new
@@ -1,83 +1,188 @@
import React, { Component } from 'react';
// Component for the advanced params input field.
export class Options extends Component {
constructor(props) {
super(props);
- this.state = { preOpts: {}, value: '', method: '' };
- this.updateBox = this.updateBox.bind(this);
- this.optionsJSX = this.optionsJSX.bind(this);
- this.showAdvancedOptions = this.showAdvancedOptions.bind(this);
+
+ this.state = {
+ textValue: '',
+ objectValue: this.defaultObjectValue(),
+ paramsMode: 'advanced'
+ };
+
+ this.onTextValueChanged = this.onTextValueChanged.bind(this);
+ this.optionsPresetsJSX = this.optionsPresetsJSX.bind(this);
+ this.advancedParamsJSX = this.advancedParamsJSX.bind(this);
+ this.showAdvancedOptionsHelp = this.showAdvancedOptionsHelp.bind(this);
}
- updateBox(value) {
- this.setState({ value: value });
+
+ defaultObjectValue() {
+ return {
+ max_target_seqs: '',
+ evalue: '',
+ task: ''
+ };
+ };
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.predefinedOptions !== this.props.predefinedOptions) {
+ let defaultOptions = this.props.predefinedOptions.default || {attributes: []};
+ let advancedOptions = this.props.predefinedOptions['last search'] || defaultOptions || {attributes: []};
+ let initialTextValue = advancedOptions.attributes.join(' ').trim();
+ let parsedOptions = this.parsedOptions(initialTextValue);
+ this.setState({ textValue: initialTextValue, objectValue: parsedOptions});
+ }
}
+ onTextValueChanged(textValue) {
+ let parsedOptions = this.parsedOptions(textValue.toString());
- optionsJSX() {
- return <span className="input-group-btn dropdown">
- <button className="btn bnt-sm btn-default dropdown-toggle"
- data-toggle="dropdown">
- <i className="fa fa-caret-down"></i>
- </button>
- <ul id='advanced-params-dropdown'
- className="dropdown-menu dropdown-menu-right">
+ this.setState({
+ textValue: textValue.toString(),
+ objectValue: parsedOptions
+ });
+ }
+
+ parsedOptions(textValue) {
+ const words = textValue.split(" ");
+ let parsedOptions = this.defaultObjectValue();
+ // Iterate through the words in steps of 2, treating each pair as an option and its potential value
+ for (let i = 0; i < words.length; i += 2) {
+ // Ensure there is a pair available
+ if (words[i]) {
+ if (words[i].startsWith("-")) {
+ const optionName = words[i].substring(1).trim();
+
+ if (words[i + 1]) {
+ // Use the second word as the value for this option
+ parsedOptions[optionName] = words[i + 1];
+ } else {
+ // No value found for this option, set it to null or a default value
+ parsedOptions[optionName] = null;
+ }
+ }
+ }
+ }
+
+ return parsedOptions;
+ }
+
+ optionsPresetsJSX() {
+ return (
+ <div id="options-presets" className="w-full">
+ { Object.keys(this.props.predefinedOptions).length > 1 && <>
+ <h3 className="w-full font-medium border-b border-seqorange mb-2">Settings</h3>
+
+ <p className="text-sm">Choose a predefined setting or customize BLAST parameters.</p>
+ {this.presetListJSX()}
+ </>}
+ </div>
+ );
+ }
+
+ presetListJSX() {
+ return (
+ <ul className="text-sm my-1">
{
- Object.entries(this.state.preOpts).map(
- ([key, value], index) => {
- value = value.join(' ');
- if (value.trim() === this.state.value.trim())
- var className = 'yellow-background';
- return <li key={index} className={className}
- onClick={() => this.updateBox(value)}>
- <strong>{key}:</strong> {value}
- </li>;
+ Object.entries(this.props.predefinedOptions).map(
+ ([key, config], index) => {
+ let textValue = config.attributes.join(' ').trim();
+ let description = config.description || textValue;
+
+ return (
+ <label key={index} className={`block w-full px-2 py-1 hover:bg-gray-200 cursor-pointer`}>
+ <input
+ type="radio"
+ name="predefinedOption"
+ value={textValue}
+ checked={textValue === this.state.textValue}
+ onChange={() => this.onTextValueChanged(textValue)}
+ />
+ <strong className="ml-2">{key}:</strong> {description}
+ </label>
+ );
}
)
}
</ul>
- </span>;
+ )
}
- showAdvancedOptions(e) {
+
+ advancedParamsJSX() {
+ if (this.state.paramsMode !== 'advanced') {
+ return null;
+ }
+
+ let classNames = 'flex-grow block px-4 py-1 text-gray-900 border border-gray-300 rounded-lg bg-gray-50 text-base';
+
+ if (this.state.textValue) {
+ classNames += ' bg-yellow-100';
+ }
+
+ return(
+ <div className="w-full">
+ <div className="flex items-end">
+ <label className="flex items-center" htmlFor="advanced">
+ Advanced parameters
+ </label>
+
+ {this.props.blastMethod &&
+ <button
+ className="text-seqblue ml-2"
+ type="button"
+ onClick={this.showAdvancedOptionsHelp}
+ data-toggle="modal" data-target="#help">
+ See available options
+ <i className="fa fa-question-circle ml-1 w-3 h-4 fill-current"></i>
+ </button>
+ }
+
+ {!this.props.blastMethod &&
+ <span className="text-gray-600 ml-2 text-sm hidden sm:block">
+ Select databases and fill in the query to see options.
+ </span>
+ }
+ </div>
+
+ <div className='flex-grow flex w-full'>
+ <input type="text" className={classNames}
+ onChange={e => this.onTextValueChanged(e.target.value)}
+ id="advanced"
+ name="advanced"
+ value={this.state.textValue}
+ placeholder="eg: -evalue 1.0e-5 -num_alignments 100"
+ title="View, and enter advanced parameters."
+ />
+ </div>
+ <div className="text-sm text-gray-600 mt-2">
+ Options as they would appear in a command line when calling BLAST eg: <i>-evalue 1.0e-5 -num_alignments 100</i>
+ </div>
+ </div>
+ )
+ }
+
+ showAdvancedOptionsHelp(e) {
const ids = ['blastn', 'tblastn', 'blastp', 'blastx', 'tblastx'];
- const method = this.state.method.toLowerCase();
+ const method = this.props.blastMethod.toLowerCase();
// hide options for other algorithms and only show for selected algorithm
for (const id of ids) {
- $(`#${id}`)[id === method ? 'show' : 'hide']();
+ if (id === method) {
+ document.getElementById(id).classList.remove('hidden')
+ } else {
+ document.getElementById(id).classList.add('hidden');
+ }
}
+ document.querySelector('[data-help-modal]').classList.remove('hidden')
}
+
render() {
- var classNames = 'form-control';
- if (this.state.value.trim()) {
- classNames += ' yellow-background';
- }
return (
- <div className="col-md-7">
- <div className="form-group">
- <div className="col-md-12">
- <div className="input-group">
- <label className="control-label" htmlFor="advanced">
- Advanced parameters:
- {/* only show link to advanced parameters if blast method is known */}
- {this.state.method && <sup style={{ marginLeft: '2px' }}>
- <a href=''
- onClick={this.showAdvancedOptions}
- data-toggle="modal" data-target="#help">
- <i className="fa fa-question-circle"></i>
- </a>
- </sup>}
- </label>
- <input type="text" className={classNames}
- onChange={e => this.updateBox(e.target.value)}
- id="advanced" name="advanced" value={this.state.value}
- placeholder="eg: -evalue 1.0e-5 -num_alignments 100"
- title="View, and enter advanced parameters."
- />
- {Object.keys(this.state.preOpts).length > 1 && this.optionsJSX()}
- </div>
- </div>
- </div>
+ <div className="flex-grow flex flex-col items-start sm:items-center space-y-4">
+ {this.optionsPresetsJSX()}
+
+ {this.advancedParamsJSX()}
</div>
);
}
}