From e08a074a1c6f3ca9824c1d9de2cb36c31dc98494 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Sat, 8 Feb 2020 17:02:44 +0100
Subject: [PATCH] mol-plugin: config

---
 src/apps/viewer/index.ts                      |  3 +-
 .../skin/base/components/temp.scss            |  1 +
 src/mol-plugin-ui/state/snapshots.tsx         | 19 ++++-----
 src/mol-plugin/config.ts                      | 40 +++++++++++++++++++
 src/mol-plugin/context.ts                     |  4 ++
 src/mol-plugin/index.ts                       |  6 ++-
 src/mol-plugin/spec.ts                        |  4 +-
 7 files changed, 65 insertions(+), 12 deletions(-)
 create mode 100644 src/mol-plugin/config.ts

diff --git a/src/apps/viewer/index.ts b/src/apps/viewer/index.ts
index da6fb6504..f5474d4a0 100644
--- a/src/apps/viewer/index.ts
+++ b/src/apps/viewer/index.ts
@@ -42,7 +42,8 @@ function init() {
             controls: {
                 ...DefaultPluginSpec.layout && DefaultPluginSpec.layout.controls
             }
-        }
+        },
+        config: DefaultPluginSpec.config
     };
     const plugin = createPlugin(document.getElementById('app')!, spec);
     trySetSnapshot(plugin);
