2017-02-09 18:06:44 +00:00
import '../css/EditTaskForm.scss' ;
import React from 'react' ;
import Utils from '../classes/Utils' ;
2017-07-24 16:39:12 +00:00
import EditPresetDialog from './EditPresetDialog' ;
2017-07-25 16:37:42 +00:00
import ErrorMessage from './ErrorMessage' ;
2017-07-25 18:09:51 +00:00
import PropTypes from 'prop-types' ;
2017-07-25 19:54:31 +00:00
import Storage from '../classes/Storage' ;
2023-02-22 17:59:01 +00:00
import TagsField from './TagsField' ;
2017-07-25 16:37:42 +00:00
import $ from 'jquery' ;
2020-12-16 19:37:35 +00:00
import { _ , interpolate } from '../classes/gettext' ;
2017-02-09 18:06:44 +00:00
class EditTaskForm extends React . Component {
static defaultProps = {
2017-02-10 16:29:59 +00:00
selectedNode : null ,
2018-12-31 21:50:51 +00:00
task : null ,
onFormChanged : ( ) => { } ,
2019-06-26 14:20:22 +00:00
inReview : false
2017-02-09 18:06:44 +00:00
} ;
static propTypes = {
2017-07-25 18:09:51 +00:00
selectedNode : PropTypes . oneOfType ( [
PropTypes . string ,
PropTypes . number
2017-02-09 18:06:44 +00:00
] ) ,
2017-07-25 18:09:51 +00:00
onFormLoaded : PropTypes . func ,
2018-12-31 21:50:51 +00:00
onFormChanged : PropTypes . func ,
2019-06-26 14:20:22 +00:00
inReview : PropTypes . bool ,
2019-08-29 02:16:39 +00:00
task : PropTypes . object ,
2020-12-15 20:56:00 +00:00
suggestedTaskName : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . func ] )
2017-02-09 18:06:44 +00:00
} ;
constructor ( props ) {
super ( props ) ;
this . state = {
error : "" ,
2017-07-25 16:37:42 +00:00
presetError : "" ,
presetActionPerforming : false ,
2020-12-15 20:56:00 +00:00
namePlaceholder : typeof props . suggestedTaskName === "string" ? props . suggestedTaskName : ( props . task !== null ? ( props . task . name || "" ) : "Task of " + ( new Date ( ) ) . toISOString ( ) ) ,
name : typeof props . suggestedTaskName === "string" ? props . suggestedTaskName : ( props . task !== null ? ( props . task . name || "" ) : "" ) ,
2017-02-09 18:06:44 +00:00
loadedProcessingNodes : false ,
2017-07-24 16:39:12 +00:00
loadedPresets : false ,
2017-02-09 18:06:44 +00:00
selectedNode : null ,
2017-07-21 20:48:01 +00:00
processingNodes : [ ] ,
2017-07-24 16:39:12 +00:00
selectedPreset : null ,
2017-07-24 20:59:57 +00:00
presets : [ ] ,
2023-03-09 18:07:49 +00:00
tags : props . task !== null ? Utils . clone ( props . task . tags ) : [ ] ,
2017-07-24 20:59:57 +00:00
2020-12-15 20:56:00 +00:00
editingPreset : false ,
2023-02-22 17:59:01 +00:00
loadingTaskName : false ,
2023-03-09 18:07:49 +00:00
showTagsField : props . task !== null ? ! ! props . task . tags . length : false
2017-02-09 18:06:44 +00:00
} ;
this . handleNameChange = this . handleNameChange . bind ( this ) ;
this . handleSelectNode = this . handleSelectNode . bind ( this ) ;
2022-10-18 18:34:47 +00:00
this . firstEnabledNode = this . firstEnabledNode . bind ( this ) ;
2017-02-09 18:06:44 +00:00
this . loadProcessingNodes = this . loadProcessingNodes . bind ( this ) ;
2017-07-24 16:39:12 +00:00
this . retryLoad = this . retryLoad . bind ( this ) ;
2017-02-09 18:06:44 +00:00
this . selectNodeByKey = this . selectNodeByKey . bind ( this ) ;
this . getTaskInfo = this . getTaskInfo . bind ( this ) ;
2017-07-24 16:39:12 +00:00
this . notifyFormLoaded = this . notifyFormLoaded . bind ( this ) ;
this . loadPresets = this . loadPresets . bind ( this ) ;
this . handleSelectPreset = this . handleSelectPreset . bind ( this ) ;
this . selectPresetById = this . selectPresetById . bind ( this ) ;
this . handleEditPreset = this . handleEditPreset . bind ( this ) ;
2017-07-24 20:59:57 +00:00
this . handleCancelEditPreset = this . handleCancelEditPreset . bind ( this ) ;
2017-07-25 16:37:42 +00:00
this . handlePresetSave = this . handlePresetSave . bind ( this ) ;
this . handleDuplicateSavePreset = this . handleDuplicateSavePreset . bind ( this ) ;
this . handleDeletePreset = this . handleDeletePreset . bind ( this ) ;
this . findFirstPresetMatching = this . findFirstPresetMatching . bind ( this ) ;
this . getAvailableOptionsOnly = this . getAvailableOptionsOnly . bind ( this ) ;
2017-07-25 17:54:41 +00:00
this . getAvailableOptionsOnlyText = this . getAvailableOptionsOnlyText . bind ( this ) ;
2017-07-25 19:54:31 +00:00
this . saveLastPresetToStorage = this . saveLastPresetToStorage . bind ( this ) ;
2018-12-31 21:50:51 +00:00
this . formReady = this . formReady . bind ( this ) ;
}
formReady ( ) {
return this . state . loadedProcessingNodes &&
this . state . selectedNode &&
this . state . loadedPresets &&
this . state . selectedPreset ;
2017-07-24 16:39:12 +00:00
}
2023-09-15 17:11:48 +00:00
checkFilesCount ( filesCount ) {
2023-09-16 16:23:49 +00:00
if ( ! this . state . selectedNode ) return true ;
2023-09-15 17:11:48 +00:00
if ( filesCount === 0 ) return true ;
if ( this . state . selectedNode . max _images === null ) return true ;
return this . state . selectedNode . max _images >= filesCount ;
}
selectedNodeMaxImages ( ) {
if ( ! this . state . selectedNode ) return null ;
return this . state . selectedNode . max _images ;
}
2017-07-24 16:39:12 +00:00
notifyFormLoaded ( ) {
2018-12-31 21:50:51 +00:00
if ( this . props . onFormLoaded && this . formReady ( ) ) this . props . onFormLoaded ( ) ;
2017-02-09 18:06:44 +00:00
}
2022-10-18 18:34:47 +00:00
firstEnabledNode ( ) {
for ( let i = 0 ; i < this . state . processingNodes . length ; i ++ ) {
if ( this . state . processingNodes [ i ] . enabled ) return this . state . processingNodes [ i ] ;
}
return null ;
}
2017-02-09 18:06:44 +00:00
loadProcessingNodes ( ) {
2018-01-18 18:03:02 +00:00
const failed = ( ) => {
2020-12-16 19:37:35 +00:00
this . setState ( { error : _ ( "Could not load list of processing nodes. Are you connected to the internet?" ) } ) ;
2017-02-09 18:06:44 +00:00
}
this . nodesRequest =
$ . getJSON ( "/api/processingnodes/?has_available_options=True" , json => {
if ( Array . isArray ( json ) ) {
// No nodes with options?
const noProcessingNodesError = ( nodes ) => {
2020-12-16 19:37:35 +00:00
var extra = nodes ? _ ( "We tried to reach:" ) + "<ul>" + nodes . map ( n => Utils . html ` <li><a href=" ${ n . url } "> ${ n . label } </a></li> ` ) . join ( "" ) + "</ul>" : "" ;
this . setState ( { error : _ ( "There are no usable processing nodes." ) + extra + _ ( "Make sure that at least one processing node is reachable and that you have granted the current user sufficient permissions to view the processing node (by going to Administration -- Processing Nodes -- Select Node -- Object Permissions -- Add User/Group and check CAN VIEW PROCESSING NODE). If you are bringing a node back online, it will take about 30 seconds for WebODM to recognize it." ) } ) ;
2017-02-15 19:20:41 +00:00
} ;
2017-02-09 18:06:44 +00:00
if ( json . length === 0 ) {
noProcessingNodesError ( ) ;
return ;
}
let nodes = json . map ( node => {
return {
id : node . id ,
key : node . id ,
2019-01-15 14:06:22 +00:00
label : ` ${ node . label } (queue: ${ node . queue _count } ) ` ,
2017-02-09 18:06:44 +00:00
options : node . available _options ,
queue _count : node . queue _count ,
2023-09-15 17:11:48 +00:00
max _images : node . max _images ,
2017-03-06 22:59:00 +00:00
enabled : node . online ,
2017-02-09 18:06:44 +00:00
url : ` http:// ${ node . hostname } : ${ node . port } `
} ;
} ) ;
2022-10-18 18:34:47 +00:00
// Find a node with lowest queue count
let minQueueCount = Math . min ( ... nodes . filter ( node => node . enabled ) . map ( node => node . queue _count ) ) ;
let minQueueCountNodes = nodes . filter ( node => node . enabled && node . queue _count === minQueueCount ) ;
2017-02-09 18:06:44 +00:00
2022-10-18 18:34:47 +00:00
if ( minQueueCountNodes . length === 0 ) {
noProcessingNodesError ( nodes ) ;
return ;
2017-02-15 19:20:41 +00:00
}
2017-02-09 18:06:44 +00:00
2022-10-18 18:34:47 +00:00
// Choose at random
let lowestQueueNode = minQueueCountNodes [ ~ ~ ( Math . random ( ) * minQueueCountNodes . length ) ] ;
2017-02-09 18:06:44 +00:00
this . setState ( {
processingNodes : nodes ,
loadedProcessingNodes : true
} ) ;
// Have we specified a node?
2017-02-10 16:29:59 +00:00
if ( this . props . task && this . props . task . processing _node ) {
2017-02-15 19:20:41 +00:00
if ( this . props . task . auto _processing _node ) {
2022-10-18 18:34:47 +00:00
this . selectNodeByKey ( lowestQueueNode . key ) ;
2017-02-15 19:20:41 +00:00
} else {
this . selectNodeByKey ( this . props . task . processing _node ) ;
}
2019-06-27 15:19:52 +00:00
} else if ( this . props . selectedNode ) {
this . selectNodeByKey ( this . props . selectedNode ) ;
2017-02-09 18:06:44 +00:00
} else {
2022-10-18 18:34:47 +00:00
this . selectNodeByKey ( lowestQueueNode . key ) ;
2017-02-09 18:06:44 +00:00
}
2017-07-24 16:39:12 +00:00
this . notifyFormLoaded ( ) ;
2017-02-09 18:06:44 +00:00
} else {
console . error ( "Got invalid json response for processing nodes" , json ) ;
failed ( ) ;
}
} )
. fail ( ( jqXHR , textStatus , errorThrown ) => {
// I don't expect this to fail, unless it's a development error or connection error.
// in which case we don't need to notify the user directly.
failed ( ) ;
} ) ;
}
2017-07-24 16:39:12 +00:00
retryLoad ( ) {
2017-02-09 18:06:44 +00:00
this . setState ( { error : "" } ) ;
this . loadProcessingNodes ( ) ;
2017-07-24 16:39:12 +00:00
this . loadPresets ( ) ;
}
2017-07-25 16:37:42 +00:00
findFirstPresetMatching ( presets , options ) {
for ( let i = 0 ; i < presets . length ; i ++ ) {
const preset = presets [ i ] ;
if ( options . length === preset . options . length ) {
let dict = { } ;
options . forEach ( opt => {
dict [ opt . name ] = opt . value ;
} ) ;
let matchingOptions = 0 ;
for ( let j = 0 ; j < preset . options . length ; j ++ ) {
if ( dict [ preset . options [ j ] . name ] !== preset . options [ j ] . value ) {
break ;
} else {
matchingOptions ++ ;
}
}
// If we terminated the loop above, all options match
if ( matchingOptions === options . length ) return preset ;
}
}
return null ;
}
2017-07-24 16:39:12 +00:00
loadPresets ( ) {
2018-01-18 18:03:02 +00:00
const failed = ( ) => {
2020-12-16 19:37:35 +00:00
this . setState ( { error : _ ( "Could not load list of presets. Are you connected to the internet?" ) } ) ;
2017-07-24 16:39:12 +00:00
}
this . presetsRequest =
2017-07-25 17:54:41 +00:00
$ . getJSON ( "/api/presets/?ordering=-system,-created_at" , presets => {
2017-07-24 16:39:12 +00:00
if ( Array . isArray ( presets ) ) {
2017-07-25 16:37:42 +00:00
// Add custom preset
const customPreset = {
id : - 1 ,
2020-12-16 19:37:35 +00:00
name : "(" + _ ( "Custom" ) + ")" ,
2017-07-25 16:37:42 +00:00
options : [ ] ,
system : true
} ;
2017-07-25 17:54:41 +00:00
presets . unshift ( customPreset ) ;
2017-07-24 16:39:12 +00:00
// Choose preset
2020-12-16 19:37:35 +00:00
_ ( "Default" ) ; // Add translation
2017-07-24 16:39:12 +00:00
let selectedPreset = presets [ 0 ] ,
defaultPreset = presets . find ( p => p . name === "Default" ) ; // Do not translate Default
if ( defaultPreset ) selectedPreset = defaultPreset ;
2017-07-25 16:37:42 +00:00
// If task's options are set attempt
// to find a preset that matches the current task options
if ( this . props . task && Array . isArray ( this . props . task . options ) && this . props . task . options . length > 0 ) {
const taskPreset = this . findFirstPresetMatching ( presets , this . props . task . options ) ;
if ( taskPreset !== null ) {
selectedPreset = taskPreset ;
} else {
customPreset . options = Utils . clone ( this . props . task . options ) ;
selectedPreset = customPreset ;
}
2017-07-25 19:54:31 +00:00
} else {
// Check local storage for last used preset
const lastPresetId = Storage . getItem ( "last_preset_id" ) ;
if ( lastPresetId !== null ) {
const lastPreset = presets . find ( p => p . id == lastPresetId ) ;
if ( lastPreset ) selectedPreset = lastPreset ;
}
2017-07-25 16:37:42 +00:00
}
2017-07-24 16:39:12 +00:00
this . setState ( {
loadedPresets : true ,
presets : presets ,
selectedPreset : selectedPreset
} ) ;
this . notifyFormLoaded ( ) ;
} else {
console . error ( "Got invalid json response for presets" , json ) ;
failed ( ) ;
}
} )
. fail ( ( jqXHR , textStatus , errorThrown ) => {
// I don't expect this to fail, unless it's a development error or connection error.
// in which case we don't need to notify the user directly.
failed ( ) ;
} ) ;
}
2020-12-15 20:56:00 +00:00
loadSuggestedName = ( ) => {
if ( typeof this . props . suggestedTaskName === "function" ) {
this . setState ( { loadingTaskName : true } ) ;
this . props . suggestedTaskName ( ) . then ( name => {
if ( this . state . loadingTaskName ) {
this . setState ( { loadingTaskName : false , name } ) ;
} else {
// User started typing its own name
}
} ) . catch ( e => {
// Do Nothing
this . setState ( { loadingTaskName : false } ) ;
} )
}
}
2017-07-24 16:39:12 +00:00
handleSelectPreset ( e ) {
this . selectPresetById ( e . target . value ) ;
}
selectPresetById ( id ) {
let preset = this . state . presets . find ( p => p . id === parseInt ( id ) ) ;
if ( preset ) this . setState ( { selectedPreset : preset } ) ;
2017-02-09 18:06:44 +00:00
}
componentDidMount ( ) {
this . loadProcessingNodes ( ) ;
2017-07-24 16:39:12 +00:00
this . loadPresets ( ) ;
2020-12-15 20:56:00 +00:00
this . loadSuggestedName ( ) ;
2017-02-09 18:06:44 +00:00
}
2018-12-31 21:50:51 +00:00
componentDidUpdate ( prevProps , prevState ) {
// Monitor changes of certain form items (user driven)
// and fire event when appropriate
if ( ! this . formReady ( ) ) return ;
let changed = false ;
[ 'name' , 'selectedNode' , 'selectedPreset' ] . forEach ( prop => {
if ( prevState [ prop ] !== this . state [ prop ] ) changed = true ;
} ) ;
if ( changed ) this . props . onFormChanged ( ) ;
}
2017-02-09 18:06:44 +00:00
componentWillUnmount ( ) {
2017-07-24 16:39:12 +00:00
if ( this . nodesRequest ) this . nodesRequest . abort ( ) ;
if ( this . presetsRequest ) this . presetsRequest . abort ( ) ;
2017-02-09 18:06:44 +00:00
}
handleNameChange ( e ) {
2020-12-15 20:56:00 +00:00
this . setState ( { name : e . target . value , loadingTaskName : false } ) ;
2017-02-09 18:06:44 +00:00
}
selectNodeByKey ( key ) {
let node = this . state . processingNodes . find ( node => node . key == key ) ;
if ( node ) this . setState ( { selectedNode : node } ) ;
2019-06-27 15:19:52 +00:00
else {
2022-10-18 18:34:47 +00:00
console . log ( ` Node ${ key } does not exist, selecting first enabled ` ) ;
const n = this . firstEnabledNode ( ) ;
if ( n ) {
this . selectNodeByKey ( n . key ) ;
}
2019-06-27 15:19:52 +00:00
}
2017-02-09 18:06:44 +00:00
}
handleSelectNode ( e ) {
this . selectNodeByKey ( e . target . value ) ;
}
2017-07-25 16:37:42 +00:00
// Filter a list of options based on the ones that
// are available (usually options are from a preset and availableOptions
// from a processing node)
getAvailableOptionsOnly ( options , availableOptions ) {
const optionNames = { } ;
availableOptions . forEach ( opt => optionNames [ opt . name ] = true ) ;
return options . filter ( opt => optionNames [ opt . name ] ) ;
}
2017-07-25 17:54:41 +00:00
getAvailableOptionsOnlyText ( options , availableOptions ) {
const opts = this . getAvailableOptionsOnly ( options , availableOptions ) ;
2019-06-26 14:20:22 +00:00
let res = opts . map ( opt => ` ${ opt . name } : ${ opt . value } ` ) . join ( ", " ) ;
2020-12-16 19:37:35 +00:00
if ( ! res ) res = _ ( "Default" ) ;
2019-06-26 14:20:22 +00:00
return res ;
2017-07-25 17:54:41 +00:00
}
2017-07-25 19:54:31 +00:00
saveLastPresetToStorage ( ) {
if ( this . state . selectedPreset ) {
Storage . setItem ( 'last_preset_id' , this . state . selectedPreset . id ) ;
}
}
2017-02-09 18:06:44 +00:00
getTaskInfo ( ) {
2023-03-07 16:56:17 +00:00
const { name , selectedNode , selectedPreset , tags } = this . state ;
2017-07-25 16:37:42 +00:00
2017-02-09 18:06:44 +00:00
return {
2023-03-09 18:07:49 +00:00
name : name !== "" ? name : this . state . namePlaceholder ,
2017-07-25 16:37:42 +00:00
selectedNode : selectedNode ,
2023-03-07 16:56:17 +00:00
options : this . getAvailableOptionsOnly ( selectedPreset . options , selectedNode . options ) ,
tags
2017-02-09 18:06:44 +00:00
} ;
}
2017-07-24 16:39:12 +00:00
handleEditPreset ( ) {
2017-07-25 16:37:42 +00:00
// If the user tries to edit a system preset
// set the "Custom..." options to it
const { selectedPreset , presets } = this . state ;
if ( selectedPreset . system ) {
let customPreset = presets . find ( p => p . id === - 1 ) ;
// Might have been deleted
if ( ! customPreset ) {
customPreset = {
id : - 1 ,
2020-12-16 19:37:35 +00:00
name : "(" + _ ( "Custom" ) + ")" ,
2017-07-25 16:37:42 +00:00
options : [ ] ,
system : true
} ;
2017-07-25 17:54:41 +00:00
presets . unshift ( customPreset ) ;
2017-07-25 16:37:42 +00:00
this . setState ( { presets } ) ;
}
customPreset . options = Utils . clone ( selectedPreset . options ) ;
this . setState ( { selectedPreset : customPreset } ) ;
}
2017-07-24 20:59:57 +00:00
this . setState ( { editingPreset : true } ) ;
}
handleCancelEditPreset ( ) {
this . setState ( { editingPreset : false } ) ;
2017-02-10 16:29:59 +00:00
}
2017-07-25 16:37:42 +00:00
handlePresetSave ( preset ) {
const done = ( ) => {
// Update presets and selected preset
let p = this . state . presets . find ( p => p . id === preset . id ) ;
p . name = preset . name ;
p . options = preset . options ;
this . setState ( { selectedPreset : p } ) ;
} ;
// If it's a custom preset do not update server-side
if ( preset . id === - 1 ) {
done ( ) ;
return $ . Deferred ( ) . resolve ( ) ;
} else {
return $ . ajax ( {
url : ` /api/presets/ ${ preset . id } / ` ,
contentType : 'application/json' ,
data : JSON . stringify ( {
name : preset . name ,
options : preset . options
} ) ,
dataType : 'json' ,
type : 'PATCH'
} ) . done ( done ) ;
}
}
handleDuplicateSavePreset ( ) {
// Create a new preset with the same settings as the
// currently selected preset
const { selectedPreset , presets } = this . state ;
this . setState ( { presetActionPerforming : true } ) ;
const isCustom = selectedPreset . id === - 1 ,
2020-12-16 19:37:35 +00:00
name = isCustom ? _ ( "My Preset" ) : interpolate ( _ ( "Copy of %(preset)s" ) , { preset : selectedPreset . name } ) ;
2017-07-25 16:37:42 +00:00
$ . ajax ( {
url : ` /api/presets/ ` ,
contentType : 'application/json' ,
data : JSON . stringify ( {
name : name ,
options : selectedPreset . options
} ) ,
dataType : 'json' ,
type : 'POST'
} ) . done ( preset => {
// If the original preset was a custom one,
// we remove it from the list (since we just saved it)
if ( isCustom ) {
presets . splice ( presets . indexOf ( selectedPreset ) , 1 ) ;
}
// Add new preset to list, select it, then edit
presets . push ( preset ) ;
this . setState ( { presets , selectedPreset : preset } ) ;
this . handleEditPreset ( ) ;
} ) . fail ( ( ) => {
2020-12-16 19:37:35 +00:00
this . setState ( { presetError : _ ( "Could not duplicate the preset. Please try to refresh the page." ) } ) ;
2017-07-25 16:37:42 +00:00
} ) . always ( ( ) => {
this . setState ( { presetActionPerforming : false } ) ;
} ) ;
}
handleDeletePreset ( ) {
const { selectedPreset , presets } = this . state ;
if ( selectedPreset . system ) {
2020-12-16 19:37:35 +00:00
this . setState ( { presetError : _ ( "System presets can only be removed by a staff member from the Administration panel." ) } ) ;
2017-07-25 16:37:42 +00:00
return ;
}
2020-12-16 19:37:35 +00:00
if ( window . confirm ( interpolate ( _ ( 'Are you sure you want to delete "%(preset)s"?' ) , { preset : selectedPreset . name } ) ) ) {
2017-07-25 16:37:42 +00:00
this . setState ( { presetActionPerforming : true } ) ;
return $ . ajax ( {
url : ` /api/presets/ ${ selectedPreset . id } / ` ,
contentType : 'application/json' ,
type : 'DELETE'
} ) . done ( ( ) => {
presets . splice ( presets . indexOf ( selectedPreset ) , 1 ) ;
// Select first by default
this . setState ( { presets , selectedPreset : presets [ 0 ] , editingPreset : false } ) ;
} ) . fail ( ( ) => {
2020-12-16 19:37:35 +00:00
this . setState ( { presetError : _ ( "Could not delete the preset. Please try to refresh the page." ) } ) ;
2017-07-25 16:37:42 +00:00
} ) . always ( ( ) => {
this . setState ( { presetActionPerforming : false } ) ;
} ) ;
} else {
return $ . Deferred ( ) . resolve ( ) ;
}
}
2023-02-22 19:51:50 +00:00
toggleTagsField = ( ) => {
if ( ! this . state . showTagsField ) {
setTimeout ( ( ) => {
if ( this . tagsField ) this . tagsField . focus ( ) ;
} , 0 ) ;
}
this . setState ( { showTagsField : ! this . state . showTagsField } ) ;
}
2017-02-09 18:06:44 +00:00
render ( ) {
if ( this . state . error ) {
return ( < div className = "edit-task-panel" >
< div className = "alert alert-warning" >
< div dangerouslySetInnerHTML = { { _ _html : this . state . error } } > < / div >
2017-07-24 16:39:12 +00:00
< button className = "btn btn-sm btn-primary" onClick = { this . retryLoad } >
2020-12-16 19:37:35 +00:00
< i className = "fa fa-rotate-left" > < / i > { _ ( "Retry" ) }
2017-02-09 18:06:44 +00:00
< / button >
< / div >
< / div > ) ;
}
2017-07-24 16:39:12 +00:00
let taskOptions = "" ;
2018-12-31 21:50:51 +00:00
if ( this . formReady ( ) ) {
2017-02-10 16:29:59 +00:00
2019-06-26 14:20:22 +00:00
const optionsSelector = ( < div >
< select
title = { this . getAvailableOptionsOnlyText ( this . state . selectedPreset . options , this . state . selectedNode . options ) }
className = "form-control"
value = { this . state . selectedPreset . id }
onChange = { this . handleSelectPreset } >
{ this . state . presets . map ( preset =>
2020-12-16 19:37:35 +00:00
< option value = { preset . id } key = { preset . id } className = { preset . system ? "system-preset" : "" } > { preset . name === "Default" ? _ ( preset . name ) : preset . name } < / option >
2019-06-26 14:20:22 +00:00
) }
< / select >
{ ! this . state . presetActionPerforming ?
< div className = "btn-group presets-dropdown" >
2023-03-08 17:21:23 +00:00
< button type = "button" className = "btn btn-sm btn-default" title = { _ ( "Edit Task Options" ) } onClick = { this . handleEditPreset } >
2020-12-16 19:37:35 +00:00
< i className = "fa fa-sliders-h" > < / i > { _ ( "Edit" ) }
2019-06-26 14:20:22 +00:00
< / button >
2023-03-08 17:21:23 +00:00
< button type = "button" className = "btn btn-default btn-sm dropdown-toggle" data - toggle = "dropdown" >
2019-06-26 14:20:22 +00:00
< span className = "caret" > < / span >
< / button >
< ul className = "dropdown-menu" >
< li >
2020-12-16 19:37:35 +00:00
< a href = "javascript:void(0);" onClick = { this . handleEditPreset } > < i className = "fa fa-sliders-h" > < / i > { _ ( "Edit" ) } < / a >
2019-06-26 14:20:22 +00:00
< / li >
< li className = "divider" > < / li >
{ this . state . selectedPreset . id !== - 1 ?
< li >
2020-12-16 19:37:35 +00:00
< a href = "javascript:void(0);" onClick = { this . handleDuplicateSavePreset } > < i className = "fa fa-copy" > < / i > { _ ( "Duplicate" ) } < / a >
2019-06-26 14:20:22 +00:00
< / li >
:
< li >
2020-12-16 19:37:35 +00:00
< a href = "javascript:void(0);" onClick = { this . handleDuplicateSavePreset } > < i className = "fa fa-save" > < / i > { _ ( "Save" ) } < / a >
2019-06-26 14:20:22 +00:00
< / li >
}
< li className = { this . state . selectedPreset . system ? "disabled" : "" } >
2020-12-16 19:37:35 +00:00
< a href = "javascript:void(0);" onClick = { this . handleDeletePreset } > < i className = "fa fa-trash" > < / i > { _ ( "Delete" ) } < / a >
2019-06-26 14:20:22 +00:00
< / li >
< / ul >
< / div >
: < i className = "preset-performing-action-icon fa fa-cog fa-spin fa-fw" > < / i > }
< ErrorMessage className = "preset-error" bind = { [ this , 'presetError' ] } / >
< / div > ) ;
2023-02-22 17:59:01 +00:00
let tagsField = "" ;
if ( this . state . showTagsField ) {
tagsField = ( < div className = "form-group" >
< label className = "col-sm-2 control-label" > { _ ( "Tags" ) } < / label >
2023-03-07 16:56:17 +00:00
< div className = "col-sm-10" >
< TagsField onUpdate = { ( tags ) => this . state . tags = tags } tags = { this . state . tags } ref = { domNode => this . tagsField = domNode } / >
2023-02-22 17:59:01 +00:00
< / div >
< / div > ) ;
}
2017-07-24 16:39:12 +00:00
taskOptions = (
2017-02-09 18:06:44 +00:00
< div >
2023-02-22 17:59:01 +00:00
{ tagsField }
2017-02-09 18:06:44 +00:00
< div className = "form-group" >
2020-12-16 19:37:35 +00:00
< label className = "col-sm-2 control-label" > { _ ( "Processing Node" ) } < / label >
2017-02-09 18:06:44 +00:00
< div className = "col-sm-10" >
< select className = "form-control" value = { this . state . selectedNode . key } onChange = { this . handleSelectNode } >
{ this . state . processingNodes . map ( node =>
< option value = { node . key } key = { node . key } disabled = { ! node . enabled } > { node . label } < / option >
) }
< / select >
< / div >
< / div >
2017-07-24 16:39:12 +00:00
< div className = "form-group form-inline" >
2020-12-16 19:37:35 +00:00
< label className = "col-sm-2 control-label" > { _ ( "Options" ) } < / label >
2017-02-09 18:06:44 +00:00
< div className = "col-sm-10" >
2019-06-26 14:20:22 +00:00
{ ! this . props . inReview ? optionsSelector :
< div className = "review-options" >
{ this . getAvailableOptionsOnlyText ( this . state . selectedPreset . options , this . state . selectedNode . options ) }
< / div > }
2017-02-09 18:06:44 +00:00
< / div >
< / div >
2017-07-24 20:59:57 +00:00
{ this . state . editingPreset ?
< EditPresetDialog
preset = { this . state . selectedPreset }
availableOptions = { this . state . selectedNode . options }
onHide = { this . handleCancelEditPreset }
2017-07-25 16:37:42 +00:00
saveAction = { this . handlePresetSave }
deleteAction = { this . handleDeletePreset }
2017-07-24 20:59:57 +00:00
ref = { ( domNode ) => { if ( domNode ) this . editPresetDialog = domNode ; } }
/ >
: "" }
2017-02-09 18:06:44 +00:00
< / div >
) ;
} else {
2017-07-24 16:39:12 +00:00
taskOptions = ( < div className = "form-group" >
2020-12-16 19:37:35 +00:00
< div className = "col-sm-offset-2 col-sm-10" > { _ ( "Loading processing nodes and presets..." ) } < i className = "fa fa-sync fa-spin fa-fw" > < / i > < / div >
2017-02-09 18:06:44 +00:00
< / div > ) ;
}
return (
< div className = "edit-task-form" >
< div className = "form-group" >
2020-12-16 19:37:35 +00:00
< label className = "col-sm-2 control-label" > { _ ( "Name" ) } < / label >
2023-02-22 17:59:01 +00:00
< div className = "col-sm-10 name-fields" >
2020-12-15 20:56:00 +00:00
{ this . state . loadingTaskName ?
< i className = "fa fa-circle-notch fa-spin fa-fw name-loading" > < / i >
: "" }
2017-02-10 16:29:59 +00:00
< input type = "text"
onChange = { this . handleNameChange }
2017-07-24 16:39:12 +00:00
className = "form-control"
2020-12-15 20:56:00 +00:00
placeholder = { this . state . namePlaceholder }
2023-03-07 16:56:17 +00:00
value = { this . state . name }
2017-02-10 16:29:59 +00:00
/ >
2023-02-23 20:13:00 +00:00
< button type = "button" title = { _ ( "Add tags" ) } onClick = { this . toggleTagsField } className = "btn btn-sm btn-secondary toggle-tags" >
< i className = "fa fa-tag" > < / i >
2023-02-22 17:59:01 +00:00
< / button >
2017-02-09 18:06:44 +00:00
< / div >
< / div >
2017-07-24 16:39:12 +00:00
{ taskOptions }
2017-02-09 18:06:44 +00:00
< / div >
) ;
}
}
export default EditTaskForm ;