Newer
Older
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { StateObject, State, Transform, StateObjectCell, Transformer } from 'mol-state';
import * as React from 'react';
import { PurePluginComponent } from '../base';
import { ParameterControls, ParamOnChange } from '../controls/parameters';
import { StateAction } from 'mol-state/action';
import { PluginContext } from 'mol-plugin/context';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { Subject } from 'rxjs';
export { StateTransformParameters, TransformContolBase };
class StateTransformParameters extends PurePluginComponent<StateTransformParameters.Props> {
validate(params: any) {
}
areInitial(params: any) {
return PD.areEqual(this.props.info.params, params, this.props.info.initialValues);
}
onChange: ParamOnChange = ({ name, value }) => {
const params = { ...this.props.params, [name]: value };
this.props.events.onChange(params, this.areInitial(params), this.validate(params));
};
render() {
return <ParameterControls params={this.props.info.params} values={this.props.params} onChange={this.onChange} onEnter={this.props.events.onEnter} isDisabled={this.props.isDisabled} />;
}
}
namespace StateTransformParameters {
export interface Props {
info: {
params: PD.Params,
initialValues: any,
source: StateObject,
isEmpty: boolean
},
events: {
onChange: (params: any, areInitial: boolean, errors?: string[]) => void,
onEnter: () => void,
}
params: any,
}
export type Class = React.ComponentClass<Props>
export function infoFromAction(plugin: PluginContext, state: State, action: StateAction, nodeRef: Transform.Ref): Props['info'] {
const source = state.cells.get(nodeRef)!.obj!;
const params = action.definition.params ? action.definition.params(source, plugin) : { };
const initialValues = PD.getDefaultValues(params);
return {
source,
initialValues,
params,
isEmpty: Object.keys(params).length === 0
};
}
export function infoFromTransform(plugin: PluginContext, state: State, transform: Transform): Props['info'] {
const cell = state.cells.get(transform.ref)!;
const source: StateObjectCell | undefined = (cell.sourceRef && state.cells.get(cell.sourceRef)!) || void 0;
const create = transform.transformer.definition.params;
const params = create ? create((source && source.obj) as any, plugin) : { };
return {
source: (source && source.obj) as any,
initialValues: transform.params,
params,
isEmpty: Object.keys(params).length === 0
}
}
}
namespace TransformContolBase {
export interface State {
params: any,
error?: string,
busy: boolean,
}
}
abstract class TransformContolBase<P, S extends TransformContolBase.State> extends PurePluginComponent<P, S> {
abstract applyAction(): Promise<void>;
abstract getInfo(): StateTransformParameters.Props['info'];
abstract getHeader(): Transformer.Definition['display'];
abstract getHeaderFallback(): string;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
abstract applyText(): string;
abstract state: S;
private busy: Subject<boolean>;
private onEnter = () => {
if (this.state.error) return;
this.apply();
}
events: StateTransformParameters.Props['events'] = {
onEnter: this.onEnter,
onChange: (params, isInitial, errors) => this.setState({ params, isInitial, error: errors && errors[0] })
}
apply = async () => {
this.setState({ busy: true });
try {
await this.applyAction();
} finally {
this.busy.next(false);
}
}
init() {
this.busy = new Subject();
this.subscribe(this.busy, busy => this.setState({ busy }));
}
refresh = () => {
this.setState({ params: this.getInfo().initialValues, isInitial: true, error: void 0 });
}
setDefault = () => {
const info = this.getInfo();
const params = PD.getDefaultValues(info.params);
this.setState({ params, isInitial: PD.areEqual(info.params, params, info.initialValues), error: void 0 });
}
toggleExpanded = () => {
this.setState({ isCollapsed: !this.state.isCollapsed });
}
render() {
const info = this.getInfo();
const display = this.getHeader();
return <div className='msp-transform-wrapper'>
<div className='msp-transform-header'>
<button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>{(display && display.name) || this.getHeaderFallback()}</button>
{!this.state.isCollapsed && <button className='msp-btn msp-btn-link msp-transform-default-params' onClick={this.setDefault} disabled={this.state.busy} style={{ float: 'right'}} title='Set default params'>↻</button>}
{!this.state.isCollapsed && <>
<StateTransformParameters info={info} events={this.events} params={this.state.params} isDisabled={this.state.busy} />
<div className='msp-transform-apply-wrap'>
<button className='msp-btn msp-btn-block msp-transform-refresh msp-form-control' title='Refresh params' onClick={this.refresh} disabled={this.state.busy || this.state.isInitial}>
↶ Reset
</button>
<div className='msp-transform-apply'>
<button className={`msp-btn msp-btn-block msp-btn-commit msp-btn-commit-${this.canApply() ? 'on' : 'off'}`} onClick={this.apply} disabled={!this.canApply()}>
{this.applyText()}
</button>
</div>
</div>
</>}