update-transform.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 { State, StateTransform, StateTransformer } from '../../mol-state';
  7. import { memoizeLatest } from '../../mol-util/memoize';
  8. import { StateTransformParameters, TransformControlBase } from './common';
  9. import { Observable } from 'rxjs';
  10. import * as React from 'react';
  11. import { PluginUIComponent } from '../base';
  12. export { UpdateTransformControl, TransformUpdaterControl };
  13. namespace UpdateTransformControl {
  14. export interface Props {
  15. transform: StateTransform,
  16. state: State,
  17. toggleCollapsed?: Observable<any>,
  18. initiallyCollapsed?: boolean,
  19. customHeader?: StateTransformer.Definition['display'] | 'none',
  20. customUpdate?: (params: any) => Promise<any>,
  21. }
  22. export interface ComponentState extends TransformControlBase.ComponentState {
  23. }
  24. }
  25. class UpdateTransformControl extends TransformControlBase<UpdateTransformControl.Props, UpdateTransformControl.ComponentState> {
  26. applyAction() {
  27. if (this.props.customUpdate) return this.props.customUpdate(this.state.params);
  28. return this.plugin.state.updateTransform(this.props.state, this.props.transform.ref, this.state.params);
  29. }
  30. getInfo() { return this._getInfo(this.props.transform); }
  31. getTransformerId() { return this.props.transform.transformer.id; }
  32. getHeader() { return this.props.customHeader || this.props.transform.transformer.definition.display; }
  33. canApply() {
  34. const { state } = this.props;
  35. const cell = state.cells.get(this.props.transform.ref);
  36. if (!cell) return false;
  37. if (cell.status === 'error') {
  38. const parent = state.cells.get(this.props.transform.parent)!;
  39. if (!parent) return false;
  40. return parent.status === 'ok';
  41. }
  42. return !this.state.error && !this.state.busy && !this.state.isInitial;
  43. }
  44. applyText() { return this.canApply() ? 'Update' : 'Nothing to Update'; }
  45. isUpdate() { return true; }
  46. getSourceAndTarget() {
  47. const bCell = this.props.state.cells.get(this.props.transform.ref);
  48. return {
  49. a: this.props.state.cells.get(this.props.transform.parent)!.obj,
  50. b: bCell?.obj,
  51. bCell
  52. };
  53. }
  54. canAutoApply(newParams: any) {
  55. const autoUpdate = this.props.transform.transformer.definition.canAutoUpdate;
  56. if (!autoUpdate) return false;
  57. const { state } = this.props;
  58. const cell = state.cells.get(this.props.transform.ref);
  59. if (!cell || !cell.sourceRef || cell.status !== 'ok') return false;
  60. const parentCell = state.cells.get(cell.sourceRef)!;
  61. return autoUpdate({ a: parentCell.obj!, b: cell.obj!, oldParams: this.getInfo().initialValues, newParams }, this.plugin);
  62. }
  63. componentDidMount() {
  64. if (super.componentDidMount) super.componentDidMount();
  65. if (this.props.toggleCollapsed) this.subscribe(this.props.toggleCollapsed, () => this.setState({ isCollapsed: !this.state.isCollapsed }));
  66. this.subscribe(this.plugin.state.events.object.updated, ({ ref, state }) => {
  67. if (this.props.transform.ref !== ref || this.props.state !== state) return;
  68. if (this.state.params !== this.props.transform.params) {
  69. this._getInfo = memoizeLatest((t: StateTransform) => StateTransformParameters.infoFromTransform(this.plugin, this.props.state, t));
  70. this.setState({ params: this.props.transform.params, isInitial: true });
  71. }
  72. });
  73. }
  74. private _getInfo = memoizeLatest((t: StateTransform) => StateTransformParameters.infoFromTransform(this.plugin, this.props.state, t));
  75. state: UpdateTransformControl.ComponentState = { error: void 0, isInitial: true, params: this.getInfo().initialValues, busy: false, isCollapsed: this.props.initiallyCollapsed };
  76. componentDidUpdate(prevProps: UpdateTransformControl.Props) {
  77. if (this.props.transform !== prevProps.transform) {
  78. const cell = this.props.state.cells.get(this.props.transform.ref)!;
  79. this.setState({
  80. params: cell.params?.values || { },
  81. isInitial: true,
  82. error: void 0,
  83. simpleOnly: this.state.simpleOnly
  84. });
  85. }
  86. }
  87. }
  88. class TransformUpdaterControl extends PluginUIComponent<{ nodeRef: string, initiallyCollapsed?: boolean, header?: StateTransformer.Definition['display'] }> {
  89. componentDidMount() {
  90. this.subscribe(this.plugin.state.events.object.updated, ({ ref, state }) => {
  91. if (this.props.nodeRef !== ref || this.plugin.state.data !== state) return;
  92. this.forceUpdate();
  93. });
  94. }
  95. render() {
  96. const state = this.plugin.state.data;
  97. const ref = this.props.nodeRef;
  98. const cell = state.cells.get(ref)!;
  99. if (!cell || (cell.status !== 'ok' && cell.status !== 'error')) return null;
  100. const transform = cell.transform;
  101. return <UpdateTransformControl state={state} transform={transform} initiallyCollapsed={this.props.initiallyCollapsed} customHeader={this.props.header} />;
  102. }
  103. }