Browse Source

mol-state & volume streaming updates
- error cells are no longer considered valid update roots
- volume streaming now better handles initialization errors

David Sehnal 5 years ago
parent
commit
1b0a310fc7

+ 11 - 5
src/mol-plugin-ui/structure/volume.tsx

@@ -6,7 +6,7 @@
  */
 
 import * as React from 'react';
-import { InitVolumeStreaming, CreateVolumeStreamingInfo } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
+import { InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
 import { CollapsableControls, CollapsableState } from '../base';
 import { ApplyActionControl } from '../state/apply-action';
 import { UpdateTransformControl } from '../state/update-transform';
@@ -14,7 +14,8 @@ import { BindingsHelp } from '../viewport/help';
 import { ExpandGroup } from '../controls/common';
 import { StructureHierarchyManager } from '../../mol-plugin-state/manager/structure/hierarchy';
 import { FocusLoci } from '../../mol-plugin/behavior/dynamic/representation';
-import { StateSelection } from '../../mol-state';
+import { StateSelection, StateTransform } from '../../mol-state';
+import { VolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/behavior';
 
 interface VolumeStreamingControlState extends CollapsableState {
     isBusy: boolean
@@ -39,6 +40,9 @@ export class VolumeStreamingControls extends CollapsableControls<{}, VolumeStrea
                 description: StructureHierarchyManager.getSelectedStructuresDescription(this.plugin)
             })
         });
+        this.subscribe(this.plugin.events.state.cell.stateUpdated, e => {
+            if (StateTransform.hasTag(e.cell.transform, VolumeStreaming.RootTag)) this.forceUpdate();
+        });
         this.subscribe(this.plugin.behaviors.state.isBusy, v => {
             this.setState({ isBusy: v })
         });
@@ -58,9 +62,11 @@ export class VolumeStreamingControls extends CollapsableControls<{}, VolumeStrea
 
     renderEnable() {
         const pivot = this.pivot;
-        const errored = this.plugin.state.data.select(StateSelection.Generators.ofTransformerWithError(CreateVolumeStreamingInfo, pivot.cell.transform.ref))[0];
-        const simpleApply = errored
-            ? { header: 'Error enabling', icon: 'alert' as const, title: errored.errorText }
+        const root = StateSelection.findTagInSubtree(this.pivot.cell.parent.tree, this.pivot.cell.transform.ref, VolumeStreaming.RootTag);
+        const rootCell = root && this.pivot.cell.parent.cells.get(root);
+
+        const simpleApply = rootCell && rootCell.status === 'error'
+            ? { header: 'Error enabling', icon: 'alert' as const, title: rootCell.errorText }
             : { header: 'Enable', icon: 'check' as const, title: 'Enable' }
 
         return <ApplyActionControl state={pivot.cell.parent} action={InitVolumeStreaming} initiallyCollapsed={true} nodeRef={pivot.cell.transform.ref} simpleApply={simpleApply} />;

+ 1 - 0
src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts

@@ -27,6 +27,7 @@ import { EmptyLoci, Loci, isEmptyLoci } from '../../../../mol-model/loci';
 export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
 
 export namespace VolumeStreaming {
+    export const RootTag = 'volume-streaming-info'
 
     export interface ChannelParams {
         isoValue: VolumeIsoValue,

+ 11 - 2
src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts

@@ -94,12 +94,21 @@ export const InitVolumeStreaming = StateAction.build({
     }
 
     const infoTree = state.build().to(ref)
-        .apply(CreateVolumeStreamingInfo, {
+        .applyOrUpdateTagged(VolumeStreaming.RootTag, CreateVolumeStreamingInfo, {
             serverUrl: params.options.serverUrl,
             entries
         });
 
-    const infoObj = await state.updateTree(infoTree).runInContext(taskCtx);
+    await plugin.updateDataState(infoTree);
+
+    const info = infoTree.selector;
+    if (!info.isOk) return;
+
+    // clear the children in case there were errors
+    const children = state.tree.children.get(info.ref);
+    if (children?.size > 0) await plugin.managers.structure.hierarchy.remove(children?.toArray());
+
+    const infoObj = info.cell!.obj!;
 
     const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior,
         PD.getDefaultValues(VolumeStreaming.createParams({ data: infoObj.data, defaultView: params.defaultView, channelParams: params.options.channelParams })),

+ 11 - 5
src/mol-state/state.ts

@@ -171,6 +171,7 @@ class State {
     }
 
     private inTransaction = false;
+    private inTransactionError = false;
 
     /** Apply series of updates to the state. If any of them fail, revert to the original state. */
     transaction(edits: () => Promise<void> | void, options?: { canUndo?: string | boolean }) {
@@ -183,12 +184,12 @@ class State {
             let restored = false;
             try {
                 if (!isNested) this.behaviors.isUpdating.next(true);
+
                 this.inTransaction = true;
+                this.inTransactionError = false;
                 await edits();
 
-                let hasError = false;
-                this.cells.forEach(c => hasError = hasError || c.state === 'error');
-                if (hasError) {
+                if (this.inTransactionError) {
                     restored = true;
                     await this.updateTree(snapshot).runInContext(ctx);
                 }
@@ -198,7 +199,10 @@ class State {
                     await this.updateTree(snapshot).runInContext(ctx);
                     this.events.log.error(e);
                 }
-                if (isNested) throw e;
+                if (isNested) {
+                    this.inTransactionError = true;
+                    throw e;
+                }
             } finally {
                 if (!isNested) {
                     this.inTransaction = false;
@@ -240,6 +244,8 @@ class State {
                     : await this._updateTree(taskCtx, params);
                 reverted = this.reverted;
 
+                if (ret.ctx.hadError) this.inTransactionError = true;
+
                 return ret.cell;
             } finally {
                 this.updateQueue.handled(params);
@@ -537,7 +543,7 @@ function findUpdateRoots(cells: Map<StateTransform.Ref, StateObjectCell>, tree:
 function findUpdateRootsVisitor(n: StateTransform, _: any, s: { roots: Ref[], cells: Map<Ref, StateObjectCell> }) {
     const cell = s.cells.get(n.ref);
     if (!cell || cell.transform.version !== n.version || cell.status === 'error') {
-        s.roots.push(n.ref);
+        if (cell?.status !== 'error') s.roots.push(n.ref);
         return false;
     }
     // nothing below a Null object can be an update root