Jelajahi Sumber

use StateBuilder.commit() instead of PluginContext.updateDataState()

David Sehnal 5 tahun lalu
induk
melakukan
6312c1f99b

+ 9 - 7
src/apps/viewer/extensions/cellpack/model.ts

@@ -321,19 +321,19 @@ async function handleHivRna(ctx: { runtime: RuntimeContext, fetch: AjaxTask }, p
 
 async function loadHivMembrane(plugin: PluginContext, runtime: RuntimeContext, state: State, params: LoadCellPackModelParams) {
     const url = `${params.baseUrl}/membranes/hiv_lipids.bcif`
-    const membrane = state.build().toRoot()
+    const membrane = await state.build().toRoot()
         .apply(StateTransforms.Data.Download, { label: 'hiv_lipids', url, isBinary: true }, { state: { isGhost: true } })
         .apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } })
         .apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } })
         .apply(StateTransforms.Model.ModelFromTrajectory, undefined, { state: { isGhost: true } })
         .apply(StateTransforms.Model.StructureFromModel)
-    await membrane.commit()
+        .commit()
 
     const membraneParams = {
         representation: params.preset.representation,
     }
 
-    await CellpackMembranePreset.apply(membrane.selector, membraneParams, plugin)
+    await CellpackMembranePreset.apply(membrane, membraneParams, plugin)
 }
 
 async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, state: State, params: LoadCellPackModelParams) {
@@ -364,10 +364,12 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat
     for (let i = 0, il = packings.length; i < il; ++i) {
         const p = { packing: i, baseUrl: params.baseUrl, ingredientFiles: params.ingredients.files }
 
-        const packing = state.build().to(cellPackBuilder.ref).apply(StructureFromCellpack, p)
-        await plugin.updateDataState(packing, { revertOnError: true });
+        const packing = await state.build()
+            .to(cellPackBuilder.ref)
+            .apply(StructureFromCellpack, p)
+            .commit({ revertOnError: true })
 
-        const structure = packing.selector.obj?.data
+        const structure = packing.obj?.data
         if (structure) {
             await CellPackInfoProvider.attach({ fetch: plugin.fetch, runtime }, structure, {
                 info: { packingsCount: packings.length, packingIndex: i }
@@ -378,7 +380,7 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat
             traceOnly: params.preset.traceOnly,
             representation: params.preset.representation,
         }
-        await CellpackPackingPreset.apply(packing.selector, packingParams, plugin)
+        await CellpackPackingPreset.apply(packing, packingParams, plugin)
     }
 }
 

+ 2 - 2
src/apps/viewer/extensions/cellpack/preset.ts

@@ -46,7 +46,7 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({
             polymer: builder.buildRepresentation<any>(update, components.polymer, { type: params.representation, typeParams: { ...typeParams, ...reprProps }, color }, { tag: 'polymer' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true })
         return { components, representations };
     }
 });
@@ -84,7 +84,7 @@ export const CellpackMembranePreset = StructureRepresentationPresetProvider({
             membrane: builder.buildRepresentation(update, components.membrane, { type: 'gaussian-surface', typeParams: { ...typeParams, ...reprProps }, color: 'uniform', colorParams: { value: ColorNames.lightgrey } }, { tag: 'all' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true })
         return { components, representations };
     }
 });

+ 7 - 7
src/mol-plugin-state/animation/built-in.ts

@@ -105,7 +105,7 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
         };
     },
     initialState: () => ({ t: 0 }),
-    async setup(params, plugin) {
+    setup(params, plugin) {
         const state = plugin.state.data;
         const root = !params.target || params.target === 'all' ? StateTransform.RootRef : params.target;
         const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D, root));
@@ -123,9 +123,9 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
 
         if (!changed) return;
 
-        return plugin.updateDataState(update, { doNotUpdateCurrent: true });
+        return update.commit({ doNotUpdateCurrent: true });
     },
