diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 5fdfdbc2ca4eea7ad4c06db994742426cbc10ad1..4fdbf9adbd4f7c697c51677371c10583446576b6 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -18,10 +18,10 @@ export const CreateStructureFromPDBe = StateAction.create<PluginStateObject.Root }, params: { default: () => ({ id: '1grm' }), - controls: () => ({ + definition: () => ({ id: PD.Text('PDB id', '', '1grm'), }), - validate: p => !p.id || !p.id.trim() ? ['Enter id.'] : void 0 + validate: p => !p.id || !p.id.trim() ? [['Enter id.', 'id']] : void 0 }, apply({ params, state }) { const url = `http://www.ebi.ac.uk/pdbe/static/entry/${params.id.toLowerCase()}_updated.cif`; diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts index a3379657811969c19913feae848307dc058f74b5..2f3e631cf59919520481560d1f8dfa9bc3fc5eff 100644 --- a/src/mol-plugin/state/transforms/data.ts +++ b/src/mol-plugin/state/transforms/data.ts @@ -26,12 +26,12 @@ const Download = PluginStateTransform.Create<SO.Root, SO.Data.String | SO.Data.B default: () => ({ url: 'https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif' }), - controls: () => ({ + definition: () => ({ url: PD.Text('URL', 'Resource URL. Must be the same domain or support CORS.', ''), label: PD.Text('Label', '', ''), isBinary: PD.Boolean('Binary', 'If true, download data as binary (string otherwise)', false) }), - validate: p => !p.url || !p.url.trim() ? ['Enter url.'] : void 0 + validate: p => !p.url || !p.url.trim() ? [['Enter url.', 'url']] : void 0 }, apply({ params: p }, globalCtx: PluginContext) { return Task.create('Download', async ctx => { diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 93b5907132aa1f2a9675901878dca5a59ddf7479..2ad0eed9f445eeab6b1fd8bc8c0cab8c1825d7a8 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -25,7 +25,7 @@ const ParseTrajectoryFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Mol to: [SO.Molecule.Trajectory], params: { default: a => ({ blockHeader: a.data.blocks[0].header }), - controls(a) { + definition(a) { const { blocks } = a.data; if (blocks.length === 0) return {}; return { @@ -58,7 +58,7 @@ const CreateModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajec to: [SO.Molecule.Model], params: { default: () => ({ modelIndex: 0 }), - controls: a => ({ modelIndex: PD.Range('Model Index', 'Model Index', 0, 0, Math.max(0, a.data.length - 1), 1) }) + definition: a => ({ modelIndex: PD.Range('Model Index', 'Model Index', 0, 0, Math.max(0, a.data.length - 1), 1) }) }, isApplicable: a => a.data.length > 0, apply({ a, params }) { @@ -103,7 +103,7 @@ const CreateStructureAssembly = PluginStateTransform.Create<SO.Molecule.Model, S to: [SO.Molecule.Structure], params: { default: () => ({ id: void 0 }), - controls(a) { + definition(a) { const model = a.data; const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]); return { id: PD.Select('Asm Id', 'Assembly Id', ids.length ? ids[0][0] : '', ids) }; diff --git a/src/mol-plugin/ui/state/parameters.tsx b/src/mol-plugin/ui/state/parameters.tsx index 804770f15682002942091539a8ecc29ff60d8412..81f3e591508199bab726d277561c581859f9092d 100644 --- a/src/mol-plugin/ui/state/parameters.tsx +++ b/src/mol-plugin/ui/state/parameters.tsx @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { StateObject, Transformer, State, Transform, StateObjectCell } from 'mol-state'; +import { StateObject, State, Transform, StateObjectCell } from 'mol-state'; import { shallowEqual } from 'mol-util/object'; import * as React from 'react'; import { PurePluginComponent } from '../base'; @@ -17,7 +17,7 @@ export { StateTransformParameters }; class StateTransformParameters extends PurePluginComponent<StateTransformParameters.Props> { getDefinition() { - const controls = this.props.info.definition.controls; + const controls = this.props.info.definition.definition; if (!controls) return { }; return controls!(this.props.info.source, this.plugin) } @@ -25,7 +25,9 @@ class StateTransformParameters extends PurePluginComponent<StateTransformParamet validate(params: any) { const validate = this.props.info.definition.validate; if (!validate) return void 0; - return validate(params, this.props.info.source, this.plugin) + const result = validate(params, this.props.info.source, this.plugin); + if (!result || result.length === 0) return void 0; + return result.map(r => r[0]); } areInitial(params: any) { @@ -48,7 +50,7 @@ class StateTransformParameters extends PurePluginComponent<StateTransformParamet namespace StateTransformParameters { export interface Props { info: { - definition: Transformer.ParamsDefinition, + definition: PD.Provider, params: PD.Params, initialValues: any, source: StateObject, @@ -68,7 +70,7 @@ namespace StateTransformParameters { const source = state.cells.get(nodeRef)!.obj!; const definition = action.definition.params || { }; const initialValues = definition.default ? definition.default(source, plugin) : {}; - const params = definition.controls ? definition.controls(source, plugin) : {}; + const params = definition.definition ? definition.definition(source, plugin) : {}; return { source, definition: action.definition.params || { }, @@ -82,7 +84,7 @@ namespace StateTransformParameters { const cell = state.cells.get(transform.ref)!; const source: StateObjectCell | undefined = (cell.sourceRef && state.cells.get(cell.sourceRef)!) || void 0; const definition = transform.transformer.definition.params || { }; - const params = definition.controls ? definition.controls((source && source.obj) as any, plugin) : {}; + const params = definition.definition ? definition.definition((source && source.obj) as any, plugin) : {}; return { source: (source && source.obj) as any, definition, diff --git a/src/mol-state/action.ts b/src/mol-state/action.ts index ad57879c7781e64c6d8993451a01cc93c59e6565..4898eb6be775af4fb07fa6e5ab52ffad16212f7d 100644 --- a/src/mol-state/action.ts +++ b/src/mol-state/action.ts @@ -46,7 +46,7 @@ namespace StateAction { */ apply(params: ApplyParams<A, P>, globalCtx: unknown): T | Task<T>, - readonly params?: Transformer<A, any, P>['definition']['params'], + readonly params?: PD.Provider<A, P, unknown> /** Test if the transform can be applied to a given node */ isApplicable?(a: A, globalCtx: unknown): boolean diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts index 6588a55167bbc472d69cfb56a3cd1335ba8ea8bb..1bf6aaceef3ed8a28140113c1223e0bf7d56e4fe 100644 --- a/src/mol-state/transformer.ts +++ b/src/mol-state/transformer.ts @@ -47,17 +47,6 @@ export namespace Transformer { export enum UpdateResult { Unchanged, Updated, Recreate } - export interface ParamsDefinition<A extends StateObject = StateObject, P = unknown> { - /** Check the parameters and return a list of errors if the are not valid. */ - default?(a: A, globalCtx: unknown): P, - /** Specify default control descriptors for the parameters */ - controls?(a: A, globalCtx: unknown): ControlsFor<P>, - /** Check the parameters and return a list of errors if the are not valid. */ - validate?(params: P, a: A, globalCtx: unknown): string[] | undefined, - /** Optional custom parameter equality. Use deep structural equal by default. */ - areEqual?(oldParams: P, newParams: P): boolean - } - export interface Definition<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> { readonly name: string, readonly from: StateObject.Ctor[], @@ -77,7 +66,7 @@ export namespace Transformer { */ update?(params: UpdateParams<A, B, P>, globalCtx: unknown): Task<UpdateResult> | UpdateResult, - readonly params?: ParamsDefinition<A, P>, + readonly params?: PD.Provider<A, P, unknown>, /** Test if the transform can be applied to a given node */ isApplicable?(a: A, globalCtx: unknown): boolean, diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 0ebf49dd83c29c74133912ff304a2ec92ec1128f..7d3d7cdb5ca7ea0fff33824dd2ad93bf81aa465b 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -90,4 +90,21 @@ export namespace ParamDefinition { Object.keys(params).forEach(k => d[k] = params[k].defaultValue) return d as { [k in keyof T]: T[k]['defaultValue'] } } + + /** + * List of [error text, pathToValue] + * i.e. ['Missing Nested Id', ['group1', 'id']] + */ + export type ParamErrors = [string, string | string[]][] + + export interface Provider<A = any, P = any, Ctx = any> { + /** Check the parameters and return a list of errors if the are not valid. */ + default?(a: A, globalCtx: Ctx): P, + /** Specify default control descriptors for the parameters */ + definition?(a: A, globalCtx: Ctx): { [K in keyof P]?: Any }, + /** Check the parameters and return a list of errors if the are not valid. */ + validate?(params: P, a: A, globalCtx: unknown): ParamErrors | undefined, + /** Optional custom parameter equality. Use deep structural equal by default. */ + areEqual?(oldParams: P, newParams: P): boolean + } } \ No newline at end of file