terriajs
Version:
Geospatial data visualization platform.
137 lines (119 loc) • 5.19 kB
JSX
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import React from 'react';
import defined from 'terriajs-cesium/Source/Core/defined';
import knockout from 'terriajs-cesium/Source/ThirdParty/knockout';
import when from 'terriajs-cesium/Source/ThirdParty/when';
import TerriaError from '../../Core/TerriaError';
import parseCustomMarkdownToReact from '../Custom/parseCustomMarkdownToReact';
import Loader from '../Loader';
import ObserveModelMixin from '../ObserveModelMixin';
import ParameterEditor from './ParameterEditor';
import Styles from './invoke-function.scss';
class FunctionViewModel {
constructor(catalogFunction) {
this.catalogFunction = catalogFunction;
this._parameters = {};
}
getParameter(parameter) {
let result = this._parameters[parameter.id];
if (!result || result.parameter !== parameter) {
result = this._parameters[parameter.id] = new ParameterViewModel(parameter);
}
return result;
}
}
class ParameterViewModel {
constructor(parameter) {
this.parameter = parameter;
this.userValue = undefined;
this.isValueValid = true;
this.wasEverBlurredWhileInvalid = false;
knockout.track(this, ['userValue', 'isValueValid', 'wasEverBlurredWhileInvalid']);
}
}
const InvokeFunction = createReactClass({
displayName: 'InvokeFunction',
mixins: [ObserveModelMixin],
propTypes: {
terria: PropTypes.object,
previewed: PropTypes.object,
viewState: PropTypes.object
},
/* eslint-disable-next-line camelcase */
UNSAFE_componentWillMount() {
this.parametersViewModel = new FunctionViewModel(this.props.previewed);
},
/* eslint-disable-next-line camelcase */
UNSAFE_componentWillUpdate(nextProps, nextState) {
if (nextProps.previewed !== this.parametersViewModel.catalogFunction) {
// Clear previous parameters view model, because this is a different catalog function.
this.parametersViewModel = new FunctionViewModel(nextProps.previewed);
}
},
submit() {
try {
const promise = when(this.props.previewed.invoke())
.otherwise(terriaError => {
if (terriaError instanceof TerriaError) {
this.props.previewed.terria.error.raiseEvent(terriaError);
}
});
// Show the Now Viewing panel
this.props.previewed.terria.nowViewing.showNowViewingRequested.raiseEvent();
// Close modal window
this.props.viewState.explorerPanelIsVisible = false;
// mobile switch to nowvewing
this.props.viewState.switchMobileView(this.props.viewState.mobileViewOptions.preview);
return promise;
} catch (e) {
if (e instanceof TerriaError) {
this.props.previewed.terria.error.raiseEvent(e);
}
return undefined;
}
},
getParams() {
// Key should include the previewed item identifier so that
// components are refreshed when different previewed items are
// displayed
return this.props.previewed.parameters.map((param, i)=>
<ParameterEditor key={param.id + this.props.previewed.uniqueId}
parameter={param}
viewState={this.props.viewState}
previewed={this.props.previewed}
parameterViewModel={this.parametersViewModel.getParameter(param)}
/>);
},
validateParameter(parameter) {
if (!this.parametersViewModel.getParameter(parameter).isValueValid) {
// Editor says it's not valid, so it's not valid.
return false;
}
// Verify that required parameters have a value.
if (parameter.isRequired && !defined(parameter.value)) {
return false;
}
return true;
},
render() {
if (this.props.previewed.isLoading) {
return <Loader />;
}
let invalidParameters = false;
if (defined(this.props.previewed.parameters)) {
invalidParameters = !this.props.previewed.parameters.every(this.validateParameter);
}
return (<div className={Styles.invokeFunction}>
<div className={Styles.content}>
<h3>{this.props.previewed.name}</h3>
<div className={Styles.description}>{parseCustomMarkdownToReact(this.props.previewed.description, {catalogItem: this.props.previewed})}</div>
{this.getParams()}
</div>
<div className={Styles.footer}>
<button type='button' className={Styles.btn} onClick={this.submit} disabled={invalidParameters}>Run Analysis</button>
</div>
</div>);
},
});
module.exports = InvokeFunction;