kopia lustrzana https://github.com/OpenDroneMap/WebODM
EditTaskForm steps state and style
rodzic
ebce3e9329
commit
32ffd09908
|
@ -14,23 +14,23 @@ class EditTaskForm extends React.Component {
|
|||
static defaultProps = {
|
||||
selectedNode: null,
|
||||
task: null,
|
||||
onFormChanged: () => {},
|
||||
inReview: false
|
||||
onFormChanged: () => { },
|
||||
inReview: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
selectedNode: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]),
|
||||
onFormLoaded: PropTypes.func,
|
||||
onFormChanged: PropTypes.func,
|
||||
inReview: PropTypes.bool,
|
||||
task: PropTypes.object,
|
||||
suggestedTaskName: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
|
||||
selectedNode: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number
|
||||
]),
|
||||
onFormLoaded: PropTypes.func,
|
||||
onFormChanged: PropTypes.func,
|
||||
inReview: PropTypes.bool,
|
||||
task: PropTypes.object,
|
||||
suggestedTaskName: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
|
||||
};
|
||||
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -48,6 +48,9 @@ class EditTaskForm extends React.Component {
|
|||
presets: [],
|
||||
tags: props.task !== null ? Utils.clone(props.task.tags) : [],
|
||||
|
||||
steps: ["settingsStep", "aiStep", "loadingStep"],
|
||||
isPopupOpen: false,
|
||||
|
||||
editingPreset: false,
|
||||
|
||||
loadingTaskName: false,
|
||||
|
@ -78,51 +81,51 @@ class EditTaskForm extends React.Component {
|
|||
this.formReady = this.formReady.bind(this);
|
||||
}
|
||||
|
||||
formReady(){
|
||||
return this.state.loadedProcessingNodes &&
|
||||
this.state.selectedNode &&
|
||||
this.state.loadedPresets &&
|
||||
this.state.selectedPreset;
|
||||
formReady() {
|
||||
return this.state.loadedProcessingNodes &&
|
||||
this.state.selectedNode &&
|
||||
this.state.loadedPresets &&
|
||||
this.state.selectedPreset;
|
||||
}
|
||||
|
||||
checkFilesCount(filesCount){
|
||||
checkFilesCount(filesCount) {
|
||||
if (!this.state.selectedNode) return true;
|
||||
if (filesCount === 0) return true;
|
||||
if (this.state.selectedNode.max_images === null) return true;
|
||||
return this.state.selectedNode.max_images >= filesCount;
|
||||
}
|
||||
|
||||
selectedNodeMaxImages(){
|
||||
selectedNodeMaxImages() {
|
||||
if (!this.state.selectedNode) return null;
|
||||
return this.state.selectedNode.max_images;
|
||||
}
|
||||
|
||||
notifyFormLoaded(){
|
||||
notifyFormLoaded() {
|
||||
if (this.props.onFormLoaded && this.formReady()) this.props.onFormLoaded();
|
||||
}
|
||||
|
||||
firstEnabledNode(){
|
||||
for (let i = 0; i < this.state.processingNodes.length; i++){
|
||||
if (this.state.processingNodes[i].enabled) return this.state.processingNodes[i];
|
||||
}
|
||||
return null;
|
||||
firstEnabledNode() {
|
||||
for (let i = 0; i < this.state.processingNodes.length; i++) {
|
||||
if (this.state.processingNodes[i].enabled) return this.state.processingNodes[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
loadProcessingNodes(){
|
||||
loadProcessingNodes() {
|
||||
const failed = () => {
|
||||
this.setState({error: _("Could not load list of processing nodes. Are you connected to the internet?")});
|
||||
this.setState({ error: _("Could not load list of processing nodes. Are you connected to the internet?") });
|
||||
}
|
||||
|
||||
this.nodesRequest =
|
||||
this.nodesRequest =
|
||||
$.getJSON("/api/processingnodes/?has_available_options=True", json => {
|
||||
if (Array.isArray(json)){
|
||||
if (Array.isArray(json)) {
|
||||
// No nodes with options?
|
||||
const noProcessingNodesError = (nodes) => {
|
||||
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.")});
|
||||
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.") });
|
||||
};
|
||||
|
||||
if (json.length === 0){
|
||||
if (json.length === 0) {
|
||||
noProcessingNodesError();
|
||||
return;
|
||||
}
|
||||
|
@ -144,66 +147,66 @@ class EditTaskForm extends React.Component {
|
|||
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);
|
||||
|
||||
if (minQueueCountNodes.length === 0){
|
||||
if (minQueueCountNodes.length === 0) {
|
||||
noProcessingNodesError(nodes);
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose at random
|
||||
let lowestQueueNode = minQueueCountNodes[~~(Math.random() * minQueueCountNodes.length)];
|
||||
|
||||
|
||||
this.setState({
|
||||
processingNodes: nodes,
|
||||
loadedProcessingNodes: true
|
||||
});
|
||||
|
||||
// Have we specified a node?
|
||||
if (this.props.task && this.props.task.processing_node){
|
||||
if (this.props.task.auto_processing_node){
|
||||
if (this.props.task && this.props.task.processing_node) {
|
||||
if (this.props.task.auto_processing_node) {
|
||||
this.selectNodeByKey(lowestQueueNode.key);
|
||||
}else{
|
||||
} else {
|
||||
this.selectNodeByKey(this.props.task.processing_node);
|
||||
}
|
||||
}else if (this.props.selectedNode){
|
||||
} else if (this.props.selectedNode) {
|
||||
this.selectNodeByKey(this.props.selectedNode);
|
||||
}else{
|
||||
} else {
|
||||
this.selectNodeByKey(lowestQueueNode.key);
|
||||
}
|
||||
|
||||
this.notifyFormLoaded();
|
||||
}else{
|
||||
} 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();
|
||||
});
|
||||
.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();
|
||||
});
|
||||
}
|
||||
|
||||
retryLoad(){
|
||||
this.setState({error: ""});
|
||||
retryLoad() {
|
||||
this.setState({ error: "" });
|
||||
this.loadProcessingNodes();
|
||||
this.loadPresets();
|
||||
}
|
||||
|
||||
findFirstPresetMatching(presets, options){
|
||||
for (let i = 0; i < presets.length; i++){
|
||||
findFirstPresetMatching(presets, options) {
|
||||
for (let i = 0; i < presets.length; i++) {
|
||||
const preset = presets[i];
|
||||
|
||||
if (options.length === preset.options.length){
|
||||
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){
|
||||
for (let j = 0; j < preset.options.length; j++) {
|
||||
if (dict[preset.options[j].name] !== preset.options[j].value) {
|
||||
break;
|
||||
}else{
|
||||
} else {
|
||||
matchingOptions++;
|
||||
}
|
||||
}
|
||||
|
@ -216,14 +219,14 @@ class EditTaskForm extends React.Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
loadPresets(){
|
||||
loadPresets() {
|
||||
const failed = () => {
|
||||
this.setState({error: _("Could not load list of presets. Are you connected to the internet?")});
|
||||
this.setState({ error: _("Could not load list of presets. Are you connected to the internet?") });
|
||||
}
|
||||
|
||||
this.presetsRequest =
|
||||
this.presetsRequest =
|
||||
$.getJSON("/api/presets/?ordering=-system,-created_at", presets => {
|
||||
if (Array.isArray(presets)){
|
||||
if (Array.isArray(presets)) {
|
||||
// Add custom preset
|
||||
const customPreset = {
|
||||
id: -1,
|
||||
|
@ -236,139 +239,139 @@ class EditTaskForm extends React.Component {
|
|||
// Choose preset
|
||||
_("Default"); // Add translation
|
||||
let selectedPreset = presets[0],
|
||||
defaultPreset = presets.find(p => p.name === "Default"); // Do not translate Default
|
||||
defaultPreset = presets.find(p => p.name === "Default"); // Do not translate Default
|
||||
if (defaultPreset) selectedPreset = defaultPreset;
|
||||
|
||||
|
||||
// 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){
|
||||
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){
|
||||
if (taskPreset !== null) {
|
||||
selectedPreset = taskPreset;
|
||||
}else{
|
||||
} else {
|
||||
customPreset.options = Utils.clone(this.props.task.options);
|
||||
selectedPreset = customPreset;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
// Check local storage for last used preset
|
||||
const lastPresetId = Storage.getItem("last_preset_id");
|
||||
if (lastPresetId !== null){
|
||||
if (lastPresetId !== null) {
|
||||
const lastPreset = presets.find(p => p.id == lastPresetId);
|
||||
if (lastPreset) selectedPreset = lastPreset;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
loadedPresets: true,
|
||||
presets: presets,
|
||||
loadedPresets: true,
|
||||
presets: presets,
|
||||
selectedPreset: selectedPreset
|
||||
});
|
||||
this.notifyFormLoaded();
|
||||
}else{
|
||||
} 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();
|
||||
});
|
||||
.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();
|
||||
});
|
||||
}
|
||||
|
||||
loadSuggestedName = () => {
|
||||
if (typeof this.props.suggestedTaskName === "function"){
|
||||
this.setState({loadingTaskName: true});
|
||||
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});
|
||||
})
|
||||
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 });
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSelectPreset(e){
|
||||
handleSelectPreset(e) {
|
||||
this.selectPresetById(e.target.value);
|
||||
}
|
||||
|
||||
selectPresetById(id){
|
||||
selectPresetById(id) {
|
||||
let preset = this.state.presets.find(p => p.id === parseInt(id));
|
||||
if (preset) this.setState({selectedPreset: preset});
|
||||
if (preset) this.setState({ selectedPreset: preset });
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
componentDidMount() {
|
||||
this.loadProcessingNodes();
|
||||
this.loadPresets();
|
||||
this.loadSuggestedName();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState){
|
||||
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 (prevState[prop] !== this.state[prop]) changed = true;
|
||||
});
|
||||
if (changed) this.props.onFormChanged();
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
if (this.nodesRequest) this.nodesRequest.abort();
|
||||
if (this.presetsRequest) this.presetsRequest.abort();
|
||||
componentWillUnmount() {
|
||||
if (this.nodesRequest) this.nodesRequest.abort();
|
||||
if (this.presetsRequest) this.presetsRequest.abort();
|
||||
}
|
||||
|
||||
handleNameChange(e){
|
||||
this.setState({name: e.target.value, loadingTaskName: false});
|
||||
handleNameChange(e) {
|
||||
this.setState({ name: e.target.value, loadingTaskName: false });
|
||||
}
|
||||
|
||||
selectNodeByKey(key){
|
||||
selectNodeByKey(key) {
|
||||
let node = this.state.processingNodes.find(node => node.key == key);
|
||||
if (node) this.setState({selectedNode: node});
|
||||
else{
|
||||
console.log(`Node ${key} does not exist, selecting first enabled`);
|
||||
const n = this.firstEnabledNode();
|
||||
if (n){
|
||||
this.selectNodeByKey(n.key);
|
||||
}
|
||||
if (node) this.setState({ selectedNode: node });
|
||||
else {
|
||||
console.log(`Node ${key} does not exist, selecting first enabled`);
|
||||
const n = this.firstEnabledNode();
|
||||
if (n) {
|
||||
this.selectNodeByKey(n.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleSelectNode(e){
|
||||
handleSelectNode(e) {
|
||||
this.selectNodeByKey(e.target.value);
|
||||
}
|
||||
|
||||
// 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){
|
||||
getAvailableOptionsOnly(options, availableOptions) {
|
||||
const optionNames = {};
|
||||
|
||||
availableOptions.forEach(opt => optionNames[opt.name] = true);
|
||||
return options.filter(opt => optionNames[opt.name]);
|
||||
}
|
||||
|
||||
getAvailableOptionsOnlyText(options, availableOptions){
|
||||
getAvailableOptionsOnlyText(options, availableOptions) {
|
||||
const opts = this.getAvailableOptionsOnly(options, availableOptions);
|
||||
let res = opts.map(opt => `${opt.name}:${opt.value}`).join(", ");
|
||||
if (!res) res = _("Default");
|
||||
return res;
|
||||
}
|
||||
|
||||
saveLastPresetToStorage(){
|
||||
if (this.state.selectedPreset){
|
||||
saveLastPresetToStorage() {
|
||||
if (this.state.selectedPreset) {
|
||||
Storage.setItem('last_preset_id', this.state.selectedPreset.id);
|
||||
}
|
||||
}
|
||||
|
||||
getTaskInfo(){
|
||||
getTaskInfo() {
|
||||
const { name, selectedNode, selectedPreset, tags } = this.state;
|
||||
|
||||
return {
|
||||
|
@ -379,15 +382,15 @@ class EditTaskForm extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
handleEditPreset(){
|
||||
handleEditPreset() {
|
||||
// If the user tries to edit a system preset
|
||||
// set the "Custom..." options to it
|
||||
const { selectedPreset, presets } = this.state;
|
||||
|
||||
if (selectedPreset.system){
|
||||
if (selectedPreset.system) {
|
||||
let customPreset = presets.find(p => p.id === -1);
|
||||
// Might have been deleted
|
||||
if (!customPreset){
|
||||
if (!customPreset) {
|
||||
customPreset = {
|
||||
id: -1,
|
||||
name: "(" + _("Custom") + ")",
|
||||
|
@ -395,34 +398,34 @@ class EditTaskForm extends React.Component {
|
|||
system: true
|
||||
};
|
||||
presets.unshift(customPreset);
|
||||
this.setState({presets});
|
||||
this.setState({ presets });
|
||||
}
|
||||
customPreset.options = Utils.clone(selectedPreset.options);
|
||||
this.setState({selectedPreset: customPreset});
|
||||
this.setState({ selectedPreset: customPreset });
|
||||
}
|
||||
|
||||
this.setState({editingPreset: true});
|
||||
this.setState({ editingPreset: true });
|
||||
}
|
||||
|
||||
handleCancelEditPreset(){
|
||||
this.setState({editingPreset: false});
|
||||
handleCancelEditPreset() {
|
||||
this.setState({ editingPreset: false });
|
||||
}
|
||||
|
||||
handlePresetSave(preset){
|
||||
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});
|
||||
this.setState({ selectedPreset: p });
|
||||
};
|
||||
|
||||
// If it's a custom preset do not update server-side
|
||||
if (preset.id === -1){
|
||||
if (preset.id === -1) {
|
||||
done();
|
||||
return $.Deferred().resolve();
|
||||
}else{
|
||||
} else {
|
||||
return $.ajax({
|
||||
url: `/api/presets/${preset.id}/`,
|
||||
contentType: 'application/json',
|
||||
|
@ -436,14 +439,14 @@ class EditTaskForm extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleDuplicateSavePreset(){
|
||||
handleDuplicateSavePreset() {
|
||||
// Create a new preset with the same settings as the
|
||||
// currently selected preset
|
||||
const { selectedPreset, presets } = this.state;
|
||||
this.setState({presetActionPerforming: true});
|
||||
this.setState({ presetActionPerforming: true });
|
||||
|
||||
const isCustom = selectedPreset.id === -1,
|
||||
name = isCustom ? _("My Preset") : interpolate(_("Copy of %(preset)s"), {preset: selectedPreset.name});
|
||||
name = isCustom ? _("My Preset") : interpolate(_("Copy of %(preset)s"), { preset: selectedPreset.name });
|
||||
|
||||
$.ajax({
|
||||
url: `/api/presets/`,
|
||||
|
@ -457,30 +460,30 @@ class EditTaskForm extends React.Component {
|
|||
}).done(preset => {
|
||||
// If the original preset was a custom one,
|
||||
// we remove it from the list (since we just saved it)
|
||||
if (isCustom){
|
||||
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.setState({ presets, selectedPreset: preset });
|
||||
this.handleEditPreset();
|
||||
}).fail(() => {
|
||||
this.setState({presetError: _("Could not duplicate the preset. Please try to refresh the page.")});
|
||||
this.setState({ presetError: _("Could not duplicate the preset. Please try to refresh the page.") });
|
||||
}).always(() => {
|
||||
this.setState({presetActionPerforming: false});
|
||||
this.setState({ presetActionPerforming: false });
|
||||
});
|
||||
}
|
||||
|
||||
handleDeletePreset(){
|
||||
handleDeletePreset() {
|
||||
const { selectedPreset, presets } = this.state;
|
||||
if (selectedPreset.system){
|
||||
this.setState({presetError: _("System presets can only be removed by a staff member from the Administration panel.")});
|
||||
if (selectedPreset.system) {
|
||||
this.setState({ presetError: _("System presets can only be removed by a staff member from the Administration panel.") });
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.confirm(interpolate(_('Are you sure you want to delete "%(preset)s"?'), { preset: selectedPreset.name}))){
|
||||
this.setState({presetActionPerforming: true});
|
||||
if (window.confirm(interpolate(_('Are you sure you want to delete "%(preset)s"?'), { preset: selectedPreset.name }))) {
|
||||
this.setState({ presetActionPerforming: true });
|
||||
|
||||
return $.ajax({
|
||||
url: `/api/presets/${selectedPreset.id}/`,
|
||||
|
@ -490,97 +493,98 @@ class EditTaskForm extends React.Component {
|
|||
presets.splice(presets.indexOf(selectedPreset), 1);
|
||||
|
||||
// Select first by default
|
||||
this.setState({presets, selectedPreset: presets[0], editingPreset: false});
|
||||
this.setState({ presets, selectedPreset: presets[0], editingPreset: false });
|
||||
}).fail(() => {
|
||||
this.setState({presetError: _("Could not delete the preset. Please try to refresh the page.")});
|
||||
this.setState({ presetError: _("Could not delete the preset. Please try to refresh the page.") });
|
||||
}).always(() => {
|
||||
this.setState({presetActionPerforming: false});
|
||||
this.setState({ presetActionPerforming: false });
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
}
|
||||
|
||||
toggleTagsField = () => {
|
||||
if (!this.state.showTagsField){
|
||||
if (!this.state.showTagsField) {
|
||||
setTimeout(() => {
|
||||
if (this.tagsField) this.tagsField.focus();
|
||||
}, 0);
|
||||
}
|
||||
this.setState({showTagsField: !this.state.showTagsField});
|
||||
this.setState({ showTagsField: !this.state.showTagsField });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error){
|
||||
if (this.state.error) {
|
||||
return (<div className="edit-task-panel">
|
||||
<div className="alert alert-warning">
|
||||
<div dangerouslySetInnerHTML={{__html:this.state.error}}></div>
|
||||
<button className="btn btn-sm btn-primary" onClick={this.retryLoad}>
|
||||
<i className="fa fa-rotate-left"></i> {_("Retry")}
|
||||
</button>
|
||||
</div>
|
||||
</div>);
|
||||
<div className="alert alert-warning">
|
||||
<div dangerouslySetInnerHTML={{ __html: this.state.error }}></div>
|
||||
<button className="btn btn-sm btn-primary" onClick={this.retryLoad}>
|
||||
<i className="fa fa-rotate-left"></i> {_("Retry")}
|
||||
</button>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
let taskOptions = "";
|
||||
if (this.formReady()){
|
||||
let iaOptions = "";
|
||||
if (this.formReady()) {
|
||||
|
||||
const optionsSelector = (
|
||||
<div className='select-container'>
|
||||
<select
|
||||
<div className='select-container' style={{ display: "flex", justifyContent: "start", alignItems: "center", }}>
|
||||
<select
|
||||
title={this.getAvailableOptionsOnlyText(this.state.selectedPreset.options, this.state.selectedNode.options)}
|
||||
className="form-control input-field"
|
||||
value={this.state.selectedPreset.id}
|
||||
className="form-control input-field"
|
||||
value={this.state.selectedPreset.id}
|
||||
onChange={this.handleSelectPreset}>
|
||||
{this.state.presets.map(preset =>
|
||||
<option value={preset.id} key={preset.id} className={preset.system ? "system-preset" : ""}>{preset.name === "Default" ? _(preset.name) : preset.name}</option>
|
||||
)}
|
||||
</select>
|
||||
{this.state.presets.map(preset =>
|
||||
<option value={preset.id} key={preset.id} className={preset.system ? "system-preset" : ""}>{preset.name === "Default" ? _(preset.name) : preset.name}</option>
|
||||
)}
|
||||
</select>
|
||||
|
||||
{!this.state.presetActionPerforming ?
|
||||
<div className="btn-group presets-dropdown">
|
||||
<button type="button" className="btn btn-sm btn-default" title={_("Edit Task Options")} onClick={this.handleEditPreset}>
|
||||
<i className="fa fa-sliders-h"></i> {_("Edit")}
|
||||
</button>
|
||||
<button type="button" className="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
{!this.state.presetActionPerforming ?
|
||||
<div className="btn-group presets-dropdown">
|
||||
<button type="button" className="btn btn-sm btn-default" title={_("Edit Task Options")} onClick={this.handleEditPreset}>
|
||||
<i className="fa fa-sliders-h"></i> {_("Edit")}
|
||||
</button>
|
||||
<button type="button" className="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<span className="caret"></span>
|
||||
</button>
|
||||
<ul className="dropdown-menu">
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleEditPreset}><i className="fa fa-sliders-h"></i> {_("Edit")}</a>
|
||||
</li>
|
||||
<li className="divider"></li>
|
||||
</button>
|
||||
<ul className="dropdown-menu">
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleEditPreset}><i className="fa fa-sliders-h"></i> {_("Edit")}</a>
|
||||
</li>
|
||||
<li className="divider"></li>
|
||||
|
||||
{this.state.selectedPreset.id !== -1 ?
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-copy"></i> {_("Duplicate")}</a>
|
||||
{this.state.selectedPreset.id !== -1 ?
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-copy"></i> {_("Duplicate")}</a>
|
||||
</li>
|
||||
:
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-save"></i> {_("Save")}</a>
|
||||
</li>
|
||||
}
|
||||
<li className={this.state.selectedPreset.system ? "disabled" : ""}>
|
||||
<a href="javascript:void(0);" onClick={this.handleDeletePreset}><i className="fa fa-trash"></i> {_("Delete")}</a>
|
||||
</li>
|
||||
:
|
||||
<li>
|
||||
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-save"></i> {_("Save")}</a>
|
||||
</li>
|
||||
}
|
||||
<li className={this.state.selectedPreset.system ? "disabled" : ""}>
|
||||
<a href="javascript:void(0);" onClick={this.handleDeletePreset}><i className="fa fa-trash"></i> {_("Delete")}</a>
|
||||
</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>);
|
||||
</ul>
|
||||
</div>
|
||||
: <i className="preset-performing-action-icon fa fa-cog fa-spin fa-fw"></i>}
|
||||
<ErrorMessage className="preset-error" bind={[this, 'presetError']} />
|
||||
</div>);
|
||||
|
||||
let tagsField = "";
|
||||
if (this.state.showTagsField){
|
||||
if (this.state.showTagsField) {
|
||||
tagsField = (<div className="form-group">
|
||||
<label className="col-sm-2 control-label">{_("Tags")}</label>
|
||||
<div className="col-sm-10">
|
||||
<TagsField onUpdate={(tags) => this.state.tags = tags } tags={this.state.tags} ref={domNode => this.tagsField = domNode}/>
|
||||
</div>
|
||||
</div>);
|
||||
<label className="col-sm-2 control-label">{_("Tags")}</label>
|
||||
<div className="col-sm-10">
|
||||
<TagsField onUpdate={(tags) => this.state.tags = tags} tags={this.state.tags} ref={domNode => this.tagsField = domNode} />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
taskOptions = (
|
||||
<div>
|
||||
<div className='edit-task-form'>
|
||||
{tagsField}
|
||||
{/* <div className="form-group col-sm-10 form-group-data">
|
||||
<label className="col-sm-2 control-label">{_("Processing Node")}</label>
|
||||
|
@ -592,60 +596,91 @@ class EditTaskForm extends React.Component {
|
|||
</select>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="form-group form-inline">
|
||||
<label className="col-sm-2 control-label">{_("Options")}</label>
|
||||
<div className="col-sm-10 option-container">
|
||||
{!this.props.inReview ? optionsSelector :
|
||||
<div className="review-options">
|
||||
{this.getAvailableOptionsOnlyText(this.state.selectedPreset.options, this.state.selectedNode.options)}
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
<div className='form-group pad-this'>
|
||||
<label className="col-sm-2 control-label">{_("Data")}</label>
|
||||
<input type="text" className="col-sm-10 input-field data-input"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.editingPreset ?
|
||||
<EditPresetDialog
|
||||
preset={this.state.selectedPreset}
|
||||
availableOptions={this.state.selectedNode.options}
|
||||
onHide={this.handleCancelEditPreset}
|
||||
saveAction={this.handlePresetSave}
|
||||
deleteAction={this.handleDeletePreset}
|
||||
ref={(domNode) => { if (domNode) this.editPresetDialog = domNode; }}
|
||||
/>
|
||||
: ""}
|
||||
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
taskOptions = (<div className="form-group">
|
||||
<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>
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="edit-task-form">
|
||||
<div className="form-group col-sm-10">
|
||||
<label className="col-sm-2 control-label">{_("Name")}</label>
|
||||
<div className="form-group col-sm-10">
|
||||
<label className="col-sm-2 control-label">{_("Name")}</label>
|
||||
<div className="col-sm-10 name-fields input-field">
|
||||
{this.state.loadingTaskName ?
|
||||
<i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i>
|
||||
: ""}
|
||||
<input type="text"
|
||||
onChange={this.handleNameChange}
|
||||
{this.state.loadingTaskName ?
|
||||
<i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i>
|
||||
: ""}
|
||||
<input type="text"
|
||||
onChange={this.handleNameChange}
|
||||
className="remove-style name-input"
|
||||
placeholder={this.state.namePlaceholder}
|
||||
value={this.state.name}/>
|
||||
placeholder={this.state.namePlaceholder}
|
||||
value={this.state.name} />
|
||||
<button type="button" title={_("Add tags")} onClick={this.toggleTagsField} className="remove-style">
|
||||
<i className="fa fa-tag"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{taskOptions}
|
||||
</div>
|
||||
{/* <div>
|
||||
<label className="col-sm-2 control-label">{_("Options")}</label>
|
||||
<div className="col-sm-10 option-container">
|
||||
{!this.props.inReview ? optionsSelector :
|
||||
<div className="review-options">
|
||||
{this.getAvailableOptionsOnlyText(this.state.selectedPreset.options, this.state.selectedNode.options)}
|
||||
</div>}
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div className='form-group col-sm-10'>
|
||||
<label className="col-sm-2 control-label">{_("Data")}</label>
|
||||
<div className="col-sm-10 option-container">
|
||||
<input type="text" className="col-sm-10 input-field data-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
this.state.editingPreset ?
|
||||
<EditPresetDialog
|
||||
preset={this.state.selectedPreset}
|
||||
availableOptions={this.state.selectedNode.options}
|
||||
onHide={this.handleCancelEditPreset}
|
||||
saveAction={this.handlePresetSave}
|
||||
deleteAction={this.handleDeletePreset}
|
||||
ref={(domNode) => { if (domNode) this.editPresetDialog = domNode; }}
|
||||
/>
|
||||
: ""
|
||||
}
|
||||
</div >);
|
||||
} else {
|
||||
taskOptions = (<div className="form-group">
|
||||
<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>
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<>
|
||||
{/* Task Information Panel */}
|
||||
{this.props.currentStep === "settingsStep" && <div>{taskOptions}</div>}
|
||||
|
||||
{/* Ai Panel */}
|
||||
{this.props.currentStep === "aiStep" && <div>
|
||||
<div className='edit-task-form'>
|
||||
<div className="form-group">
|
||||
<label className="col-sm-2 control-label ai-label">{_("Detecção de Daninhas e Obstáculos com IA:")}</label>
|
||||
<select className='btn btn-default-s selectBtn dropdown-toggle' style={{ backgroundColor: "#74B16F" }}>
|
||||
<option>Sim</option>
|
||||
<option>Não</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label className="col-sm-2 control-label ai-label">{_("Geração de Arquivos")}</label>
|
||||
<button className='btn btn-default-s selectBtn dropdown-toggle'>Uso em Drones</button>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label className="col-sm-2 control-label ai-label" >{_("Detecção de Subtalhões:")}</label>
|
||||
<select className='btn btn-default-s selectBtn dropdown-toggle' style={{ backgroundColor: "#74B16F" }}>
|
||||
<option>Sim</option>
|
||||
<option>Não</option>
|
||||
</select>
|
||||
</div>
|
||||
</div >
|
||||
</div>}
|
||||
|
||||
{/* Loading Panel */}
|
||||
{this.props.currentStep === "loadingStep" && <div></div>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,20 +49,38 @@
|
|||
|
||||
.form-group {
|
||||
width: 100%;
|
||||
|
||||
|
||||
.select-container {
|
||||
display: flex;
|
||||
}
|
||||
.option-container {
|
||||
padding: 0 15px 0 7px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.option-container {
|
||||
padding: 0px 15px;
|
||||
}
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.pad-this {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.selectBtn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
background-position: calc(100% - 0.75rem) center !important;
|
||||
-moz-appearance:none !important;
|
||||
-webkit-appearance: none !important;
|
||||
appearance: none !important;
|
||||
}
|
||||
|
||||
.ai-label {
|
||||
width: 400px;
|
||||
@media (max-width: 600px) {
|
||||
.ai-label {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-group-data {
|
||||
|
|
Ładowanie…
Reference in New Issue