/** * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sebastian Bittrich */ import { CollapsableControls, CollapsableState } from 'molstar/lib/mol-plugin-ui/base'; import { StructureHierarchyManager } from 'molstar/lib/mol-plugin-state/manager/structure/hierarchy'; import { ValidationReport } from 'molstar/lib/extensions/rcsb/validation-report/prop'; import { ValidationReportGeometryQualityPreset } from 'molstar/lib/extensions/rcsb/validation-report/behavior'; import { ActionMenu } from 'molstar/lib/mol-plugin-ui/controls/action-menu'; import { Model } from 'molstar/lib/mol-model/structure/model'; import { MmcifFormat } from 'molstar/lib/mol-model-formats/structure/mmcif'; import { AlphaFoldConfidence } from '../helpers/af-confidence/prop'; import { AlphaFoldConfidenceColorThemeProvider } from '../helpers/af-confidence/color'; interface ValidationReportState extends CollapsableState { errorStates: Set } const ValidationReportTag = 'validation-report'; const _QualityIcon = ; export function QualityIconSvg() { return _QualityIcon; } /** * A high-level component that gives access to the validation report preset. */ export class ValidationReportControls extends CollapsableControls<{}, ValidationReportState> { protected defaultState() { return { header: 'Quality Assessment', isCollapsed: false, isHidden: true, errorStates: new Set(), brand: { accent: 'cyan' as const, svg: QualityIconSvg } }; } componentDidMount() { this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, () => { const { errorStates, description } = this.state; const nextDescription = StructureHierarchyManager.getSelectedStructuresDescription(this.plugin); this.setState({ isHidden: !this.canEnable(), // if structure is unchanged then keep old error states errorStates: nextDescription === description ? errorStates : new Set(), description: nextDescription }); }); } get pivot() { return this.plugin.managers.structure.hierarchy.selection.structures[0]; } canEnable() { const { selection } = this.plugin.managers.structure.hierarchy; if (selection.structures.length !== 1) return false; const pivot = this.pivot.cell; if (!pivot.obj || pivot.obj.data.models.length !== 1) return false; const model = pivot.obj.data.models[0]; // all supported options must be registered here return ValidationReport.isApplicable(model) || AlphaFoldConfidence.isApplicable(model); } get noValidationReport() { const structure = this.pivot.cell.obj?.data; if (!structure || structure.models.length !== 1) return true; const model = structure.models[0]; return !model || !this.isFromPdbArchive(model); } get alphaFoldData() { const structure = this.pivot.cell.obj?.data; if (!structure || structure.models.length !== 1) return false; const model = structure.models[0]; return AlphaFoldConfidence.isApplicable(model); } isFromPdbArchive(model: Model) { if (!MmcifFormat.is(model.sourceData)) return false; return model.entryId.match(/^[1-9][a-z0-9]{3}$/i) !== null || model.entryId.match(/^pdb_[0-9]{4}[1-9][a-z0-9]{3}$/i) !== null; } requestValidationReportPreset = async () => { try { await ValidationReportGeometryQualityPreset.apply(this.pivot.cell, Object.create(null), this.plugin); } catch (err) { // happens e.g. for 2W4S this.setState(({ errorStates }) => { const errors = new Set(errorStates); errors.add(ValidationReportTag); return { errorStates: errors }; }); } }; requestAlphaFoldConfidenceColoring = async () => { await this.plugin.managers.structure.component.updateRepresentationsTheme(this.pivot.components, { color: AlphaFoldConfidenceColorThemeProvider.name as any }); }; get actions(): ActionMenu.Items { const noValidationReport = this.noValidationReport; const validationReportError = this.state.errorStates.has(ValidationReportTag); const out: ActionMenu.Items = [ { kind: 'item', label: validationReportError ? 'Failed to Obtain Validation Report' : (noValidationReport ? 'No Validation Report Available' : 'RCSB PDB Validation Report'), value: this.requestValidationReportPreset, disabled: noValidationReport || validationReportError }, ]; if (this.alphaFoldData) { out.push({ kind: 'item', label: 'AlphaFold Confidence Scores', value: this.requestAlphaFoldConfidenceColoring }); } return out; } selectAction: ActionMenu.OnSelect = item => { if (!item) return; (item?.value as any)(); }; renderControls() { return ; } }