-    async teardown(_, plugin) {
+    teardown(_, plugin) {
         const state = plugin.state.data;
         const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
             .withTag('animate-assembly-unwind'));
@@ -133,7 +133,7 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
 
         const update = state.build();
         for (const r of reprs) update.delete(r.transform.ref);
-        return plugin.updateDataState(update);
+        return update.commit();
     },
     async apply(animState, t, ctx) {
         const state = ctx.plugin.state.data;
@@ -190,9 +190,9 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({
 
         if (!changed) return;
 
-        return plugin.updateDataState(update, { doNotUpdateCurrent: true });
+        return update.commit({ doNotUpdateCurrent: true });
     },
-    async teardown(_, plugin) {
+    teardown(_, plugin) {
         const state = plugin.state.data;
         const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
             .withTag('animate-units-explode'));
@@ -200,7 +200,7 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({
 
         const update = state.build();
         for (const r of reprs) update.delete(r.transform.ref);
-        return plugin.updateDataState(update);
+        return update.commit();
     },
     async apply(animState, t, ctx) {
         const state = ctx.plugin.state.data;

+ 8 - 12
src/mol-plugin-state/builder/data.ts

@@ -14,29 +14,25 @@ export class DataBuilder {
         return this.plugin.state.data;
     }
 
-    async rawData(params: StateTransformer.Params<RawData>, options?: Partial<StateTransform.Options>) {
+    rawData(params: StateTransformer.Params<RawData>, options?: Partial<StateTransform.Options>) {
         const data = this.dataState.build().toRoot().apply(RawData, params, options);
-        await this.plugin.updateDataState(data, { revertOnError: true });
-        return data.selector;
+        return data.commit({ revertOnError: true });
     }
 
-    async download(params: StateTransformer.Params<Download>, options?: Partial<StateTransform.Options>) {
+    download(params: StateTransformer.Params<Download>, options?: Partial<StateTransform.Options>) {
         const data = this.dataState.build().toRoot().apply(Download, params, options);
-        await this.plugin.updateDataState(data, { revertOnError: true });
-        return data.selector;
+        return data.commit({ revertOnError: true });
     }
 
-    async downloadBlob(params: StateTransformer.Params<DownloadBlob>, options?: Partial<StateTransform.Options>) {
+    downloadBlob(params: StateTransformer.Params<DownloadBlob>, options?: Partial<StateTransform.Options>) {
         const data = this.dataState.build().toRoot().apply(DownloadBlob, params, options);
-        await this.plugin.updateDataState(data, { revertOnError: true });
-        return data.selector;
+        return data.commit({ revertOnError: true });
     }
 
     async readFile(params: StateTransformer.Params<ReadFile>, options?: Partial<StateTransform.Options>) {
-        const data = this.dataState.build().toRoot().apply(ReadFile, params, options);
+        const data = await this.dataState.build().toRoot().apply(ReadFile, params, options).commit({ revertOnError: true });
         const fileInfo = getFileInfo(params.file || '');
-        await this.plugin.updateDataState(data, { revertOnError: true });
-        return { data: data.selector, fileInfo };
+        return { data: data, fileInfo };
     }
 
     constructor(public plugin: PluginContext) {

+ 17 - 24
src/mol-plugin-state/builder/structure.ts

@@ -32,21 +32,20 @@ export class StructureBuilder {
         return trajectory;
     }
 
-    private async parseTrajectoryBlob(data: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>) {
+    private parseTrajectoryBlob(data: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>) {
         const state = this.dataState;
         const trajectory = state.build().to(data)
             .apply(StateTransforms.Data.ParseBlob, params, { state: { isGhost: true } })
             .apply(StateTransforms.Model.TrajectoryFromBlob, void 0);
-        await this.plugin.updateDataState(trajectory, { revertOnError: true });
-        return trajectory.selector;
+        return trajectory.commit({ revertOnError: true });
     }
 
     readonly hierarchy = new TrajectoryHierarchyBuilder(this.plugin);
     readonly representation = new StructureRepresentationBuilder(this.plugin);
 
-    async parseTrajectory(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: BuiltInTrajectoryFormat | TrajectoryFormatProvider): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
-    async parseTrajectory(blob: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
-    async parseTrajectory(data: StateObjectRef, params: any) {
+    parseTrajectory(data: StateObjectRef<SO.Data.Binary | SO.Data.String>, format: BuiltInTrajectoryFormat | TrajectoryFormatProvider): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
+    parseTrajectory(blob: StateObjectRef<SO.Data.Blob>, params: StateTransformer.Params<StateTransforms['Data']['ParseBlob']>): Promise<StateObjectSelector<SO.Molecule.Trajectory>>
+    parseTrajectory(data: StateObjectRef, params: any) {
         const cell = StateObjectRef.resolveAndCheck(this.dataState, data as StateObjectRef);
         if (!cell) throw new Error('Invalid data cell.');
 
@@ -57,24 +56,22 @@ export class StructureBuilder {
         }
     }
 
-    async createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>, initialState?: Partial<StateTransform.State>) {
+    createModel(trajectory: StateObjectRef<SO.Molecule.Trajectory>, params?: StateTransformer.Params<StateTransforms['Model']['ModelFromTrajectory']>, initialState?: Partial<StateTransform.State>) {
         const state = this.dataState;
         const model = state.build().to(trajectory)
             .apply(StateTransforms.Model.ModelFromTrajectory, params || { modelIndex: 0 }, { state: initialState });
 
-        await this.plugin.updateDataState(model, { revertOnError: true });
-        return model.selector;
+        return model.commit({ revertOnError: true });
     }
 
-    async insertModelProperties(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Model']['CustomModelProperties']>, initialState?: Partial<StateTransform.State>) {
+    insertModelProperties(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Model']['CustomModelProperties']>, initialState?: Partial<StateTransform.State>) {
         const state = this.dataState;
         const props = state.build().to(model)
             .apply(StateTransforms.Model.CustomModelProperties, params, { state: initialState });
-        await this.plugin.updateDataState(props, { revertOnError: true });
-        return props.selector;
+        return props.commit({ revertOnError: true });
     }
 
-    async tryCreateUnitcell(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Representation']['ModelUnitcell3D']>, initialState?: Partial<StateTransform.State>) {
+    tryCreateUnitcell(model: StateObjectRef<SO.Molecule.Model>, params?: StateTransformer.Params<StateTransforms['Representation']['ModelUnitcell3D']>, initialState?: Partial<StateTransform.State>) {
         const state = this.dataState;
         const m = StateObjectRef.resolveAndCheck(state, model)?.obj?.data;
         if (!m) return;
@@ -83,11 +80,10 @@ export class StructureBuilder {
 
         const unitcell = state.build().to(model)
             .apply(StateTransforms.Representation.ModelUnitcell3D, params, { state: initialState });
-        await this.plugin.updateDataState(unitcell, { revertOnError: true });
-        return unitcell.selector;
+        return unitcell.commit({ revertOnError: true });
     }
 
-    async createStructure(modelRef: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params, initialState?: Partial<StateTransform.State>) {
+    createStructure(modelRef: StateObjectRef<SO.Molecule.Model>, params?: RootStructureDefinition.Params, initialState?: Partial<StateTransform.State>) {
         const state = this.dataState;
 
         if (!params) {
@@ -101,16 +97,14 @@ export class StructureBuilder {
         const structure = state.build().to(modelRef)
             .apply(StateTransforms.Model.StructureFromModel, { type: params || { name: 'assembly', params: { } } }, { state: initialState });
 
-        await this.plugin.updateDataState(structure, { revertOnError: true });
-        return structure.selector;
+        return structure.commit({ revertOnError: true });
     }
 
-    async insertStructureProperties(structure: StateObjectRef<SO.Molecule.Structure>, params?: StateTransformer.Params<StateTransforms['Model']['CustomStructureProperties']>) {
+    insertStructureProperties(structure: StateObjectRef<SO.Molecule.Structure>, params?: StateTransformer.Params<StateTransforms['Model']['CustomStructureProperties']>) {
         const state = this.dataState;
         const props = state.build().to(structure)
             .apply(StateTransforms.Model.CustomStructureProperties, params);
-        await this.plugin.updateDataState(props, { revertOnError: true });
-        return props.selector;
+        return props.commit({ revertOnError: true });
     }
 
     isComponentTransform(cell: StateObjectCell) {
@@ -128,13 +122,12 @@ export class StructureBuilder {
             tags: tags ? [...tags, keyTag] : [keyTag]
         });
 
-        await this.plugin.updateDataState(component);
+        await component.commit();
 
         const selector = component.selector;
 
         if (!selector.isOk || selector.cell?.obj?.data.elementCount === 0) {
-            const del = state.build().delete(selector.ref);
-            await this.plugin.updateDataState(del);
+            await state.build().delete(selector.ref).commit();
             return;
         }
 

+ 4 - 4
src/mol-plugin-state/builder/structure/representation-preset.ts

@@ -149,7 +149,7 @@ const proteinAndNucleic = StructureRepresentationPresetProvider({
             nucleic: builder.buildRepresentation(update, components.nucleic, { type: 'gaussian-surface', typeParams, color }, { tag: 'nucleic' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true });
         return { components, representations };
     }
 });
@@ -190,7 +190,7 @@ const coarseSurface = StructureRepresentationPresetProvider({
             polymer: builder.buildRepresentation(update, components.polymer, { type: 'gaussian-surface', typeParams: { ...typeParams, ...gaussianProps }, color }, { tag: 'polymer' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true });
         return { components, representations };
     }
 });
@@ -215,7 +215,7 @@ const polymerCartoon = StructureRepresentationPresetProvider({
             polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams, color }, { tag: 'polymer' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true });
         return { components, representations };
     }
 });
@@ -240,7 +240,7 @@ const atomicDetail = StructureRepresentationPresetProvider({
             all: builder.buildRepresentation(update, components.all, { type: 'ball-and-stick', typeParams, color }, { tag: 'all' })
         };
 
-        await plugin.updateDataState(update, { revertOnError: true });
+        await update.commit({ revertOnError: true });
         return { components, representations };
     }
 });

+ 1 - 1
src/mol-plugin-state/builder/structure/representation.ts

@@ -117,7 +117,7 @@ export class StructureRepresentationBuilder {
         const selector = this.buildRepresentation(repr, structure, props, options);
         if (!selector) return;
 
-        await this.plugin.updateDataState(repr);
+        await repr.commit();
         return selector;
     }
 

+ 1 - 1
src/mol-plugin-state/formats/shape.ts

@@ -22,7 +22,7 @@ export const PlyProvider = DataFormatProvider({
 
         const shape = format.apply(StateTransforms.Model.ShapeFromPly);
 
-        await plugin.updateDataState(format);
+        await format.commit();
 
         return { format: format.selector, shape: shape.selector };
     }

+ 3 - 5
src/mol-plugin-state/formats/structure.ts

@@ -21,7 +21,7 @@ export const PsfProvider = DataFormatProvider({
             .apply(StateTransforms.Data.ParsePsf, {}, { state: { isGhost: true } });
         const topology = format.apply(StateTransforms.Model.TopologyFromPsf);
 
-        await plugin.updateDataState(format);
+        await format.commit();
 
         return { format: format.selector, topology: topology.selector };
     }
@@ -32,14 +32,12 @@ export const DcdProvider = DataFormatProvider({
     description: 'DCD',
     category: Category,
     binaryExtensions: ['dcd'],
-    parse: async (plugin, data) => {
+    parse: (plugin, data) => {
         const coordinates = plugin.state.data.build()
             .to(data)
             .apply(StateTransforms.Model.CoordinatesFromDcd);
 
-        await plugin.updateDataState(coordinates);
-
-        return { coordinates: coordinates.selector };
+        return coordinates.commit();
     }
 });
 

+ 14 - 9
src/mol-plugin-state/formats/trajectory.ts

@@ -37,12 +37,15 @@ export const MmcifProvider: TrajectoryFormatProvider = {
         const state = plugin.state.data;
         const cif = state.build().to(data)
             .apply(StateTransforms.Data.ParseCif, void 0, { state: { isGhost: true } })
-        const trajectory = cif.apply(StateTransforms.Model.TrajectoryFromMmCif, void 0, { tags: params?.trajectoryTags })
-        await plugin.updateDataState(trajectory, { revertOnError: true });
+        const trajectory = await cif
+            .apply(StateTransforms.Model.TrajectoryFromMmCif, void 0, { tags: params?.trajectoryTags })
+            .commit({ revertOnError: true });
+
         if ((cif.selector.cell?.obj?.data.blocks.length || 0) > 1) {
             plugin.state.data.updateCellState(cif.ref, { isGhost: false });
         }
-        return { trajectory: trajectory.selector };
+
+        return { trajectory };
     },
     visuals: defaultVisuals
 }
@@ -60,12 +63,14 @@ export const CifCoreProvider: TrajectoryFormatProvider = {
         const state = plugin.state.data;
         const cif = state.build().to(data)
             .apply(StateTransforms.Data.ParseCif, void 0, { state: { isGhost: true } })
-        const trajectory = cif.apply(StateTransforms.Model.TrajectoryFromCifCore, void 0, { tags: params?.trajectoryTags })
-        await plugin.updateDataState(trajectory, { revertOnError: true });
+        const trajectory = await cif
+            .apply(StateTransforms.Model.TrajectoryFromCifCore, void 0, { tags: params?.trajectoryTags })
+            .commit({ revertOnError: true });
+
         if ((cif.selector.cell?.obj?.data.blocks.length || 0) > 1) {
             plugin.state.data.updateCellState(cif.ref, { isGhost: false });
         }
-        return { trajectory: trajectory.selector };
+        return { trajectory };
     },
     visuals: defaultVisuals
 }
@@ -73,10 +78,10 @@ export const CifCoreProvider: TrajectoryFormatProvider = {
 function directTrajectory(transformer: StateTransformer<PluginStateObject.Data.String | PluginStateObject.Data.Binary, PluginStateObject.Molecule.Trajectory>): TrajectoryFormatProvider['parse'] {
     return async (plugin, data, params) => {
         const state = plugin.state.data;
-        const trajectory = state.build().to(data)
+        const trajectory = await state.build().to(data)
             .apply(transformer, void 0, { tags: params?.trajectoryTags })
-        await plugin.updateDataState(trajectory, { revertOnError: true });
-        return { trajectory: trajectory.selector };
+            .commit({ revertOnError: true });
+        return { trajectory };
     }
 }
 

+ 1 - 2
src/mol-plugin-state/formats/volume.ts

@@ -18,8 +18,7 @@ const Category = 'Volume';
 
 async function defaultVisuals(plugin: PluginContext, data: { volume: StateObjectSelector<PluginStateObject.Volume.Data> }) {
     const visual = plugin.build().to(data.volume).apply(StateTransforms.Representation.VolumeRepresentation3D);
-    await visual.commit();
-    return [visual];
+    return [await visual.commit()];
 }
 
 export const Ccp4Provider = DataFormatProvider({

+ 2 - 2
src/mol-plugin-state/helpers/structure-overpaint.ts

@@ -55,7 +55,7 @@ export async function clearStructureOverpaint(plugin: PluginContext, components:
     });
 }
 
-async function eachRepr(plugin: PluginContext, components: StructureComponentRef[], callback: OverpaintEachReprCallback) {
+function eachRepr(plugin: PluginContext, components: StructureComponentRef[], callback: OverpaintEachReprCallback) {
     const state = plugin.state.data;
     const update = state.build();
     for (const c of components) {
@@ -65,7 +65,7 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef
         }
     }
 
-    await plugin.updateDataState(update, { doNotUpdateCurrent: true });
+    return update.commit({ doNotUpdateCurrent: true });
 }
 
 /** filter overpaint layers for given structure */

+ 11 - 11
src/mol-plugin-state/manager/structure/component.ts

@@ -60,7 +60,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
         }
 
         return this.plugin.dataTransaction(async () => {
-            await this.plugin.updateDataState(update);
+            await update.commit();
             if (interactionChanged) await this.updateInterationProps();
         });
     }
@@ -89,11 +89,11 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
                 const oldParams = s.properties.cell.transform.params?.properties[InteractionsProvider.descriptor.name];
                 if (PD.areEqual(interactionParams, oldParams, this.state.options.interactions)) continue;
 
-                const b = this.dataState.build();
-                b.to(s.properties.cell).update(old => {
-                    old.properties[InteractionsProvider.descriptor.name] = this.state.options.interactions;
-                });
-                await this.plugin.updateDataState(b);
+                await this.dataState.build().to(s.properties.cell)
+                    .update(old => {
+                        old.properties[InteractionsProvider.descriptor.name] = this.state.options.interactions;
+                    })
+                    .commit();
             } else {
                 const pd = this.plugin.customStructureProperties.getParams(s.cell.obj?.data);
                 const params = PD.getDefaultValues(pd);
@@ -113,7 +113,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
         }, { canUndo: 'Preset' });
     }
 
-    private async syncPreset(root: StructureRef, preset?: StructureRepresentationPresetProvider.Result) {
+    private syncPreset(root: StructureRef, preset?: StructureRepresentationPresetProvider.Result) {
         if (!preset || !preset.components) return this.clearComponents([root]);
 
         const keptRefs = new Set<string>();
@@ -153,7 +153,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
             }
         }
 
-        if (changed) return this.plugin.updateDataState(update);
+        if (changed) return update.commit();
     }
 
     clear(structures: ReadonlyArray<StructureRef>) {
@@ -247,7 +247,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
             update.to(repr.cell).update(params);
         }
 
-        return this.plugin.updateDataState(update, { canUndo: 'Update Representation' });
+        return update.commit({ canUndo: 'Update Representation' });
     }
 
     /**
@@ -288,7 +288,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
             }
         }
 
-        return this.plugin.updateDataState(update, { canUndo: 'Update Theme' });
+        return update.commit({ canUndo: 'Update Theme' });
     }
 
     addRepresentation(components: ReadonlyArray<StructureComponentRef>, type: string) {
@@ -384,7 +384,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
                 deletes.delete(c.cell.transform.ref);
             }
         }
-        return this.plugin.updateDataState(deletes, { canUndo: 'Clear Selections' });
+        return deletes.commit({ canUndo: 'Clear Selections' });
     }
 
     constructor(public plugin: PluginContext) {

+ 2 - 2
src/mol-plugin-state/manager/structure/hierarchy.ts

@@ -155,7 +155,7 @@ export class StructureHierarchyManager extends PluginComponent {
         if (refs.length === 0) return;
         const deletes = this.plugin.state.data.build();
         for (const r of refs) deletes.delete(typeof r === 'string' ? r : r.cell.transform.ref);
-        return this.plugin.updateDataState(deletes, { canUndo: canUndo ? 'Remove' : false });
+        return deletes.commit({ canUndo: canUndo ? 'Remove' : false });
     }
 
     toggleVisibility(refs: ReadonlyArray<HierarchyRef>, action?: 'show' | 'hide') {
@@ -196,7 +196,7 @@ export class StructureHierarchyManager extends PluginComponent {
         for (const m of trajectory.models) {
             builder.delete(m.cell);
         }
-        return this.plugin.updateDataState(builder);
+        return builder.commit();
     }
 
     constructor(private plugin: PluginContext) {

+ 2 - 3
src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts

@@ -188,10 +188,9 @@ export const AssemblySymmetryPreset = StructureRepresentationPresetProvider({
     }
 });
 
-export async function tryCreateAssemblySymmetry(plugin: PluginContext, structure: StateObjectRef<PluginStateObject.Molecule.Structure>, params?: StateTransformer.Params<AssemblySymmetry3D>, initialState?: Partial<StateTransform.State>) {
+export function tryCreateAssemblySymmetry(plugin: PluginContext, structure: StateObjectRef<PluginStateObject.Molecule.Structure>, params?: StateTransformer.Params<AssemblySymmetry3D>, initialState?: Partial<StateTransform.State>) {
     const state = plugin.state.data;
     const assemblySymmetry = state.build().to(structure)
         .applyOrUpdateTagged(AssemblySymmetry.Tag.Representation, AssemblySymmetry3D, params, { state: initialState });
-    await plugin.updateDataState(assemblySymmetry, { revertOnError: true });
-    return assemblySymmetry.selector
+    return assemblySymmetry.commit({ revertOnError: true });
 }

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props/rcsb/ui/assembly-symmetry.tsx

@@ -96,7 +96,7 @@ export class AssemblySymmetryControls extends CollapsableControls<{}, AssemblySy
             b.to(s.properties.cell).update(old => {
                 old.properties[AssemblySymmetryProvider.descriptor.name] = values;
             });
-            await this.plugin.updateDataState(b);
+            await b.commit();
         } else {
             const pd = this.plugin.customStructureProperties.getParams(s.cell.obj?.data);
             const params = PD.getDefaultValues(pd);

+ 1 - 1
src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts

@@ -329,7 +329,7 @@ export const ValidationReportGeometryQualityPreset = StructureRepresentationPres
             clashesSnfg3d = builder.buildRepresentation<any>(update, clashes, { type: ClashesRepresentationProvider.name, typeParams, color }, { tag: 'clashes-snfg-3d' });
         }
 
-        await plugin.updateDataState(update, { revertOnError: false });
+        await update.commit({ revertOnError: true });
         return { components: { ...components, clashes }, representations: { ...representations, clashesBallAndStick, clashesSnfg3d } };
     }
 });

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

@@ -99,7 +99,7 @@ export const InitVolumeStreaming = StateAction.build({
             entries
         });
 
-    await plugin.updateDataState(infoTree);
+    await infoTree.commit();
 
     const info = infoTree.selector;
     if (!info.isOk) return;

+ 3 - 7
src/mol-plugin/context.ts

@@ -13,6 +13,7 @@ import { CustomProperty } from '../mol-model-props/common/custom-property';
 import { Model, Structure } from '../mol-model/structure';
 import { DataBuilder } from '../mol-plugin-state/builder/data';
 import { StructureBuilder } from '../mol-plugin-state/builder/structure';
+import { DataFormatRegistry } from '../mol-plugin-state/formats/registry';
 import { StructureSelectionQueryRegistry } from '../mol-plugin-state/helpers/structure-selection-query';
 import { CameraManager } from '../mol-plugin-state/manager/camera';
 import { InteractivityManager } from '../mol-plugin-state/manager/interactivity';
@@ -28,7 +29,7 @@ import { StateTransformParameters } from '../mol-plugin-ui/state/common';
 import { Representation } from '../mol-repr/representation';
 import { StructureRepresentationRegistry } from '../mol-repr/structure/registry';
 import { VolumeRepresentationRegistry } from '../mol-repr/volume/registry';
-import { State, StateBuilder, StateTree, StateTransform } from '../mol-state';
+import { StateTransform } from '../mol-state';
 import { Progress, Task } from '../mol-task';
 import { ColorTheme } from '../mol-theme/color';
 import { SizeTheme } from '../mol-theme/size';
@@ -43,7 +44,7 @@ import { BuiltInPluginBehaviors } from './behavior';
 import { PluginBehavior } from './behavior/behavior';
 import { PluginCommandManager } from './command';
 import { PluginCommands } from './commands';
-import { PluginConfigManager, PluginConfig } from './config';
+import { PluginConfig, PluginConfigManager } from './config';
 import { LeftPanelTabName, PluginLayout } from './layout';
 import { PluginSpec } from './spec';
 import { PluginState } from './state';
@@ -52,7 +53,6 @@ import { TaskManager } from './util/task-manager';
 import { PluginToastManager } from './util/toast';
 import { ViewportScreenshotHelper } from './util/viewport-screenshot';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
-import { DataFormatRegistry } from '../mol-plugin-state/formats/registry';
 
 export class PluginContext {
     runTask = <T>(task: Task<T>) => this.tasks.run(task);
@@ -223,10 +223,6 @@ export class PluginContext {
         return this.runTask(this.state.data.transaction(f, options));
     }
 
-    updateDataState(tree: StateTree | StateBuilder, options?: Partial<State.UpdateOptions>) {
-        return this.runTask(this.state.data.updateTree(tree, options));
-    }
-
     requestTaskAbort(progress: Progress, reason?: string) {
         this.tasks.requestAbort(progress, reason);
     }

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

@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { StateObject, StateObjectCell } from './object';
+import { StateObject, StateObjectCell, StateObjectSelector } from './object';
 import { StateTree } from './tree';
 import { StateTransform } from './transform';
 import { StateTransformer } from './transformer';
@@ -234,7 +234,7 @@ class State {
      * @param tree Tree instance or a tree builder instance
      * @param doNotReportTiming Indicates whether to log timing of the individual transforms
      */
-    updateTree<T extends StateObject>(tree: StateBuilder.To<T, any>, options?: Partial<State.UpdateOptions>): Task<StateObjectCell<T>>
+    updateTree<T extends StateObject>(tree: StateBuilder.To<T, any>, options?: Partial<State.UpdateOptions>): Task<StateObjectSelector<T>>
     updateTree(tree: StateTree | StateBuilder, options?: Partial<State.UpdateOptions>): Task<void>
     updateTree(tree: StateTree | StateBuilder, options?: Partial<State.UpdateOptions>): Task<any> {
         const params: UpdateParams = { tree, options };
@@ -257,7 +257,9 @@ class State {
 
                 if (ret.ctx.hadError) this.inTransactionError = true;
 
-                return ret.cell;
+                if (!ret.cell) return;
+
+                return new StateObjectSelector(ret.cell.transform.ref, this);
             } finally {
                 this._inUpdate = false;
                 this.updateQueue.handled(params);

+ 2 - 1
src/mol-state/state/builder.ts

@@ -258,7 +258,8 @@ namespace StateBuilder {
 
         getTree(): StateTree { return buildTree(this.state); }
 
-        commit(options?: Partial<State.UpdateOptions>): Promise<StateObjectCell<A>> {
+        /** Returns selector to this node. */
+        commit(options?: Partial<State.UpdateOptions>): Promise<StateObjectSelector<A>> {
             if (!this.state.state) throw new Error('Cannot commit template tree');
             return this.state.state.runTask(this.state.state.updateTree(this, options));
         }