diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 440d3eb78d6501808bf4a355a0c75a24cd4133b1..51c5cfc6da08f2c10523aae1d5ddb8ebbd2f9f75 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -14,6 +14,7 @@ import { compile } from 'mol-script/runtime/query/compiler'; import { MolScriptBuilder } from 'mol-script/language/builder'; import { StateObject } from 'mol-state'; import { PluginContext } from 'mol-plugin/context'; +import { stringToWords } from 'mol-util/string'; export { TrajectoryFromMmCif } type TrajectoryFromMmCif = typeof TrajectoryFromMmCif @@ -90,21 +91,21 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({ to: SO.Molecule.Structure, params(a) { const model = a.data; - const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]); - return { id: PD.makeOptional(PD.Select(ids.length ? ids[0][0] : '', ids, { label: 'Asm Id', description: 'Assembly Id' })) }; + const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]); + if (!ids.length) ids.push(['deposited', 'Deposited']) + return { id: PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' }) }; } })({ apply({ a, params }, plugin: PluginContext) { return Task.create('Build Assembly', async ctx => { - let id = (params.id || '').trim(); const model = a.data; - if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id; + const id = params.id; const asm = ModelSymmetry.findAssembly(model, id); - if (id && !asm) throw new Error(`Assembly '${id}' not found`); + if (id !== 'deposited' && !asm) throw new Error(`Assembly '${id}' not found`); const base = Structure.ofModel(model); if (!asm) { - plugin.log.warn(`Model '${a.label}' has no assembly, returning default structure.`); + plugin.log.warn(`Model '${a.label}' has no assembly, returning deposited structure.`); const label = { label: a.data.label, description: structureDesc(base) }; return new SO.Molecule.Structure(base, label); } diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx index b688506b0a42d81888916002f07872f3371d92ee..8714fe2365cd9994ca4e4a3cc11f8df3192088a3 100644 --- a/src/mol-plugin/ui/controls/parameters.tsx +++ b/src/mol-plugin/ui/controls/parameters.tsx @@ -203,6 +203,7 @@ export class SelectControl extends SimpleParam<PD.Select<string | number>> { } renderControl() { return <select value={this.props.value || ''} onChange={this.onChange} disabled={this.props.isDisabled}> + {!this.props.param.options.some(e => e[0] === this.props.value) ? <option key={this.props.value} value={this.props.value}>{`Invalid Option '${this.props.value}'`}</option> : ''} {this.props.param.options.map(([value, label]) => <option key={value} value={value}>{label}</option>)} </select>; } diff --git a/src/mol-util/string.ts b/src/mol-util/string.ts index a40026c5d4e8121962b586b778b8478488ff598c..f2e8f5958ba30fd56124d1844cb478f45e1caa14 100644 --- a/src/mol-util/string.ts +++ b/src/mol-util/string.ts @@ -25,4 +25,16 @@ export const upperCase = (str: string) => str.toUpperCase() /** Uppercase the first character of each word. */ export function capitalize(str: string) { return str.toLowerCase().replace(/^\w|\s\w/g, upperCase); +} + +export function splitSnakeCase(str: string) { + return str.replace(/_/g, ' ') +} + +export function snakeCaseToWords(str: string) { + return capitalize(splitSnakeCase(str)) +} + +export function stringToWords(str: string) { + return capitalize(splitCamelCase(splitSnakeCase(str))) } \ No newline at end of file