UNPKG

stitch-ui

Version:

350 lines (336 loc) 10.6 kB
/* global window */ import React from "react"; import PropTypes from "prop-types"; import { List } from "immutable"; import { connect } from "react-redux"; import qs from "query-string"; import PipelineEditor from "../../pipelineeditor/components/PipelineEditor"; import * as pipelineActions from "../../pipelineeditor/actions"; import * as actions from "../actions"; import { Pipeline, PipelineStage } from "../../models"; import { PIPELINE_OUTPUT_ARRAY } from "../../models/Pipeline"; import { User } from "../../user"; import UserModal from "./UserModal"; import OutputPanel from "./OutputPanel"; import { Button, Banner, Panel } from "../../core"; const savedPipelinesKey = "debugconsole/pipelines"; const pipelineKey = appId => `debugconsole/${appId}`; const defaultNewPipeline = new Pipeline({ stages: List([ new PipelineStage({ action: "literal", args: { items: [{ x: 1, y: "foo" }] } }) ]), output: PIPELINE_OUTPUT_ARRAY }); const keepPipeline = (appId, pipeline, userId) => { if (typeof window === "undefined" || !window.localStorage) { return; } const savedPipelines = JSON.parse( window.localStorage.getItem(savedPipelinesKey) || "{}" ); savedPipelines[appId] = { pipeline, userId }; window.localStorage.setItem( savedPipelinesKey, JSON.stringify(savedPipelines) ); }; const restorePipeline = appId => { if (typeof window === "undefined" || !window.localStorage) { return null; } const savedPipelines = JSON.parse( window.localStorage.getItem(savedPipelinesKey) || "{}" ); return savedPipelines[appId]; }; class DebugConsole extends React.Component { componentDidMount() { const { resetDebugConsole, resetUsers, loadUser, initPipeline, app } = this.props; const location = this.props.history.location; location.query = qs.parse(location.search); resetDebugConsole(); resetUsers(); let shouldRestoreUser = true; let shouldRestorePipeline = true; if (location && location.query.user_id) { loadUser(location.query.user_id); shouldRestoreUser = false; } let initialPipeline = defaultNewPipeline; if ( typeof window !== "undefined" && window.localStorage && location && location.query.pipelineKey ) { try { const jsonStages = JSON.parse( window.localStorage.getItem(location.query.pipelineKey) ); const stages = List(jsonStages.map(s => new PipelineStage(s))); initialPipeline = new Pipeline({ output: PIPELINE_OUTPUT_ARRAY, stages }); shouldRestorePipeline = false; } catch (err) { this.props.setError(err); } } if (shouldRestoreUser || shouldRestorePipeline) { const restoredPipeline = restorePipeline(app._id); if (restoredPipeline && shouldRestoreUser) { loadUser(restoredPipeline.userId); } if (restoredPipeline && shouldRestorePipeline) { initialPipeline = new Pipeline({ output: restoredPipeline.pipeline.output, stages: List( restoredPipeline.pipeline.pipeline.map(s => new PipelineStage(s)) ) }); } } initPipeline(initialPipeline); } render() { const { app, error, adminError, output, users, loadUsers, setError, services, executePipeline, clearOutput, lastUserId, selectUser, selectedUser, clearSelectedUser } = this.props; return ( <div> <div className="section-header"> <div className="section-header-title"> <div className="section-header-title-text">Debug Console</div> </div> </div> <div className="tabs-content"> <Banner message="All stages of pipelines executed in the debug console will be fully run against services configured." info icon clearable /> <UserModal users={users} loadUsers={loadUsers} lastUserId={lastUserId} selectUser={selectUser} selectedUser={selectedUser} open={(this.state || {}).showUserModal} onClose={() => { this.setState({ showUserModal: false }); }} /> <Panel> <div className="panel-header"> <div className="panel-header-title"> <div className="steps-step"> <div className="steps-step-num">1</div> <h5 className="steps-step-title"> Execute pipeline as user:&nbsp;{" "} </h5> </div> {selectedUser ? <span> <div className="users-list-item"> <div className="users-list-item-column users-list-item-pic"> {selectedUser.getImage()} </div> <div className="users-list-item-column users-list-item-name"> {selectedUser.getDisplayName()} </div> </div> <Button type="button" className="button button-is-small" onClick={clearSelectedUser} > Clear </Button> </span> : <Button type="button" className="button button-is-small" onClick={() => { this.setState({ showUserModal: true }); }} > Select User </Button>} </div> </div> <div className="panel-content splitpanel-debug-content"> <div className="debugconsole-splitpanel-input"> <div className="steps-step"> <div className="steps-step-num">2</div> <h5 className="steps-step-title">Pipeline to execute:</h5> </div> <div> <Button small primary onClick={() => this.pipelineEditor.getWrappedInstance().child.submit()} > Execute </Button> </div> <PipelineEditor noOutputType ref={pipelineEditor => (this.pipelineEditor = pipelineEditor)} pipelineKey={pipelineKey(app._id)} onSubmit={pipeline => { if (!selectedUser) { setError("Must select a user first."); return; } keepPipeline( app._id, pipeline.toRaw(), selectedUser.getId() ); executePipeline( pipeline.toRaw().pipeline, selectedUser.getId() ); }} saveButtonText="Execute" services={services} /> </div> <OutputPanel error={error} clearOutput={clearOutput} adminError={adminError} output={output} /> </div> </Panel> </div> </div> ); } } const mapStateToProps = state => { const { app } = state.app.root; const { output, error, adminError, selectedUser } = state.debugconsole.debugconsole; const { services } = state.app.root; const { users, loadingUsers, loadingUsersError, lastUserId } = state.debugconsole.users; return { output, error, adminError, services, app, users, loadingUsers, loadingUsersError, lastUserId, selectedUser }; }; const mapDispatchToProps = (dispatch, ownProps) => ({ resetDebugConsole: () => dispatch(actions.resetDebugConsole()), resetUsers: () => dispatch(actions.resetUsersAction()), resetError: () => dispatch(actions.resetError()), setError: msg => dispatch(actions.setError(msg)), selectUser: user => dispatch(actions.selectUser(user)), clearOutput: () => dispatch(actions.clearOutput()), clearSelectedUser: () => dispatch(actions.clearSelectedUser()), loadUser: userId => dispatch(actions.loadUser(ownProps.app.groupId, ownProps.app._id, userId)), loadUsers: filter => dispatch(actions.loadUsers(ownProps.app.groupId, ownProps.app._id, filter)), initPipeline: pipelineObj => dispatch( pipelineActions.initPipeline({ pipelineKey: pipelineKey(ownProps.app._id), pipelineObj }) ), executePipeline: (pipelineObj, userId) => dispatch( actions.executePipeline( ownProps.app.groupId, ownProps.app._id, userId, pipelineObj ) ) }); DebugConsole.propTypes = { // Data app: PropTypes.shape({ _id: PropTypes.string.isRequired }).isRequired, error: PropTypes.string, adminError: PropTypes.string, output: PropTypes.object, // eslint-disable-line react/forbid-prop-types users: PropTypes.instanceOf(List).isRequired, services: PropTypes.objectOf( PropTypes.shape({ type: PropTypes.string.isRequired }) ).isRequired, lastUserId: PropTypes.string, location: PropTypes.object, // eslint-disable-line react/forbid-prop-types selectedUser: PropTypes.instanceOf(User), history: PropTypes.objectOf( PropTypes.shape({ location: PropTypes.any }) ), // Functions loadUsers: PropTypes.func.isRequired, setError: PropTypes.func.isRequired, executePipeline: PropTypes.func.isRequired, selectUser: PropTypes.func.isRequired, clearSelectedUser: PropTypes.func.isRequired, resetDebugConsole: PropTypes.func.isRequired, resetUsers: PropTypes.func.isRequired, loadUser: PropTypes.func.isRequired, initPipeline: PropTypes.func.isRequired, clearOutput: PropTypes.func.isRequired }; DebugConsole.defaultProps = { error: null, adminError: null, output: undefined, lastUserId: null, selectedUser: null, location: null, match: null, history: null }; export default connect(mapStateToProps, mapDispatchToProps)(DebugConsole);