UNPKG

terriajs

Version:

Geospatial data visualization platform.

137 lines (119 loc) 5.19 kB
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;