apply-action.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import * as React from 'react';
  7. import { PluginCommands } from 'mol-plugin/command';
  8. import { State, Transform } from 'mol-state';
  9. import { StateAction } from 'mol-state/action';
  10. import { Subject } from 'rxjs';
  11. import { PurePluginComponent } from '../base';
  12. import { StateTransformParameters } from './parameters';
  13. import { memoizeOne } from 'mol-util/memoize';
  14. import { PluginContext } from 'mol-plugin/context';
  15. export { ApplyActionContol };
  16. namespace ApplyActionContol {
  17. export interface Props {
  18. plugin: PluginContext,
  19. nodeRef: Transform.Ref,
  20. state: State,
  21. action: StateAction
  22. }
  23. export interface ComponentState {
  24. nodeRef: Transform.Ref,
  25. params: any,
  26. error?: string,
  27. busy: boolean,
  28. isInitial: boolean
  29. }
  30. }
  31. class ApplyActionContol extends PurePluginComponent<ApplyActionContol.Props, ApplyActionContol.ComponentState> {
  32. private busy: Subject<boolean>;
  33. onEnter = () => {
  34. if (this.state.error) return;
  35. this.apply();
  36. }
  37. source = this.props.state.cells.get(this.props.nodeRef)!.obj!;
  38. getInfo = memoizeOne((t: Transform.Ref) => StateTransformParameters.infoFromAction(this.plugin, this.props.state, this.props.action, this.props.nodeRef));
  39. events: StateTransformParameters.Props['events'] = {
  40. onEnter: this.onEnter,
  41. onChange: (params, isInitial, errors) => {
  42. this.setState({ params, isInitial, error: errors && errors[0] })
  43. }
  44. }
  45. // getInitialParams() {
  46. // const p = this.props.action.definition.params;
  47. // if (!p || !p.default) return {};
  48. // return p.default(this.source, this.plugin);
  49. // }
  50. // initialErrors() {
  51. // const p = this.props.action.definition.params;
  52. // if (!p || !p.validate) return void 0;
  53. // const errors = p.validate(this.info.initialValues, this.source, this.plugin);
  54. // return errors && errors[0];
  55. // }
  56. state = { nodeRef: this.props.nodeRef, error: void 0, isInitial: true, params: this.getInfo(this.props.nodeRef).initialValues, busy: false };
  57. apply = async () => {
  58. this.setState({ busy: true });
  59. try {
  60. await PluginCommands.State.ApplyAction.dispatch(this.plugin, {
  61. state: this.props.state,
  62. action: this.props.action.create(this.state.params),
  63. ref: this.props.nodeRef
  64. });
  65. } finally {
  66. this.busy.next(false);
  67. }
  68. }
  69. init() {
  70. this.busy = new Subject();
  71. this.subscribe(this.busy, busy => this.setState({ busy }));
  72. }
  73. refresh = () => {
  74. this.setState({ params: this.getInfo(this.props.nodeRef).initialValues, isInitial: true, error: void 0 });
  75. }
  76. static getDerivedStateFromProps(props: ApplyActionContol.Props, state: ApplyActionContol.ComponentState) {
  77. if (props.nodeRef === state.nodeRef) return null;
  78. const source = props.state.cells.get(props.nodeRef)!.obj!;
  79. const definition = props.action.definition.params || { };
  80. const initialValues = definition.default ? definition.default(source, props.plugin) : {};
  81. const newState: Partial<ApplyActionContol.ComponentState> = {
  82. nodeRef: props.nodeRef,
  83. params: initialValues,
  84. isInitial: true,
  85. error: void 0
  86. };
  87. return newState;
  88. }
  89. render() {
  90. const info = this.getInfo(this.props.nodeRef);
  91. const action = this.props.action;
  92. return <div>
  93. <div style={{ borderBottom: '1px solid #999', marginBottom: '5px' }}><h3>{(action.definition.display && action.definition.display.name) || action.id}</h3></div>
  94. <StateTransformParameters info={info} events={this.events} params={this.state.params} isEnabled={!this.state.busy} />
  95. <div style={{ textAlign: 'right' }}>
  96. <span style={{ color: 'red' }}>{this.state.error}</span>
  97. {this.state.isInitial ? void 0 : <button title='Refresh Params' onClick={this.refresh} disabled={this.state.busy}>↻</button>}
  98. <button onClick={this.apply} disabled={!!this.state.error || this.state.busy}>Create</button>
  99. </div>
  100. </div>
  101. }
  102. }