/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal */ import { PluginCommands } from 'mol-plugin/command'; import * as React from 'react'; import { PluginComponent } from './base'; import { shallowEqual } from 'mol-util'; import { List } from 'immutable'; import { LogEntry } from 'mol-util/log-entry'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { ParameterControls } from './controls/parameters'; import { Subject } from 'rxjs'; export class StateSnapshots extends PluginComponent<{ }, { serverUrl: string }> { state = { serverUrl: 'https://webchem.ncbr.muni.cz/molstar-state' } updateServerUrl = (serverUrl: string) => { this.setState({ serverUrl }) }; render() { return
State Snapshots
; } } // TODO: this is not nice: device some custom event system. const UploadedEvent = new Subject(); class StateSnapshotControls extends PluginComponent<{ serverUrl: string, serverChanged: (url: string) => void }, { name: string, description: string, serverUrl: string, isUploading: boolean }> { state = { name: '', description: '', serverUrl: this.props.serverUrl, isUploading: false }; static Params = { name: PD.Text(), description: PD.Text(), serverUrl: PD.Text() } add = () => { PluginCommands.State.Snapshots.Add.dispatch(this.plugin, { name: this.state.name, description: this.state.description }); this.setState({ name: '', description: '' }) } clear = () => { PluginCommands.State.Snapshots.Clear.dispatch(this.plugin, {}); } shouldComponentUpdate(nextProps: { serverUrl: string, serverChanged: (url: string) => void }, nextState: { name: string, description: string, serverUrl: string, isUploading: boolean }) { return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); } upload = async () => { this.setState({ isUploading: true }); await PluginCommands.State.Snapshots.Upload.dispatch(this.plugin, { name: this.state.name, description: this.state.description, serverUrl: this.state.serverUrl }); this.setState({ isUploading: false }); this.plugin.log(LogEntry.message('Snapshot uploaded.')); UploadedEvent.next(); } render() { return
{ this.setState({ [p.name]: p.value } as any); if (p.name === 'serverUrl') this.props.serverChanged(p.value); }}/>
; } } class LocalStateSnapshotList extends PluginComponent<{ }, { }> { componentDidMount() { this.subscribe(this.plugin.events.state.snapshots.changed, () => this.forceUpdate()); } apply(id: string) { return () => PluginCommands.State.Snapshots.Apply.dispatch(this.plugin, { id }); } remove(id: string) { return () => { PluginCommands.State.Snapshots.Remove.dispatch(this.plugin, { id }); } } render() { return ; } } type RemoteEntry = { url: string, removeUrl: string, timestamp: number, id: string, name: string, description: string } class RemoteStateSnapshotList extends PluginComponent<{ serverUrl: string }, { entries: List, isFetching: boolean }> { state = { entries: List(), isFetching: false }; componentDidMount() { this.subscribe(this.plugin.events.state.snapshots.changed, () => this.forceUpdate()); this.refresh(); this.subscribe(UploadedEvent, this.refresh); } refresh = async () => { try { this.setState({ isFetching: true }); const req = await fetch(`${this.props.serverUrl}/list`); const json: RemoteEntry[] = await req.json(); this.setState({ entries: List(json.map((e: RemoteEntry) => ({ ...e, url: `${this.props.serverUrl}/get/${e.id}`, removeUrl: `${this.props.serverUrl}/remove/${e.id}` }))), isFetching: false }) } catch (e) { this.plugin.log(LogEntry.error('Fetching Remote Snapshots: ' + e)); this.setState({ entries: List(), isFetching: false }) } } fetch(url: string) { return () => PluginCommands.State.Snapshots.Fetch.dispatch(this.plugin, { url }); } remove(url: string) { return async () => { this.setState({ entries: List() }); try { await fetch(url); } catch { } this.refresh(); } } render() { return
    {this.state.entries.valueSeq().map(e =>
  • )}
; } }