diff --git a/src/mol-plugin-ui/skin/base/components/temp.scss b/src/mol-plugin-ui/skin/base/components/temp.scss
index b77c4cd2d..004a90f17 100644
--- a/src/mol-plugin-ui/skin/base/components/temp.scss
+++ b/src/mol-plugin-ui/skin/base/components/temp.scss
@@ -83,6 +83,7 @@
 
     > li {
         position: relative;
+        overflow: hidden;
 
         > button:first-child {
             border-left: $control-spacing solid color-increase-contrast($default-background, 12%) !important;
diff --git a/src/mol-plugin-ui/state/snapshots.tsx b/src/mol-plugin-ui/state/snapshots.tsx
index a74699a32..515d86628 100644
--- a/src/mol-plugin-ui/state/snapshots.tsx
+++ b/src/mol-plugin-ui/state/snapshots.tsx
@@ -15,6 +15,7 @@ import { PluginState } from '../../mol-plugin/state';
 import { urlCombine } from '../../mol-util/url';
 import { IconButton, Icon, SectionHeader } from '../controls/common';
 import { formatTimespan } from '../../mol-util/now';
+import { PluginConfig } from '../../mol-plugin/config';
 
 export class StateSnapshots extends PluginUIComponent<{ }> {
     downloadToFile = () => {
@@ -161,22 +162,22 @@ class LocalStateSnapshotList extends PluginUIComponent<{ }, { }> {
 export type RemoteEntry = { url: string, removeUrl: string, timestamp: number, id: string, name: string, description: string, isSticky?: boolean }
 export class RemoteStateSnapshots extends PluginUIComponent<
     { listOnly?: boolean },
-    { params: PD.Values<typeof RemoteStateSnapshots.Params>, entries: OrderedMap<string, RemoteEntry>, isBusy: boolean }> {
+    { params: PD.Values<RemoteStateSnapshots['Params']>, entries: OrderedMap<string, RemoteEntry>, isBusy: boolean }> {
 
-    state = { params: PD.getDefaultValues(RemoteStateSnapshots.Params), entries: OrderedMap<string, RemoteEntry>(), isBusy: false };
-
-    static Params = {
+    Params = {
         name: PD.Text(),
         options: PD.Group({
             description: PD.Text(),
             playOnLoad: PD.Boolean(false),
-            serverUrl: PD.Text('https://webchem.ncbr.muni.cz/molstar-state')
+            serverUrl: PD.Text(this.plugin.config.get(PluginConfig.PluginState.Server))
         })
     };
 
-    static ListOnlyParams = {
+    state = { params: PD.getDefaultValues(this.Params), entries: OrderedMap<string, RemoteEntry>(), isBusy: false };
+
+    ListOnlyParams = {
         options: PD.Group({
-            serverUrl: PD.Text('https://webchem.ncbr.muni.cz/molstar-state')
+            serverUrl: PD.Text(this.plugin.config.get(PluginConfig.PluginState.Server))
         }, { isFlat: true })
     };
 
@@ -268,7 +269,7 @@ export class RemoteStateSnapshots extends PluginUIComponent<
             <SectionHeader title='Remote States' />
 
             {!this.props.listOnly && <>
-                <ParameterControls params={RemoteStateSnapshots.Params} values={this.state.params} onEnter={this.upload} onChange={p => {
+                <ParameterControls params={this.Params} values={this.state.params} onEnter={this.upload} onChange={p => {
                     this.setState({ params: { ...this.state.params, [p.name]: p.value } } as any);
                 }} isDisabled={this.state.isBusy}/>
                 <div className='msp-btn-row-group'>
@@ -281,7 +282,7 @@ export class RemoteStateSnapshots extends PluginUIComponent<
                 fetch={this.fetch} remove={this.props.listOnly ? void 0 : this.remove} />
 
             {this.props.listOnly && <>
-                <ParameterControls params={RemoteStateSnapshots.ListOnlyParams} values={this.state.params} onEnter={this.upload} onChange={p => {
+                <ParameterControls params={this.ListOnlyParams} values={this.state.params} onEnter={this.upload} onChange={p => {
                     this.setState({ params: { ...this.state.params, [p.name]: p.value } } as any);
                 }} isDisabled={this.state.isBusy}/>
                 <div className='msp-btn-row-group'>
diff --git a/src/mol-plugin/config.ts b/src/mol-plugin/config.ts
new file mode 100644
index 000000000..b2d094f05
--- /dev/null
+++ b/src/mol-plugin/config.ts
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+export class PluginConfigItem<T = any> {
+    toString() { return this.key; }
+    valueOf() { return this.key; }
+    constructor(public key: string, public defaultValue?: T) { }
+}
+
+function item<T>(key: string, defaultValue?: T) { return new PluginConfigItem(key, defaultValue); }
+
+export const PluginConfig = {
+    item,
+    PluginState: { Server: item('plugin-state.server', 'https://webchem.ncbr.muni.cz/molstar-state') }
+}
+
+export class PluginConfigManager {    
+    private _config = new Map<PluginConfigItem<any>, unknown>();
+
+    get<T>(key: PluginConfigItem<T>) {
+        if (!this._config.has(key)) return key.defaultValue;
+        return this._config.get(key) as T;
+    }
+
+    set<T>(key: PluginConfigItem<T>, value: T) {
+        this._config.set(key, value);
+    }
+
+    delete<T>(key: PluginConfigItem<T>) {
+        this._config.delete(key);
+    }
+
+    constructor(initial?: Map<PluginConfigItem, unknown>) {
+        if (!initial) return;
+        initial.forEach((v, k) => this._config.set(k, v));
+    }
+}
\ No newline at end of file
diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts
index 213a3e574..f61454b6c 100644
--- a/src/mol-plugin/context.ts
+++ b/src/mol-plugin/context.ts
@@ -44,6 +44,7 @@ import { StructureMeasurementManager } from './util/structure-measurement';
 import { ViewportScreenshotHelper } from './util/viewport-screenshot';
 import { StructureRepresentationManager } from './state/representation/structure';
 import { CustomProperty } from '../mol-model-props/common/custom-property';
+import { PluginConfigManager } from './config';
 
 interface Log {
     entries: List<LogEntry>
@@ -88,6 +89,8 @@ export class PluginContext {
             selectionUpdated: this.ev()
         }
     } as const
+    
+    readonly config = new PluginConfigManager(this.spec.config);
 
     readonly behaviors = {
         state: {
@@ -113,6 +116,7 @@ export class PluginContext {
 
     readonly lociLabels: LociLabelManager;
 
+
     readonly structureRepresentation = {
         registry: new StructureRepresentationRegistry(),
         themeCtx: { colorThemeRegistry: ColorTheme.createRegistry(), sizeThemeRegistry: SizeTheme.createRegistry() } as ThemeRegistryContext,
diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts
index 68c8b525a..d8832d51d 100644
--- a/src/mol-plugin/index.ts
+++ b/src/mol-plugin/index.ts
@@ -18,6 +18,7 @@ import { InitVolumeStreaming, BoxifyVolumeStreaming, CreateVolumeStreamingBehavi
 import { StructureRepresentationInteraction } from './behavior/dynamic/selection/structure-representation-interaction';
 import { TransformStructureConformation } from './state/actions/structure';
 import { VolumeStreamingCustomControls } from '../mol-plugin-ui/custom/volume';
+import { PluginConfig } from './config';
 
 export const DefaultPluginSpec: PluginSpec = {
     actions: [
@@ -86,7 +87,10 @@ export const DefaultPluginSpec: PluginSpec = {
         AnimateAssemblyUnwind,
         AnimateUnitsExplode,
         AnimateStateInterpolation
-    ]
+    ],
+    config: new Map([
+        [PluginConfig.PluginState.Server, 'https://webchem.ncbr.muni.cz/molstar-state']
+    ])
 }
 
 export function createPlugin(target: HTMLElement, spec?: PluginSpec): PluginContext {
diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts
index 61c9a21f9..c3c11f44d 100644
--- a/src/mol-plugin/spec.ts
+++ b/src/mol-plugin/spec.ts
@@ -10,6 +10,7 @@ import { StateTransformParameters } from '../mol-plugin-ui/state/common';
 import { PluginLayoutStateProps } from './layout';
 import { PluginStateAnimation } from './state/animation/model';
 import { ParamDefinition as PD } from '../mol-util/param-definition';
+import { PluginConfigItem } from './config';
 
 export { PluginSpec }
 
@@ -25,7 +26,8 @@ interface PluginSpec {
     },
     components?: {
         remoteState?: 'none' | 'default' // TODO: props for server etc
-    }
+    },
+    config?: Map<PluginConfigItem, unknown>
 }
 
 namespace PluginSpec {
-- 
GitLab