diff --git a/src/mol-model-props/pdbe/structure-quality-report.ts b/src/mol-model-props/pdbe/structure-quality-report.ts index 137ea579d09ace454ac615cd4f767a65828b2a9b..4907860f4c3e45b4d74607962b63b35b201007d8 100644 --- a/src/mol-model-props/pdbe/structure-quality-report.ts +++ b/src/mol-model-props/pdbe/structure-quality-report.ts @@ -28,16 +28,17 @@ const _Descriptor = ModelPropertyDescriptor({ categories: [{ name: 'pdbe_structure_quality_report', instance(ctx) { - if (ctx.globalCache.pdbe_structure_quality_report) return CifWriter.Category.Empty; - ctx.globalCache.pdbe_structure_quality_report = true; - return { fields: _structure_quality_report_fields, rowCount: 1 } + const issues = StructureQualityReport.get(ctx.model); + if (typeof ctx.globalCache.pdbe_structure_quality_report !== 'undefined' && ctx.globalCache.pdbe_structure_quality_report !== ctx.model.modelNum) return CifWriter.Category.Empty; + ctx.globalCache.pdbe_structure_quality_report = ctx.model.modelNum; + return { fields: _structure_quality_report_fields, rowCount: 1, data: issues ? issues.updated : 'n/a' } } }, { name: 'pdbe_structure_quality_report_issues', instance(ctx) { const issues = StructureQualityReport.get(ctx.model); - if (!issues) return CifWriter.Category.Empty; - return ResidueCustomProperty.createCifCategory(ctx, issues, _structure_quality_report_issues_fields); + if (!issues || !issues.map) return CifWriter.Category.Empty; + return ResidueCustomProperty.createCifCategory(ctx, issues.map, _structure_quality_report_issues_fields); } }] }, @@ -56,8 +57,8 @@ const _structure_quality_report_issues_fields: CifField<number, ExportCtx>[] = [ CifField.str<number, ExportCtx>('issues', (i, d) => d.property(i).join(',')) ]; -const _structure_quality_report_fields: CifField<ResidueIndex, ExportCtx>[] = [ - CifField.str('updated_datetime_utc', () => `${new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')}`) +const _structure_quality_report_fields: CifField<number, string>[] = [ + CifField.str('updated_datetime_utc', (_, date) => date) ]; function createIssueMapFromJson(modelData: Model, data: any): IssueMap | undefined { @@ -98,6 +99,11 @@ function createIssueMapFromCif(modelData: Model, data: Table<typeof StructureQua } export namespace StructureQualityReport { + export interface Data { + updated: string, + map: IssueMap | undefined + } + export const Descriptor = _Descriptor; export const Schema = { @@ -118,10 +124,11 @@ export namespace StructureQualityReport { }) { if (get(model)) return true; - let issueMap; - + let issueMap, updated = `${new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')}`; if (model.sourceData.kind === 'mmCIF' && model.sourceData.frame.categoryNames.includes('pdbe_structure_quality_report')) { - const data = toTable(Schema.pdbe_structure_quality_report_issues, model.sourceData.frame.categories.pdbe_structure_quality_report); + const data = toTable(Schema.pdbe_structure_quality_report_issues, model.sourceData.frame.categories.pdbe_structure_quality_report_issues); + const f = model.sourceData.frame.categories['pdbe_structure_quality_report'].getField('updated_datetime_utc'); + updated = f ? f.str(0) : updated; issueMap = createIssueMapFromCif(model, data); } else if (params.PDBe_apiSourceJson) { const data = await params.PDBe_apiSourceJson(model); @@ -132,11 +139,14 @@ export namespace StructureQualityReport { } model.customProperties.add(Descriptor); - model._dynamicPropertyData.__StructureQualityReport__ = issueMap; + (model._dynamicPropertyData.__StructureQualityReport__ as Data) = { + updated, + map: issueMap + }; return true; } - export function get(model: Model): IssueMap | undefined { + export function get(model: Model): Data | undefined { return model._dynamicPropertyData.__StructureQualityReport__; } @@ -144,8 +154,8 @@ export namespace StructureQualityReport { export function getIssues(e: StructureElement) { if (!Unit.isAtomic(e.unit)) return _emptyArray; const issues = StructureQualityReport.get(e.unit.model); - if (!issues) return _emptyArray; + if (!issues || !issues.map) return _emptyArray; const rI = e.unit.residueIndex[e.element]; - return issues.has(rI) ? issues.get(rI)! : _emptyArray; + return issues.map.has(rI) ? issues.map.get(rI)! : _emptyArray; } } \ No newline at end of file diff --git a/src/servers/model/server/api-web.ts b/src/servers/model/server/api-web.ts index 4151a933a43d13a9dac465772a04f7346bb2f174..297a0c6436f74cdd122517eb2893d0271c099581 100644 --- a/src/servers/model/server/api-web.ts +++ b/src/servers/model/server/api-web.ts @@ -12,6 +12,7 @@ import { ConsoleLogger } from 'mol-util/console-logger'; import { resolveJob } from './query'; import { JobManager } from './jobs'; import { UUID } from 'mol-util'; +import { LandingPage } from './landing'; function makePath(p: string) { return Config.appPrefix + '/' + p; @@ -138,6 +139,10 @@ export function initWebApi(app: express.Express) { if (JobManager.size === 1) processNextJob(); }); + app.get('*', (req, res) => { + res.send(LandingPage); + }); + // for (const q of QueryList) { // mapQuery(app, q.name, q.definition); // } diff --git a/src/servers/model/server/landing.ts b/src/servers/model/server/landing.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cb4e0aaf3ba22273995bad8ff4953b887fa38c6 --- /dev/null +++ b/src/servers/model/server/landing.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import Version from '../version' + +function create() { + return `<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> + <title>Mol* ModelServer ${Version}</title> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" /> + </head> + <body> + <h1>Mol* Model Server ${Version}</h1> + <textarea style="height: 280px; width: 600px; font-family: monospace" id="query-text">{ + "id": "1cbs", + "name": "residueInteraction", + "params": { + "radius": 5, + "atom_site": { "label_comp_id": "REA" } + } +}</textarea><br> + <button class="button button-primary" style="width: 600px" id="query">Query</button> + <div id='error' style='color: red; font-weight: blue'></div> + <div>Static input files available as CIF and BinaryCIF at <a href='ModelServer/static/cif/1cbs' target='_blank'>static/cif/id</a> and <a href='ModelServer/static/bcif/1cbs' target='_blank'>static/bcif/id</a> respectively.</div> + <script> + const err = document.getElementById('error'); + document.getElementById('query').onclick = function () { + err.innerText = ''; + try { + var q = JSON.parse(document.getElementById('query-text').value); + var path = 'ModelServer/api/v1?' + encodeURIComponent(JSON.stringify(q)); + console.log(path); + window.open(path, '_blank'); + } catch (e) { + err.innerText = '' + e; + } + } + </script> + </body> +</html>`; +} + +export const LandingPage = create(); \ No newline at end of file diff --git a/src/servers/model/version.ts b/src/servers/model/version.ts index e3941c34a2ff25bc14e17941fe12b356c5b60f2a..2ee344558fa63c6e040d3a0c23cc476f30acc9f0 100644 --- a/src/servers/model/version.ts +++ b/src/servers/model/version.ts @@ -4,4 +4,4 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -export default '0.1.0'; \ No newline at end of file +export default '0.8.0'; \ No newline at end of file