Bladeren bron

mol-state: transformer & state action definition tweaks

David Sehnal 6 jaren geleden
bovenliggende
commit
ec1dc600d2

+ 5 - 13
src/mol-plugin/state/actions/basic.ts

@@ -82,13 +82,10 @@ const DownloadStructure = StateAction.create<PluginStateObject.Root, void, Downl
 });
 
 export const OpenStructure = StateAction.build({
+    display: { name: 'Open Structure', description: 'Load a structure from file and create its default Assembly and visual' },
     from: PluginStateObject.Root,
     params: { file: PD.File({ accept: '.cif,.bcif' }) }
 })({
-    display: {
-        name: 'Open Structure',
-        description: 'Load a structure from file and create its default Assembly and visual'
-    },
     apply({ params, state }) {
         const b = state.build();
         const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) });
@@ -132,12 +129,9 @@ function complexRepresentation(root: StateTreeBuilder.To<PluginStateObject.Molec
 }
 
 export const CreateComplexRepresentation = StateAction.build({
+    display: { name: 'Create Complex', description: 'Split the structure into Sequence/Water/Ligands/... ' },
     from: PluginStateObject.Molecule.Structure
 })({
-    display: {
-        name: 'Create Complex',
-        description: 'Split the structure into Sequence/Water/Ligands/... '
-    },
     apply({ ref, state }) {
         const root = state.build().to(ref);
         complexRepresentation(root);
@@ -146,14 +140,12 @@ export const CreateComplexRepresentation = StateAction.build({
 });
 
 export const UpdateTrajectory = StateAction.build({
-    params: () => ({
+    display: { name: 'Update Trajectory' },
+    params: {
         action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]),
         by: PD.makeOptional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
-    })
+    }
 })({
-    display: {
-        name: 'Update Trajectory'
-    },
     apply({ params, state }) {
         const models = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Model)
             .filter(c => c.transform.transformer === StateTransforms.Model.ModelFromTrajectory));

+ 4 - 13
src/mol-plugin/state/transforms/data.ts

@@ -17,6 +17,7 @@ export { Download }
 type Download = typeof Download
 const Download = PluginStateTransform.BuiltIn({
     name: 'download',
+    display: { name: 'Download', description: 'Download string or binary data from the specified URL' },
     from: [SO.Root],
     to: [SO.Data.String, SO.Data.Binary],
     params: {
@@ -25,10 +26,6 @@ const Download = PluginStateTransform.BuiltIn({
         isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, download data as binary (string otherwise)' }))
     }
 })({
-    display: {
-        name: 'Download',
-        description: 'Download string or binary data from the specified URL'
-    },
     apply({ params: p }, globalCtx: PluginContext) {
         return Task.create('Download', async ctx => {
             const data = await globalCtx.fetch(p.url, p.isBinary ? 'binary' : 'string').runInContext(ctx);
@@ -51,18 +48,15 @@ export { ReadFile }
 type ReadFile = typeof ReadFile
 const ReadFile = PluginStateTransform.BuiltIn({
     name: 'read-file',
+    display: { name: 'Read File', description: 'Read string or binary data from the specified file' },
     from: SO.Root,
     to: [SO.Data.String, SO.Data.Binary],
     params: {
         file: PD.File(),
         label: PD.makeOptional(PD.Text('')),
         isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' }))
-    },
+    }
 })({
-    display: {
-        name: 'Read File',
-        description: 'Read string or binary data from the specified file'
-    },
     apply({ params: p }) {
         return Task.create('Open File', async ctx => {
             const data = await readFromFile(p.file, p.isBinary ? 'binary' : 'string').runInContext(ctx);
@@ -85,13 +79,10 @@ export { ParseCif }
 type ParseCif = typeof ParseCif
 const ParseCif = PluginStateTransform.BuiltIn({
     name: 'parse-cif',
+    display: { name: 'Parse CIF', description: 'Parse CIF from String or Binary data' },
     from: [SO.Data.String, SO.Data.Binary],
     to: SO.Format.Cif
 })({
-    display: {
-        name: 'Parse CIF',
-        description: 'Parse CIF from String or Binary data'
-    },
     apply({ a }) {
         return Task.create('Parse CIF', async ctx => {
             const parsed = await (SO.Data.String.is(a) ? CIF.parse(a.data) : CIF.parseBinary(a.data)).runInContext(ctx);

+ 11 - 29
src/mol-plugin/state/transforms/model.ts

@@ -19,6 +19,7 @@ export { TrajectoryFromMmCif }
 type TrajectoryFromMmCif = typeof TrajectoryFromMmCif
 const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({
     name: 'trajectory-from-mmcif',
+    display: { name: 'Trajectory from mmCIF', description: 'Identify and create all separate models in the specified CIF data block' },
     from: SO.Format.Cif,
     to: SO.Molecule.Trajectory,
     params(a) {
@@ -26,12 +27,8 @@ const TrajectoryFromMmCif = PluginStateTransform.BuiltIn({
         return {
             blockHeader: PD.makeOptional(PD.Select(blocks[0] && blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]), { description: 'Header of the block to parse' }))
         };
-    },
+    }
 })({
-    display: {
-        name: 'Models from mmCIF',
-        description: 'Identify and create all separate models in the specified CIF data block'
-    },
     isApplicable: a => a.data.blocks.length > 0,
     apply({ a, params }) {
         return Task.create('Parse mmCIF', async ctx => {
@@ -51,14 +48,11 @@ const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1;
 type ModelFromTrajectory = typeof ModelFromTrajectory
 const ModelFromTrajectory = PluginStateTransform.BuiltIn({
     name: 'model-from-trajectory',
+    display: { name: 'Model from Trajectory', description: 'Create a molecular structure from the specified model.' },
     from: SO.Molecule.Trajectory,
     to: SO.Molecule.Model,
     params: a => ({ modelIndex: PD.Converted(plus1, minus1, PD.Numeric(1, { min: 1, max: a.data.length, step: 1 }, { description: 'Model Index' })) })
 })({
-    display: {
-        name: 'Model from Trajectory',
-        description: 'Create a molecular structure from the specified model.'
-    },
     isApplicable: a => a.data.length > 0,
     apply({ a, params }) {
         if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`);
@@ -72,13 +66,10 @@ export { StructureFromModel }
 type StructureFromModel = typeof StructureFromModel
 const StructureFromModel = PluginStateTransform.BuiltIn({
     name: 'structure-from-model',
+    display: { name: 'Structure from Model', description: 'Create a molecular structure from the specified model.' },
     from: SO.Molecule.Model,
-    to: SO.Molecule.Structure,
+    to: SO.Molecule.Structure
 })({
-    display: {
-        name: 'Structure from Model',
-        description: 'Create a molecular structure from the specified model.'
-    },
     apply({ a }) {
         let s = Structure.ofModel(a.data);
         const label = { label: a.data.label, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` };
@@ -94,6 +85,7 @@ export { StructureAssemblyFromModel }
 type StructureAssemblyFromModel = typeof StructureAssemblyFromModel
 const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
     name: 'structure-assembly-from-model',
+    display: { name: 'Structure Assembly', description: 'Create a molecular structure assembly.' },
     from: SO.Molecule.Model,
     to: SO.Molecule.Structure,
     params(a) {
@@ -102,10 +94,6 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
         return { id: PD.makeOptional(PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' })) };
     }
 })({
-    display: {
-        name: 'Structure Assembly',
-        description: 'Create a molecular structure assembly.'
-    },
     apply({ a, params }, plugin: PluginContext) {
         return Task.create('Build Assembly', async ctx => {
             let id = (params.id || '').trim();
@@ -132,17 +120,14 @@ export { StructureSelection }
 type StructureSelection = typeof StructureSelection
 const StructureSelection = PluginStateTransform.BuiltIn({
     name: 'structure-selection',
+    display: { name: 'Structure Selection', description: 'Create a molecular structure from the specified model.' },
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
-    params: () => ({
+    params: {
         query: PD.Value<Expression>(MolScriptBuilder.struct.generator.all, { isHidden: true }),
         label: PD.makeOptional(PD.Text('', { isHidden: true }))
-    })
+    }
 })({
-    display: {
-        name: 'Structure Selection',
-        description: 'Create a molecular structure from the specified model.'
-    },
     apply({ a, params }) {
         // TODO: use cache, add "update"
         const compiled = compile<Sel>(params.query);
@@ -158,14 +143,11 @@ namespace StructureComplexElement { export type Types = 'atomic-sequence' | 'wat
 type StructureComplexElement = typeof StructureComplexElement
 const StructureComplexElement = PluginStateTransform.BuiltIn({
     name: 'structure-complex-element',
+    display: { name: 'Complex Element', description: 'Create a molecular structure from the specified model.' },
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
-    params: () => ({ type: PD.Text<StructureComplexElement.Types>('atomic-sequence', { isHidden: true }) }),
+    params: { type: PD.Text<StructureComplexElement.Types>('atomic-sequence', { isHidden: true }) }
 })({
-    display: {
-        name: 'Complex Element',
-        description: 'Create a molecular structure from the specified model.'
-    },
     apply({ a, params }) {
         // TODO: update function.
 

+ 1 - 1
src/mol-plugin/state/transforms/representation.ts

@@ -17,6 +17,7 @@ export { StructureRepresentation3D }
 type StructureRepresentation3D = typeof StructureRepresentation3D
 const StructureRepresentation3D = PluginStateTransform.BuiltIn({
     name: 'structure-representation-3d',
+    display: '3D Representation',
     from: SO.Molecule.Structure,
     to: SO.Molecule.Representation3D,
     params: (a, ctx: PluginContext) => ({
@@ -38,7 +39,6 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
         )
     })
 })({
-    display: { name: '3D Representation' },
     canAutoUpdate({ oldParams, newParams }) {
         // TODO: allow for small molecules
         return oldParams.type.name === newParams.type.name;

+ 1 - 1
src/mol-plugin/ui/state-tree.tsx

@@ -162,7 +162,7 @@ class StateTreeNodeLabel extends PluginComponent<{ nodeRef: string, state: State
 
         let label: any;
         if (cell.status !== 'ok' || !cell.obj) {
-            const name = (n.transformer.definition.display && n.transformer.definition.display.name) || n.transformer.definition.name;
+            const name = n.transformer.definition.display.name;
             const title = `${cell.errorText}`
             label = <><b>{cell.status}</b> <a title={title} href='#' onClick={this.setCurrent}>{name}</a>: <i>{cell.errorText}</i></>;
         } else {

+ 0 - 1
src/mol-plugin/ui/state/apply-action.tsx

@@ -42,7 +42,6 @@ class ApplyActionContol extends TransformContolBase<ApplyActionContol.Props, App
     }
     getInfo() { return this._getInfo(this.props.nodeRef, this.props.state.transforms.get(this.props.nodeRef).version); }
     getHeader() { return this.props.action.definition.display; }
-    getHeaderFallback() { return this.props.action.id; }
     canApply() { return !this.state.error && !this.state.busy; }
     canAutoApply() { return false; }
     applyText() { return 'Apply'; }

+ 1 - 2
src/mol-plugin/ui/state/common.tsx

@@ -99,7 +99,6 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState
     abstract applyAction(): Promise<void>;
     abstract getInfo(): StateTransformParameters.Props['info'];
     abstract getHeader(): Transformer.Definition['display'];
-    abstract getHeaderFallback(): string;
     abstract canApply(): boolean;
     abstract canAutoApply(newParams: any): boolean;
     abstract applyText(): string;
@@ -171,7 +170,7 @@ abstract class TransformContolBase<P, S extends TransformContolBase.ControlState
 
         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>
+                <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>{display.name}</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>}
             </div>
             {!this.state.isCollapsed && <>

+ 0 - 1
src/mol-plugin/ui/state/update-transform.tsx

@@ -29,7 +29,6 @@ class UpdateTransformContol extends TransformContolBase<UpdateTransformContol.Pr
     applyAction() { return this.plugin.updateTransform(this.props.state, this.props.transform.ref, this.state.params); }
     getInfo() { return this._getInfo(this.props.transform); }
     getHeader() { return this.props.transform.transformer.definition.display; }
-    getHeaderFallback() { return this.props.transform.transformer.definition.name; }
     canApply() { return !this.state.error && !this.state.busy && !this.state.isInitial; }
     applyText() { return this.canApply() ? 'Update' : 'Nothing to Update'; }
     isUpdate() { return true; }

+ 9 - 4
src/mol-state/action.ts

@@ -39,8 +39,6 @@ namespace StateAction {
     }
 
     export interface DefinitionBase<A extends StateObject = StateObject, T = any, P extends {} = {}> {
-        readonly display?: { readonly name: string, readonly description?: string },
-
         /**
          * Apply an action that modifies the State specified in Params.
          */
@@ -52,6 +50,7 @@ namespace StateAction {
 
     export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> extends DefinitionBase<A, T, P> {
         readonly from: StateObject.Ctor[],
+        readonly display: { readonly name: string, readonly description?: string },
         params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any }
     }
 
@@ -80,7 +79,8 @@ namespace StateAction {
     export namespace Builder {
         export interface Type<A extends StateObject.Ctor, P extends { }> {
             from?: A | A[],
-            params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>)
+            params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>),
+            display?: string | { name: string, description?: string }
         }
 
         export interface Root {
@@ -88,7 +88,7 @@ namespace StateAction {
         }
 
         export interface Define<A extends StateObject, P> {
-            <T>(def: DefinitionBase<A, T, P>): StateAction<A, T, P>
+            <T>(def: DefinitionBase<A, T, P>): StateAction<A, T, P>,
         }
 
         function root(info: Type<any, any>): Define<any, any> {
@@ -96,6 +96,11 @@ namespace StateAction {
                 from: info.from instanceof Array
                     ? info.from
                     : !!info.from ? [info.from] : [],
+                display: typeof info.display === 'string'
+                    ? { name: info.display }
+                    : !!info.display
+                    ? info.display
+                    : { name: 'Unnamed State Action' },
                 params: typeof info.params === 'object'
                     ? () => info.params as any
                     : !!info.params

+ 10 - 3
src/mol-state/transformer.ts

@@ -9,6 +9,7 @@ import { StateObject } from './object';
 import { Transform } from './transform';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { StateAction } from './action';
+import { capitalize } from 'mol-util/string';
 
 export interface Transformer<A extends StateObject = StateObject, B extends StateObject = StateObject, P extends {} = {}> {
     apply(parent: Transform.Ref, params?: P, props?: Partial<Transform.Options>): Transform<A, B, P>,
@@ -57,8 +58,6 @@ export namespace Transformer {
     // export type ParamsDefinition<A extends StateObject = StateObject, P = any> = (a: A, globalCtx: unknown) => { [K in keyof P]: PD.Any }
 
     export interface DefinitionBase<A extends StateObject = StateObject, B extends StateObject = StateObject, P extends {} = {}> {
-        readonly display?: { readonly name: string, readonly description?: string },
-
         /**
          * Apply the actual transformation. It must be pure (i.e. with no side effects).
          * Returns a task that produces the result of the result directly.
@@ -89,6 +88,7 @@ export namespace Transformer {
         readonly name: string,
         readonly from: StateObject.Ctor[],
         readonly to: StateObject.Ctor[],
+        readonly display: { readonly name: string, readonly description?: string },
         params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any },
     }
 
@@ -151,7 +151,8 @@ export namespace Transformer {
             name: string,
             from: A | A[],
             to: B | B[],
-            params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>)
+            params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>),
+            display?: string | { name: string, description?: string }
         }
 
         export interface Root {
@@ -167,6 +168,11 @@ export namespace Transformer {
                 name: info.name,
                 from: info.from instanceof Array ? info.from : [info.from],
                 to: info.to instanceof Array ? info.to : [info.to],
+                display: typeof info.display === 'string'
+                    ? { name: info.display }
+                    : !!info.display
+                    ? info.display
+                    : { name: capitalize(info.name.replace(/[-]/g, ' ')) },
                 params: typeof info.params === 'object'
                     ? () => info.params as any
                     : !!info.params
@@ -189,6 +195,7 @@ export namespace Transformer {
         name: 'root',
         from: [],
         to: [],
+        display: { name: 'Root' },
         apply() { throw new Error('should never be applied'); },
         update() { return UpdateResult.Unchanged; }
     })