<commit_before>import React, { PureComponent } from 'react';
import { List, ListItem } from 'material-ui/List';
import Checkbox from 'material-ui/Checkbox';
import Divider from 'material-ui/Divider';

import CalendarSystemDialog from './CalendarSystemDialog';
import FirstDayOfWeekDialog from './FirstDayOfWeekDialog';
import './Settings.css';

class Settings extends PureComponent {
  constructor() {
    super();
    this.state = {
      calendarSystemDialogOpen: false,
      firstDayOfWeekDialogOpen: false,
    };
  }
  handleCheckShowNotYet = (e, checked) => {
    this.props.toggleNotYet(checked);
  }
  handleCheckFullscreen = (e, checked) => {
    this.props.toggleFullscreen(checked);
  }
  handleChangeCalendarSystem = (calendarSystem) => {
    this.props.toggleFullscreen(calendarSystem);
  }
  handleRequestCalendarSystemDialogOpen = () => {
    this.setState({
      calendarSystemDialogOpen: true,
    });
  }
  handleRequestFirstDayOfWeekDialogOpen = () => {
    this.setState({
      firstDayOfWeekDialogOpen: true,
    });
  }
  handleRequestCalendarSystemDialogClose = (calendarSystem) => {
    this.props.changeCalendarSystem(calendarSystem);
    this.setState({
      calendarSystemDialogOpen: false,
    });
  }
  handleRequestFirstDayOfWeekDialogClose = (dayNumber) => {
    this.props.changeFirstDayOfWeek(+dayNumber);
    this.setState({
      firstDayOfWeekDialogOpen: false,
    });
  }
  render() {
    const weekDays = {
      0: 'Sunday',
      1: 'Monday',
      6: 'Saturday',
    };
    const marginStyles = {
      expanded: {
        marginLeft: 200,
      },
      mini: {
        marginLeft: 56,
      },
    };
    return (
      <div
        className="Settings"
        style={
          this.props.sidebarExpanded ?
          marginStyles.expanded :
          marginStyles.mini
        }
      >
        <List>
          <ListItem
            leftCheckbox={
              <Checkbox
                defaultChecked={this.props.showNotYetTasks}
                onCheck={this.handleCheckShowNotYet}
              />
            }
            primaryText="Show not-yet tasks"
          />
          <Divider />
          <ListItem
            leftCheckbox={
              <Checkbox
                defaultChecked={this.props.fullscreen}
                onCheck={this.handleCheckFullscreen}
              />
            }
            primaryText="Start app in fullscreen mode"
            secondaryText="Changes will apply after restarting the app"
          />
          <Divider />
          <ListItem
            primaryText="Calendar system"
            secondaryText={this.props.calendarSystem}
            onClick={this.handleRequestCalendarSystemDialogOpen}
          />
          <Divider />
          <ListItem
            primaryText="First day of week"
            secondaryText={weekDays[this.props.firstDayOfWeek]}
            onClick={this.handleRequestFirstDayOfWeekDialogOpen}
          />
          <Divider />
        </List>
        <CalendarSystemDialog
          onRequestClose={this.handleRequestCalendarSystemDialogClose}
          open={this.state.calendarSystemDialogOpen}
          calendarSystem={this.props.calendarSystem}
        />
        <FirstDayOfWeekDialog
          onRequestClose={this.handleRequestFirstDayOfWeekDialogClose}
          open={this.state.firstDayOfWeekDialogOpen}
          firstDayOfWeek={this.props.firstDayOfWeek}
        />
      </div>
    );
  }
}

export default Settings;
<commit_msg>Update settings items sequence<commit_after>import React, { PureComponent } from 'react';
import { List, ListItem } from 'material-ui/List';
import Checkbox from 'material-ui/Checkbox';
import Divider from 'material-ui/Divider';

import CalendarSystemDialog from './CalendarSystemDialog';
import FirstDayOfWeekDialog from './FirstDayOfWeekDialog';
import './Settings.css';

class Settings extends PureComponent {
  constructor() {
    super();
    this.state = {
      calendarSystemDialogOpen: false,
      firstDayOfWeekDialogOpen: false,
    };
  }
  handleCheckShowNotYet = (e, checked) => {
    this.props.toggleNotYet(checked);
  }
  handleCheckFullscreen = (e, checked) => {
    this.props.toggleFullscreen(checked);
  }
  handleChangeCalendarSystem = (calendarSystem) => {
    this.props.toggleFullscreen(calendarSystem);
  }
  handleRequestCalendarSystemDialogOpen = () => {
    this.setState({
      calendarSystemDialogOpen: true,
    });
  }
  handleRequestFirstDayOfWeekDialogOpen = () => {
    this.setState({
      firstDayOfWeekDialogOpen: true,
    });
  }
  handleRequestCalendarSystemDialogClose = (calendarSystem) => {
    this.props.changeCalendarSystem(calendarSystem);
    this.setState({
      calendarSystemDialogOpen: false,
    });
  }
  handleRequestFirstDayOfWeekDialogClose = (dayNumber) => {
    this.props.changeFirstDayOfWeek(+dayNumber);
    this.setState({
      firstDayOfWeekDialogOpen: false,
    });
  }
  render() {
    const weekDays = {
      0: 'Sunday',
      1: 'Monday',
      6: 'Saturday',
    };
    const marginStyles = {
      expanded: {
        marginLeft: 200,
      },
      mini: {
        marginLeft: 56,
      },
    };
    return (
      <div
        className="Settings"
        style={
          this.props.sidebarExpanded ?
          marginStyles.expanded :
          marginStyles.mini
        }
      >
        <List>
          <ListItem
            primaryText="Calendar system"
            secondaryText={this.props.calendarSystem}
            onClick={this.handleRequestCalendarSystemDialogOpen}
          />
          <Divider />
          <ListItem
            primaryText="First day of week"
            secondaryText={weekDays[this.props.firstDayOfWeek]}
            onClick={this.handleRequestFirstDayOfWeekDialogOpen}
          />
          <Divider />
          <ListItem
            leftCheckbox={
              <Checkbox
                defaultChecked={this.props.fullscreen}
                onCheck={this.handleCheckFullscreen}
              />
            }
            primaryText="Start app in fullscreen mode"
            secondaryText="Changes will apply after restarting the app"
          />
          <Divider />
          <ListItem
            leftCheckbox={
              <Checkbox
                defaultChecked={this.props.showNotYetTasks}
                onCheck={this.handleCheckShowNotYet}
              />
            }
            primaryText="Show not-yet tasks"
          />
          <Divider />
        </List>
        <CalendarSystemDialog
          onRequestClose={this.handleRequestCalendarSystemDialogClose}
          open={this.state.calendarSystemDialogOpen}
          calendarSystem={this.props.calendarSystem}
        />
        <FirstDayOfWeekDialog
          onRequestClose={this.handleRequestFirstDayOfWeekDialogClose}
          open={this.state.firstDayOfWeekDialogOpen}
          firstDayOfWeek={this.props.firstDayOfWeek}
        />
      </div>
    );
  }
}

export default Settings;
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Red Hat Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var events = require('events');
var fs = require('fs');
var http = require('http');
var https = require('https');
var path = require('path');
var url = require('url');
var util = require('util');

function shift_if_matches(path, match) {
    if (path[0] === match) {
        path.shift();
        return true;
    } else {
        return false;
    }
}

function parse(request_url) {
    var result = {};
    var path = url.parse(request_url).pathname.split('/');
    shift_if_matches(path, '');
    if (path.shift() === 'api' && path.shift() === 'v1') {
        result.watch = shift_if_matches(path, 'watch');
        if (shift_if_matches(path, 'namespaces')) {
            result.namespace = path.shift();
            result.type = path.shift();
            result.name = path.shift();
            return result;
        }
    }
    return undefined;
}

function ResourceServer (kind, read_only, externalize, internalize) {
    events.EventEmitter.call(this);
    this.kind = kind;
    this.read_only = read_only;
    this.externalize = externalize || function (o) { return o; };
    this.internalize = internalize;
    this.list_kind = kind + 'List';
    this.resources = [];
    this.watch_timeout = 1000;
    Object.defineProperty(this, 'externalized', { get: function () { return this.resources.map(this.externalize); } });
    this.debug = false;
    if (this.debug) {
        this.on('added', function (o) {
            console.log('ADDED: %j', o);
        });
        this.on('deleted', function (o) {
            console.log('DELETED: %j', o);
        });
    }
}

util.inherits(ResourceServer, events.EventEmitter);

ResourceServer.prototype.update = function (index, object) {
    this.resources[index] = this.internalize ? this.codec.internalize(object) : object;
};

ResourceServer.prototype.push = function (object) {
    this.resources.push(this.internalize ? this.codec.internalize(object) : object);
    this.emit('added', this.externalize(object));
};

function relativepath(name) {
    return path.resolve(__dirname, name);
}

function error(request, response, status_code, message) {
    response.statusCode = status_code;
    var text = message || http.STATUS_CODES[status_code];
    response.end(util.format('%s: %s %s', text, request.method, request.url));
}

ResourceServer.prototype.listen = function (port, callback) {
    var self = this;
    var options = {
        key: fs.readFileSync(relativepath('../test/server-key.pem')),
        cert: fs.readFileSync(relativepath('../test/server-cert.pem'))
    };
    this.server = https.createServer(options, function (request, response) {
        var path = parse(request.url);
        if (self.debug) console.log('%s %s => %j', request.method, request.url, path);
        if (path === undefined) {
            error(request, response, 404);
        } else {
            if (path.watch && request.method === 'GET') {
                self.watch_resources(request, response);
            } else if (request.method === 'GET') {
                if (path.name) {
                    self.get_resource(request, response, path.name);
                } else {
                    self.get_resources(request, response);
                }
            } else if (request.method === 'PUT' && path.name) {
                self.put_resource(request, response, path.name);
            } else if (request.method === 'DELETE' && path.name) {
                self.delete_resource(request, response, path.name);
            } else if (request.method === 'POST') {
                self.post_resource(request, response);
            } else {
                error(request, response, 405);
            }
        }
    });
    this.server.listen(port || 0, function () {
        self.port = self.server.address().port;
        if (callback) callback();
    });
    return this.server;
};

ResourceServer.prototype.close = function (callback) {
    this.clear();
    this.server.close(callback);
};

ResourceServer.prototype.clear = function () {
    this.resources = [];
};

ResourceServer.prototype.add_resource = function (resource) {
    if (this.resource_initialiser) {
        this.resource_initialiser(resource);
    }
    this.resources.push(resource);
    this.emit('added', this.externalize(resource));
};

ResourceServer.prototype.resource_modified = function (resource) {
    this.emit('modified', this.externalize(resource));
};

ResourceServer.prototype.remove_resource = function (resource) {
    var i = this.resources.indexOf(resource);
    if (i >= 0) {
        this.resources.splice(i, 1);
        this.emit('deleted', this.externalize(resource));
    }
};

ResourceServer.prototype.remove_resource_by_name = function (name) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.resources[i].metadata.name === name) {
            var removed = this.resources[i];
            this.resources.splice(i, 1);
            this.emit('deleted', this.externalize(removed));
            return true;
        }
    }
    return false;
};

function getLabelSelectorFn(request) {
    var parsed = url.parse(request.url, true);
    var selector = parsed.query.labelSelector;
    if (selector) {
        var parts = selector.split('=');
        return function (object) {
            return object.metadata.labels && object.metadata.labels[parts[0]] === parts[1];
        }
    } else {
        return function () {
            return true;
        }
    }
}

function Watcher (parent, response, selector) {
    this.parent = parent;
    this.response = response;
    this.selector = selector;
    this.callbacks = {};
    this.add_callback('added');
    this.add_callback('deleted');
    this.add_callback('modified');
    for (var k in this.callbacks) {
        this.parent.on(k, this.callbacks[k]);
    }
}

Watcher.prototype.add_callback = function (type) {
    var response = this.response;
    var filter = this.selector;
    this.callbacks[type] = function (resource) {
        if (filter(resource)) {
            response.write(JSON.stringify({type:type.toUpperCase(), object:resource}) + '\n');
        }
    };
};

Watcher.prototype.close = function () {
    for (var k in this.callbacks) {
        this.parent.removeListener(k, this.callbacks[k]);
    }
    this.response.end();
}

ResourceServer.prototype.get_resources = function (request, response) {
    var filter = getLabelSelectorFn(request);
    response.end(JSON.stringify({kind: this.list_kind, items: this.externalized.filter(filter)}));
};

ResourceServer.prototype.watch_resources = function (request, response) {
    var filter = getLabelSelectorFn(request);
    for (var i = 0; i < this.resources.length; i++) {
        if (filter(this.externalized[i])) {
            response.write(JSON.stringify({type:'ADDED', object:this.externalized[i]}) + '\n');
        }
    }
    var watcher = new Watcher(this, response, filter);
    setTimeout(function () { watcher.close(); }, this.watch_timeout);
};

ResourceServer.prototype.find_resource = function (name) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === name) {
            return this.externalized[i];
        }
    }
};

ResourceServer.prototype.get_resource = function (request, response, name) {
    var result = this.find_resource(name);
    if (result) {
        response.end(JSON.stringify(result));
    } else {
        error(request, response, 404);
    }
};

ResourceServer.prototype.update_resource = function (name, updated) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === name) {
            this.update(i, updated);
            return true;
        }
    }
    return false;
};

ResourceServer.prototype.add_resource_if_not_exists = function (resource) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === resource.metadata.name) {
            return false;
        }
    }
    this.add_resource(resource);
    return true;
};

ResourceServer.prototype.delete_resource = function (request, response, name) {
    if (this.remove_resource_by_name(name)) {
        response.statusCode = 200;
        response.end();
    } else {
        error(request, response, 404);
    }
};

ResourceServer.prototype.put_resource = function (request, response, name) {
    var self = this;
    var bodytext = '';
    request.on('data', function (data) { bodytext += data; });
    request.on('end', function () {
        var body = JSON.parse(bodytext);
        if (body.kind === self.kind) {
            if (self.update_resource(name, body)) {
                response.statusCode = 200;
                response.end();
            } else {
                error(request, response, 404);
            }
        } else {
            error(request, response, 500, 'Invalid resource kind ' + body.kind);
        }
    });
};

ResourceServer.prototype.post_resource = function (request, response) {
    var self = this;
    var bodytext = '';
    request.on('data', function (data) { bodytext += data; });
    request.on('end', function () {
        var body = JSON.parse(bodytext);
        if (body.kind === self.kind) {
            if (self.add_resource_if_not_exists(body)) {
                response.statusCode = 200;
                response.end();
            } else {
                error(request, response, 409);
            }
        } else {
            error(request, response, 500, 'Invalid resource kind ' + body.kind);
        }
    });
};

function ConfigMapServer () {
    ResourceServer.call(this, 'ConfigMap');
}

util.inherits(ConfigMapServer, ResourceServer);

function get_config_map(name, type, key, content) {
    var cm = {
        kind:'ConfigMap',
        metadata: {
            name: name,
            labels: {
                type: type
            }
        },
        data:{}
    };
    cm.data[key] = JSON.stringify(content);
    return cm;
}

ConfigMapServer.prototype.add_address_definition = function (def, name, annotations, status) {
    var address = {kind: 'Address', metadata: {name: def.address}, spec:def};
    if (annotations) {
        address.metadata.annotations = annotations;
    }
    address.status = status || { phase: 'Active' };
    this.add_resource(get_config_map(name || def.address, 'address-config', 'config.json', address));
};

ConfigMapServer.prototype.add_address_definitions = function (defs) {
    for (var i in defs) {
        this.add_address_definition(defs[i]);
    }
};

ConfigMapServer.prototype.add_address_plan = function (params) {
    var plan = {
        kind: 'AddressPlan',
        metadata: {name: params.plan_name},
        displayName: params.display_name,
        shortDescription: params.shortDescription,
        longDescription: params.longDescription,
        displayOrder: params.displayOrder,
        addressType: params.address_type
    };
    this.add_resource(get_config_map(plan.name, 'address-plan', 'definition', plan));
};

ConfigMapServer.prototype.resource_initialiser = function (resource) {
    if (resource.data['config.json']) {
        try {
            var address = JSON.parse(resource.data['config.json']);
            var changed = true;
            if (address.status === undefined) {
                address.status = {'phase': 'Active'};
            } else if (address.status.phase === undefined) {
                address.status.phase = 'Active';
            } else {
                changed = false;
            }
            if (changed) {
                resource.data['config.json'] = JSON.stringify(address);
            }
        } catch (e) {
            console.error('Failed to parse address for resource initialisation: %s', e);
        }
    }
};

module.exports.ResourceServer = ResourceServer;
module.exports.ConfigMapServer = ConfigMapServer;
<commit_msg>Fix deletion and tests<commit_after>/*
 * Copyright 2017 Red Hat Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

var events = require('events');
var fs = require('fs');
var http = require('http');
var https = require('https');
var path = require('path');
var url = require('url');
var util = require('util');

function shift_if_matches(path, match) {
    if (path[0] === match) {
        path.shift();
        return true;
    } else {
        return false;
    }
}

function parse(request_url) {
    var result = {};
    var path = url.parse(request_url).pathname.split('/');
    shift_if_matches(path, '');
    if (path.shift() === 'api' && path.shift() === 'v1') {
        result.watch = shift_if_matches(path, 'watch');
        if (shift_if_matches(path, 'namespaces')) {
            result.namespace = path.shift();
            result.type = path.shift();
            result.name = path.shift();
            return result;
        }
    }
    return undefined;
}

function ResourceServer (kind, read_only, externalize, internalize) {
    events.EventEmitter.call(this);
    this.kind = kind;
    this.read_only = read_only;
    this.externalize = externalize || function (o) { return o; };
    this.internalize = internalize;
    this.list_kind = kind + 'List';
    this.resources = [];
    this.watch_timeout = 1000;
    Object.defineProperty(this, 'externalized', { get: function () { return this.resources.map(this.externalize); } });
    this.debug = false;
    if (this.debug) {
        this.on('added', function (o) {
            console.log('ADDED: %j', o);
        });
        this.on('deleted', function (o) {
            console.log('DELETED: %j', o);
        });
    }
}

util.inherits(ResourceServer, events.EventEmitter);

ResourceServer.prototype.update = function (index, object) {
    this.resources[index] = this.internalize ? this.codec.internalize(object) : object;
};

ResourceServer.prototype.push = function (object) {
    this.resources.push(this.internalize ? this.codec.internalize(object) : object);
    this.emit('added', this.externalize(object));
};

function relativepath(name) {
    return path.resolve(__dirname, name);
}

function error(request, response, status_code, message) {
    response.statusCode = status_code;
    var text = message || http.STATUS_CODES[status_code];
    response.end(util.format('%s: %s %s', text, request.method, request.url));
}

ResourceServer.prototype.listen = function (port, callback) {
    var self = this;
    var options = {
        key: fs.readFileSync(relativepath('../test/server-key.pem')),
        cert: fs.readFileSync(relativepath('../test/server-cert.pem'))
    };
    this.server = https.createServer(options, function (request, response) {
        var path = parse(request.url);
        if (self.debug) console.log('%s %s => %j', request.method, request.url, path);
        if (path === undefined) {
            error(request, response, 404);
        } else {
            if (path.watch && request.method === 'GET') {
                self.watch_resources(request, response);
            } else if (request.method === 'GET') {
                if (path.name) {
                    self.get_resource(request, response, path.name);
                } else {
                    self.get_resources(request, response);
                }
            } else if (request.method === 'PUT' && path.name) {
                self.put_resource(request, response, path.name);
            } else if (request.method === 'DELETE' && path.name) {
                self.delete_resource(request, response, path.name);
            } else if (request.method === 'POST') {
                self.post_resource(request, response);
            } else {
                error(request, response, 405);
            }
        }
    });
    this.server.listen(port || 0, function () {
        self.port = self.server.address().port;
        if (callback) callback();
    });
    return this.server;
};

ResourceServer.prototype.close = function (callback) {
    this.clear();
    this.server.close(callback);
};

ResourceServer.prototype.clear = function () {
    this.resources = [];
};

ResourceServer.prototype.add_resource = function (resource) {
    if (this.resource_initialiser) {
        this.resource_initialiser(resource);
    }
    this.resources.push(resource);
    this.emit('added', this.externalize(resource));
};

ResourceServer.prototype.resource_modified = function (resource) {
    this.emit('modified', this.externalize(resource));
};

ResourceServer.prototype.remove_resource = function (resource) {
    var i = this.resources.indexOf(resource);
    if (i >= 0) {
        this.resources.splice(i, 1);
        this.emit('deleted', this.externalize(resource));
    }
};

ResourceServer.prototype.remove_resource_by_name = function (name) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.resources[i].metadata.name === name) {
            var removed = this.resources[i];
            this.resources.splice(i, 1);
            this.emit('deleted', this.externalize(removed));
            return true;
        }
    }
    return false;
};

function getLabelSelectorFn(request) {
    var parsed = url.parse(request.url, true);
    var selector = parsed.query.labelSelector;
    if (selector) {
        var parts = selector.split('=');
        return function (object) {
            return object.metadata.labels && object.metadata.labels[parts[0]] === parts[1];
        }
    } else {
        return function () {
            return true;
        }
    }
}

function Watcher (parent, response, selector) {
    this.parent = parent;
    this.response = response;
    this.selector = selector;
    this.callbacks = {};
    this.add_callback('added');
    this.add_callback('deleted');
    this.add_callback('modified');
    for (var k in this.callbacks) {
        this.parent.on(k, this.callbacks[k]);
    }
}

Watcher.prototype.add_callback = function (type) {
    var response = this.response;
    var filter = this.selector;
    this.callbacks[type] = function (resource) {
        if (filter(resource)) {
            response.write(JSON.stringify({type:type.toUpperCase(), object:resource}) + '\n');
        }
    };
};

Watcher.prototype.close = function () {
    for (var k in this.callbacks) {
        this.parent.removeListener(k, this.callbacks[k]);
    }
    this.response.end();
}

ResourceServer.prototype.get_resources = function (request, response) {
    var filter = getLabelSelectorFn(request);
    response.end(JSON.stringify({kind: this.list_kind, items: this.externalized.filter(filter)}));
};

ResourceServer.prototype.watch_resources = function (request, response) {
    var filter = getLabelSelectorFn(request);
    for (var i = 0; i < this.resources.length; i++) {
        if (filter(this.externalized[i])) {
            response.write(JSON.stringify({type:'ADDED', object:this.externalized[i]}) + '\n');
        }
    }
    var watcher = new Watcher(this, response, filter);
    setTimeout(function () { watcher.close(); }, this.watch_timeout);
};

ResourceServer.prototype.find_resource = function (name) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === name) {
            return this.externalized[i];
        }
    }
};

ResourceServer.prototype.get_resource = function (request, response, name) {
    var result = this.find_resource(name);
    if (result) {
        response.end(JSON.stringify(result));
    } else {
        error(request, response, 404);
    }
};

ResourceServer.prototype.update_resource = function (name, updated) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === name) {
            this.update(i, updated);
            return true;
        }
    }
    return false;
};

ResourceServer.prototype.add_resource_if_not_exists = function (resource) {
    for (var i = 0; i < this.resources.length; i++) {
        if (this.externalized[i].metadata.name === resource.metadata.name) {
            return false;
        }
    }
    this.add_resource(resource);
    return true;
};

ResourceServer.prototype.delete_resource = function (request, response, name) {
    if (this.remove_resource_by_name(name)) {
        response.statusCode = 200;
        response.end();
    } else {
        error(request, response, 404);
    }
};

ResourceServer.prototype.put_resource = function (request, response, name) {
    var self = this;
    var bodytext = '';
    request.on('data', function (data) { bodytext += data; });
    request.on('end', function () {
        var body = JSON.parse(bodytext);
        if (body.kind === self.kind) {
            if (self.update_resource(name, body)) {
                response.statusCode = 200;
                response.end();
            } else {
                error(request, response, 404);
            }
        } else {
            error(request, response, 500, 'Invalid resource kind ' + body.kind);
        }
    });
};

ResourceServer.prototype.post_resource = function (request, response) {
    var self = this;
    var bodytext = '';
    request.on('data', function (data) { bodytext += data; });
    request.on('end', function () {
        var body = JSON.parse(bodytext);
        if (body.kind === self.kind) {
            if (self.add_resource_if_not_exists(body)) {
                response.statusCode = 200;
                response.end();
            } else {
                error(request, response, 409);
            }
        } else {
            error(request, response, 500, 'Invalid resource kind ' + body.kind);
        }
    });
};

function ConfigMapServer () {
    ResourceServer.call(this, 'ConfigMap');
}

util.inherits(ConfigMapServer, ResourceServer);

function get_config_map(name, type, key, content) {
    var cm = {
        kind:'ConfigMap',
        metadata: {
            name: name,
            labels: {
                type: type
            }
        },
        data:{}
    };
    cm.data[key] = JSON.stringify(content);
    return cm;
}

ConfigMapServer.prototype.add_address_definition = function (def, name, annotations, status) {
    var address = {kind: 'Address', metadata: {name: name}, spec:def};
    if (annotations) {
        address.metadata.annotations = annotations;
    }
    address.status = status || { phase: 'Active' };
    this.add_resource(get_config_map(name || def.address, 'address-config', 'config.json', address));
};

ConfigMapServer.prototype.add_address_definitions = function (defs) {
    for (var i in defs) {
        this.add_address_definition(defs[i]);
    }
};

ConfigMapServer.prototype.add_address_plan = function (params) {
    var plan = {
        kind: 'AddressPlan',
        metadata: {name: params.plan_name},
        displayName: params.display_name,
        shortDescription: params.shortDescription,
        longDescription: params.longDescription,
        displayOrder: params.displayOrder,
        addressType: params.address_type
    };
    this.add_resource(get_config_map(plan.name, 'address-plan', 'definition', plan));
};

ConfigMapServer.prototype.resource_initialiser = function (resource) {
    if (resource.data['config.json']) {
        try {
            var address = JSON.parse(resource.data['config.json']);
            var changed = true;
            if (address.status === undefined) {
                address.status = {'phase': 'Active'};
            } else if (address.status.phase === undefined) {
                address.status.phase = 'Active';
            } else {
                changed = false;
            }
            if (changed) {
                resource.data['config.json'] = JSON.stringify(address);
            }
        } catch (e) {
            console.error('Failed to parse address for resource initialisation: %s', e);
        }
    }
};

module.exports.ResourceServer = ResourceServer;
module.exports.ConfigMapServer = ConfigMapServer;
<|endoftext|>


<commit_before>import {
  QUESTION_TYPE_ENUM,
  DIMENSION_TYPE,
  DIMENSION_FORMATS,
  DEFAULT_CODES_LIST_SELECTOR_PATH,
  DATATYPE_NAME
} from 'constants/pogues-constants';
import { uuid } from 'utils/utils';
import { debug } from 'util';
import { sortByWeight } from 'model/transformations/codes-list';
const { SIMPLE, SINGLE_CHOICE, MULTIPLE_CHOICE, TABLE } = QUESTION_TYPE_ENUM;
const { PRIMARY, SECONDARY, MEASURE, LIST_MEASURE } = DIMENSION_TYPE;
const { CODES_LIST } = DIMENSION_FORMATS;
const { TEXT, BOOLEAN } = DATATYPE_NAME;

export function sortByYAndX(store) {
  return (id1, id2) => {
    let c1 = id1;
    let c2 = id2;
    if (store) {
      c1 = store[id1];
      c2 = store[id2];
    }

    if (!c1.y) return c1.x - c2.x;
    return c1.y * 100 + c1.x - (c2.y * 100 + c2.x);
  };
}

export function getCollecteVariable(
  name,
  label,
  coordinates,
  reponseFormatValues = {}
) {
  let collectedVariable = {
    id: uuid(),
    name,
    label,
    ...reponseFormatValues
  };

  if (coordinates) collectedVariable = { ...collectedVariable, ...coordinates };

  return collectedVariable;
}

export function getCollectedVariablesMultiple(
  questionName,
  form,
  codesListStore
) {
  /**
   * This method will recursively sort an array of code.
   * A code have a depth, a weight and maybe a parent.
   * We will first sort codes with the depth=1, and recurively for each code,
   * sort its direct children.
   */
  function sortCodes(codes = [], depth = 1, parent = '') {
    const filtered = codes.filter(
      code => code.depth === depth && code.parent === parent
    );
    if (filtered.length === 0) {
      return [];
    }
    return filtered
      .sort((code1, code2) => {
        const weight1 = code1.weight;
        const weight2 = code2.weight;
        if (weight1 < weight2) return -1;
        if (weight1 > weight2) return 1;
        return 0;
      })
      .map(code => [code, ...sortCodes(codes, depth + 1, code.value)])
      .reduce((acc, res) => [...acc, ...res], []);
  }

  const {
    [PRIMARY]: { [DEFAULT_CODES_LIST_SELECTOR_PATH]: { codes, id } },
    [MEASURE]: { type: typeMeasure }
  } = form;
  let listCodes = sortCodes(codes);
  if (listCodes.length === 0 && codesListStore[id]) {
    const codesStore = codesListStore[id].codes;
    listCodes = Object.keys(codesStore).map(key => codesStore[key]);
  }

  let reponseFormatValues = {
    type: BOOLEAN,
    [BOOLEAN]: {}
  };

  if (typeMeasure === CODES_LIST) {
    reponseFormatValues = {
      codeListReference: form[MEASURE][CODES_LIST].CodesList.id,
      codeListReferenceLabel: form[MEASURE][CODES_LIST].CodesList.label,
      type: TEXT,
      [TEXT]: {
        maxLength: 1,
        pattern: ''
      }
    };
  }

  return listCodes.map((c, index) =>
    getCollecteVariable(
      `${questionName}${index + 1}`,
      `${c.value} - ${c.label}`,
      { x: index + 1 },
      reponseFormatValues
    )
  );
}

export function getCollectedVariablesTable(questionName, form, codesListStore) {
  function getReponsesValues(measure) {
    let reponseFormatValues = {};

    if (measure.type === SIMPLE) {
      reponseFormatValues = {
        codeListReference: '',
        codeListReferenceLabel: '',
        type: measure[SIMPLE].type,
        BOOLEAN: measure[SIMPLE].BOOLEAN,
        DATE: measure[SIMPLE].DATE,
        NUMERIC: measure[SIMPLE].NUMERIC,
        TEXT: measure[SIMPLE].TEXT
      };
    } else if (measure.type === SINGLE_CHOICE) {
      reponseFormatValues = {
        codeListReference: measure[SINGLE_CHOICE].CodesList.id,
        codeListReferenceLabel: measure[SINGLE_CHOICE].CodesList.label,
        type: TEXT,
        [TEXT]: {
          maxLength: 1,
          pattern: ''
        }
      };
    }
    return reponseFormatValues;
  }
  const collectedVariables = [];
  let codesListState;
  let codesStore;
  let codesStatePrimary;
  let codesStateSecondary;
  let codePrimary;
  let codeSecondary;
  let measure;
  const {
    [PRIMARY]: primaryState,
    [SECONDARY]: secondaryState,
    [MEASURE]: measureState,
    [LIST_MEASURE]: listMeasuresState
  } = form;

  if (primaryState.type === CODES_LIST) {
    const {
      [CODES_LIST]: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: {
          codes: componentCodesStatePrimary,
          id: codesListIdPrimary
        }
      }
    } = primaryState;

    codesListState = codesListStore[codesListIdPrimary] || {};
    codesStore = codesListState.codes || {};
    codesStatePrimary = Object.keys(codesStore).map(key => codesStore[key]);
    if (codesStatePrimary.length === 0)
      codesStatePrimary = componentCodesStatePrimary;

    if (secondaryState && secondaryState.showSecondaryAxis) {
      const {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: {
          codes: componentCodesStateSecondary,
          id: codesListIdSecondary
        }
      } = secondaryState;

      codesListState = codesListStore[codesListIdSecondary] || {};
      codesStore = codesListState.codes || {};
      codesStateSecondary = Object.keys(codesStore).map(key => codesStore[key]);
      if (codesStateSecondary.length === 0)
        codesStateSecondary = componentCodesStateSecondary;

      // First case
      for (let i = 0; i < codesStatePrimary.length; i += 1) {
        codePrimary = codesStatePrimary[i];
        for (let j = 0; j < codesStateSecondary.length; j += 1) {
          codeSecondary = codesStateSecondary[j];
          collectedVariables.push(
            getCollecteVariable(
              `${questionName}${i + 1}${j + 1}`,
              `${codePrimary.label}-${codeSecondary.label}-${
                measureState.label
              }`,
              { x: i + 1, y: j + 1 },
              getReponsesValues(measureState)
            )
          );
        }
      }
    } else {
      // Second case
      for (let i = 0; i < codesStatePrimary.length; i += 1) {
        codePrimary = codesStatePrimary[i];
        for (let j = 0; j < listMeasuresState.measures.length; j += 1) {
          measure = listMeasuresState.measures[j];
          collectedVariables.push(
            getCollecteVariable(
              `${questionName}${i + 1}${j + 1}`,
              `${codePrimary.label}-${measure.label}`,
              {
                x: i + 1,
                y: j + 1
              },
              getReponsesValues(measure)
            )
          );
        }
      }
    }
  } else {
    const { LIST: { numLinesMin, numLinesMax } } = primaryState;
    const numLines = numLinesMax - numLinesMin + 1;

    // Third case
    for (let i = 0; i < numLines; i += 1) {
      for (let j = 0; j < listMeasuresState.measures.length; j += 1) {
        measure = listMeasuresState.measures[j];

        collectedVariables.push(
          getCollecteVariable(
            `${questionName}${i + 1}${j + 1}`,
            `Line${i + 1}-${measure.label}`,
            {
              x: i + 1,
              y: j + 1
            },
            getReponsesValues(measure)
          )
        );
      }
    }
  }
  return collectedVariables.sort(sortByYAndX());
}

export function generateCollectedVariables(
  responseFormat,
  questionName,
  form,
  codesListStore
) {
  let generatedCollectedVariables = [];

  if (responseFormat === SIMPLE) {
    generatedCollectedVariables = [
      getCollecteVariable(
        questionName,
        `${questionName} label`,
        undefined,
        form
      )
    ];
  } else if (responseFormat === SINGLE_CHOICE) {
    generatedCollectedVariables = [
      getCollecteVariable(questionName, `${questionName} label`, undefined, {
        codeListReference: form.CodesList.id,
        codeListReferenceLabel: form.CodesList.label,
        type: TEXT,
        [TEXT]: {
          maxLength: 1,
          pattern: ''
        }
      })
    ];
  } else if (responseFormat === MULTIPLE_CHOICE) {
    generatedCollectedVariables = getCollectedVariablesMultiple(
      questionName,
      form,
      codesListStore
    );
  } else if (responseFormat === TABLE) {
    generatedCollectedVariables = getCollectedVariablesTable(
      questionName,
      form,
      codesListStore
    );
  }

  return generatedCollectedVariables;
}
<commit_msg>Fix collected variables generation for tab format response<commit_after>import {
  QUESTION_TYPE_ENUM,
  DIMENSION_TYPE,
  DIMENSION_FORMATS,
  DEFAULT_CODES_LIST_SELECTOR_PATH,
  DATATYPE_NAME
} from 'constants/pogues-constants';
import { uuid } from 'utils/utils';
import { debug } from 'util';
import { sortByWeight } from 'model/transformations/codes-list';
const { SIMPLE, SINGLE_CHOICE, MULTIPLE_CHOICE, TABLE } = QUESTION_TYPE_ENUM;
const { PRIMARY, SECONDARY, MEASURE, LIST_MEASURE } = DIMENSION_TYPE;
const { CODES_LIST } = DIMENSION_FORMATS;
const { TEXT, BOOLEAN } = DATATYPE_NAME;

export function sortByYAndX(store) {
  return (id1, id2) => {
    let c1 = id1;
    let c2 = id2;
    if (store) {
      c1 = store[id1];
      c2 = store[id2];
    }

    if (!c1.y) return c1.x - c2.x;
    return c1.y * 100 + c1.x - (c2.y * 100 + c2.x);
  };
}

export function getCollecteVariable(
  name,
  label,
  coordinates,
  reponseFormatValues = {}
) {
  let collectedVariable = {
    id: uuid(),
    name,
    label,
    ...reponseFormatValues
  };

  if (coordinates) collectedVariable = { ...collectedVariable, ...coordinates };

  return collectedVariable;
}

export function getCollectedVariablesMultiple(
  questionName,
  form,
  codesListStore
) {
  /**
   * This method will recursively sort an array of code.
   * A code have a depth, a weight and maybe a parent.
   * We will first sort codes with the depth=1, and recurively for each code,
   * sort its direct children.
   */
  function sortCodes(codes = [], depth = 1, parent = '') {
    const filtered = codes.filter(
      code => code.depth === depth && code.parent === parent
    );
    if (filtered.length === 0) {
      return [];
    }
    return filtered
      .sort((code1, code2) => {
        const weight1 = code1.weight;
        const weight2 = code2.weight;
        if (weight1 < weight2) return -1;
        if (weight1 > weight2) return 1;
        return 0;
      })
      .map(code => [code, ...sortCodes(codes, depth + 1, code.value)])
      .reduce((acc, res) => [...acc, ...res], []);
  }

  const {
    [PRIMARY]: { [DEFAULT_CODES_LIST_SELECTOR_PATH]: { codes, id } },
    [MEASURE]: { type: typeMeasure }
  } = form;
  let listCodes = sortCodes(codes);
  if (listCodes.length === 0 && codesListStore[id]) {
    const codesStore = codesListStore[id].codes;
    listCodes = Object.keys(codesStore).map(key => codesStore[key]);
  }

  let reponseFormatValues = {
    type: BOOLEAN,
    [BOOLEAN]: {}
  };

  if (typeMeasure === CODES_LIST) {
    reponseFormatValues = {
      codeListReference: form[MEASURE][CODES_LIST].CodesList.id,
      codeListReferenceLabel: form[MEASURE][CODES_LIST].CodesList.label,
      type: TEXT,
      [TEXT]: {
        maxLength: 1,
        pattern: ''
      }
    };
  }

  return listCodes.map((c, index) =>
    getCollecteVariable(
      `${questionName}${index + 1}`,
      `${c.value} - ${c.label}`,
      { x: index + 1 },
      reponseFormatValues
    )
  );
}

export function getCollectedVariablesTable(questionName, form, codesListStore) {
  /**
   * This method will recursively sort an array of code.
   * A code have a depth, a weight and maybe a parent.
   * We will first sort codes with the depth=1, and recurively for each code,
   * sort its direct children.
   */
  function sortCodes(codes = [], depth = 1, parent = '') {
    const filtered = codes.filter(
      code => code.depth === depth && code.parent === parent
    );
    if (filtered.length === 0) {
      return [];
    }
    return filtered
      .sort((code1, code2) => {
        const weight1 = code1.weight;
        const weight2 = code2.weight;
        if (weight1 < weight2) return -1;
        if (weight1 > weight2) return 1;
        return 0;
      })
      .map(code => [code, ...sortCodes(codes, depth + 1, code.value)])
      .reduce((acc, res) => [...acc, ...res], []);
  }

  function getReponsesValues(measure) {
    let reponseFormatValues = {};

    if (measure.type === SIMPLE) {
      reponseFormatValues = {
        codeListReference: '',
        codeListReferenceLabel: '',
        type: measure[SIMPLE].type,
        BOOLEAN: measure[SIMPLE].BOOLEAN,
        DATE: measure[SIMPLE].DATE,
        NUMERIC: measure[SIMPLE].NUMERIC,
        TEXT: measure[SIMPLE].TEXT
      };
    } else if (measure.type === SINGLE_CHOICE) {
      reponseFormatValues = {
        codeListReference: measure[SINGLE_CHOICE].CodesList.id,
        codeListReferenceLabel: measure[SINGLE_CHOICE].CodesList.label,
        type: TEXT,
        [TEXT]: {
          maxLength: 1,
          pattern: ''
        }
      };
    }
    return reponseFormatValues;
  }
  const collectedVariables = [];
  let codesListState;
  let codesStore;
  let codesStatePrimary;
  let codesStateSecondary;
  let codePrimary;
  let codeSecondary;
  let measure;
  const {
    [PRIMARY]: primaryState,
    [SECONDARY]: secondaryState,
    [MEASURE]: measureState,
    [LIST_MEASURE]: listMeasuresState
  } = form;

  if (primaryState.type === CODES_LIST) {
    const {
      [CODES_LIST]: {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: {
          codes: componentCodesStatePrimary,
          id: codesListIdPrimary
        }
      }
    } = primaryState;

    codesListState = codesListStore[codesListIdPrimary] || {};
    codesStore = codesListState.codes || {};
    codesStatePrimary = Object.keys(codesStore).map(key => codesStore[key]);
    if (codesStatePrimary.length === 0)
      codesStatePrimary = componentCodesStatePrimary;
    codesStatePrimary = sortCodes(codesStatePrimary);
    if (secondaryState && secondaryState.showSecondaryAxis) {
      const {
        [DEFAULT_CODES_LIST_SELECTOR_PATH]: {
          codes: componentCodesStateSecondary,
          id: codesListIdSecondary
        }
      } = secondaryState;

      codesListState = codesListStore[codesListIdSecondary] || {};
      codesStore = codesListState.codes || {};
      codesStateSecondary = Object.keys(codesStore).map(key => codesStore[key]);
      if (codesStateSecondary.length === 0)
        codesStateSecondary = componentCodesStateSecondary;

      // First case
      for (let i = 0; i < codesStatePrimary.length; i += 1) {
        codePrimary = codesStatePrimary[i];
        for (let j = 0; j < codesStateSecondary.length; j += 1) {
          codeSecondary = codesStateSecondary[j];
          collectedVariables.push(
            getCollecteVariable(
              `${questionName}${i + 1}${j + 1}`,
              `${codePrimary.label}-${codeSecondary.label}-${
                measureState.label
              }`,
              { x: i + 1, y: j + 1 },
              getReponsesValues(measureState)
            )
          );
        }
      }
    } else {
      // Second case
      for (let i = 0; i < codesStatePrimary.length; i += 1) {
        codePrimary = codesStatePrimary[i];
        for (let j = 0; j < listMeasuresState.measures.length; j += 1) {
          measure = listMeasuresState.measures[j];
          collectedVariables.push(
            getCollecteVariable(
              `${questionName}${i + 1}${j + 1}`,
              `${codePrimary.label}-${measure.label}`,
              {
                x: i + 1,
                y: j + 1
              },
              getReponsesValues(measure)
            )
          );
        }
      }
    }
  } else {
    const { LIST: { numLinesMin, numLinesMax } } = primaryState;
    const numLines = numLinesMax - numLinesMin + 1;

    // Third case
    for (let i = 0; i < numLines; i += 1) {
      for (let j = 0; j < listMeasuresState.measures.length; j += 1) {
        measure = listMeasuresState.measures[j];

        collectedVariables.push(
          getCollecteVariable(
            `${questionName}${i + 1}${j + 1}`,
            `Line${i + 1}-${measure.label}`,
            {
              x: i + 1,
              y: j + 1
            },
            getReponsesValues(measure)
          )
        );
      }
    }
  }
  return collectedVariables.sort(sortByYAndX());
}

export function generateCollectedVariables(
  responseFormat,
  questionName,
  form,
  codesListStore
) {
  let generatedCollectedVariables = [];

  if (responseFormat === SIMPLE) {
    generatedCollectedVariables = [
      getCollecteVariable(
        questionName,
        `${questionName} label`,
        undefined,
        form
      )
    ];
  } else if (responseFormat === SINGLE_CHOICE) {
    generatedCollectedVariables = [
      getCollecteVariable(questionName, `${questionName} label`, undefined, {
        codeListReference: form.CodesList.id,
        codeListReferenceLabel: form.CodesList.label,
        type: TEXT,
        [TEXT]: {
          maxLength: 1,
          pattern: ''
        }
      })
    ];
  } else if (responseFormat === MULTIPLE_CHOICE) {
    generatedCollectedVariables = getCollectedVariablesMultiple(
      questionName,
      form,
      codesListStore
    );
  } else if (responseFormat === TABLE) {
    generatedCollectedVariables = getCollectedVariablesTable(
      questionName,
      form,
      codesListStore
    );
  }

  return generatedCollectedVariables;
}
<|endoftext|>


<commit_before>import {connect} from 'zefir/utils'
import Slider from '../../../components/ui/slider'
import Arrow from './arrow.svg'

const SECONDS_PRICE = 5
const SECONDS_MAX = 20000000
const SECONDS_MIN = 270000

const CALLS_PRICE = 20
const CALLS_MAX = 100000000
const CALLS_MIN = 1000000

const PricingEstimate = ({
  calls, seconds, handleCallsChange, handleSecondsChange, price
}) => (

    {(() => {
      const callsPrice = Math.floor(
        calls.value / CALLS_MIN * CALLS_PRICE - // calculate base price
        ((calls.value - CALLS_MIN) * 757 / CALLS_MAX) // calculate discount
      )

      const secondsPrice = Math.floor(
        seconds.value / SECONDS_MIN * SECONDS_PRICE - // calculate base price
        ((seconds.value - SECONDS_MIN) * 122 / SECONDS_MAX) // calculate discount
      )

      price = callsPrice + secondsPrice
    })()}

      {/* TODO: Handle max value */}

API calls per month

{calls.value.toLocaleString()}

        <Slider {...calls} onChange={handleCallsChange} />

Script seconds per month

{seconds.value.toLocaleString()}

        <Slider {...seconds} onChange={handleSecondsChange} />

Your pricing plan

{
            price === 25 ? 'Base' : 'Growth'
          }

          <Arrow />

Monthly price

${price}

)

PricingEstimate.init = ({
  form: {fields: {calls, seconds}, setValue}
}) => {
  return {
    calls,
    seconds,
    handleCallsChange: value => setValue('calls', value),
    handleSecondsChange: value => setValue('seconds', value)
  }
}

PricingEstimate.form = {
  formName: 'PricingEstimateForm',
  fields: {
    calls: {
      min: CALLS_MIN,
      step: 1000000,
      max: CALLS_MAX,
      value: CALLS_MIN
    },
    seconds: {
      min: SECONDS_MIN,
      step: 10000,
      max: SECONDS_MAX,
      value: SECONDS_MIN
    }
  }
}

export default connect(PricingEstimate)
<commit_msg>feat(views): add tooltips<commit_after>import {connect} from 'zefir/utils'
import Slider from '../../../components/ui/slider'
import Arrow from './arrow.svg'

const SECONDS_PRICE = 5
const SECONDS_MAX = 20000000
const SECONDS_MIN = 270000

const CALLS_PRICE = 20
const CALLS_MAX = 100000000
const CALLS_MIN = 1000000

const PricingEstimate = ({
  calls, seconds, handleCallsChange, handleSecondsChange, price
}) => (

    {(() => {
      const callsPrice = Math.floor(
        calls.value / CALLS_MIN * CALLS_PRICE - // calculate base price
        ((calls.value - CALLS_MIN) * 757 / CALLS_MAX) // calculate discount
      )

      const secondsPrice = Math.floor(
        seconds.value / SECONDS_MIN * SECONDS_PRICE - // calculate base price
        ((seconds.value - SECONDS_MIN) * 122 / SECONDS_MAX) // calculate discount
      )

      price = callsPrice + secondsPrice
    })()}

      {/* TODO: Handle max value */}

API calls per month What is an API call?

{calls.value.toLocaleString()}

        <Slider {...calls} onChange={handleCallsChange} />

Script seconds per month What is a script second?

{seconds.value.toLocaleString()}

        <Slider {...seconds} onChange={handleSecondsChange} />

Your pricing plan

{
            price === 25 ? 'Base' : 'Growth'
          }

          <Arrow />

Monthly price

${price}

)

PricingEstimate.init = ({
  form: {fields: {calls, seconds}, setValue}
}) => {
  return {
    calls,
    seconds,
    handleCallsChange: value => setValue('calls', value),
    handleSecondsChange: value => setValue('seconds', value)
  }
}

PricingEstimate.form = {
  formName: 'PricingEstimateForm',
  fields: {
    calls: {
      min: CALLS_MIN,
      step: 1000000,
      max: CALLS_MAX,
      value: CALLS_MIN
    },
    seconds: {
      min: SECONDS_MIN,
      step: 10000,
      max: SECONDS_MAX,
      value: SECONDS_MIN
    }
  }
}

export default connect(PricingEstimate)
<|endoftext|>


<commit_before>import Immutable from 'immutable'
import { createReducer } from 'redux-immutablejs'

import * as actions from './actionTypes'

export const initialState = Immutable.fromJS({
  requesting: false,
  error: null,
  search: {
    features: false,
    focus: false,
    overlay: true,
  }
})

export default createReducer(initialState, {

  [actions.UPDATE]: (state, action) => state.merge({ ...action.payload }),
  [actions.RESET]: state => state.merge({ ...initialState.toJS() }),

})
<commit_msg>add todo<commit_after>import Immutable from 'immutable'
import { createReducer } from 'redux-immutablejs'

import * as actions from './actionTypes'

export const initialState = Immutable.fromJS({
  requesting: false,
  error: null,
  search: {
    features: false,
    focus: false,
    overlay: true,
  }
})

export default createReducer(initialState, {

  // TODO - this doesn't work for nested objects (replace not merge)
  [actions.UPDATE]: (state, action) => state.merge({ ...action.payload }),
  [actions.RESET]: state => state.merge({ ...initialState.toJS() }),

})
<|endoftext|>


<commit_before>/*
 *
 *                              ~ Store Lib ~
 *  Enables apps to store persistant data using simple unique key/value pairs.
 */
'use strict';

var process = require('process');
const ipc = require('ipc');
const jetpack = require('fs-jetpack');
const im = require('./instance-manager');
const Datastore = require('nedb');
const meta = require('./app-meta');

module.exports = (function() {

  let getStore = function (event) {
    let id = event.sender.getId();
    let instance = im.get(id);
    let metaContents = meta.contents(instance.app.name);
    let appname = metaContents.name + metaContents.version;
    let fn = `${__dirname}/../../store/${appname}.db`;

    let personalDb = new Datastore({
      filename: fn,
      autoload: true
    });

    return personalDb;
  };

  ipc.on('store-get', function(event, key, opt) {
    let db = getStore(event);
    db.findOne({'key': key}, function (err, doc) {
      //if(err != null) event.returnValue = err;
      event.returnValue = doc;
    });

  });

  ipc.on('store-put', function(event, key, val) {
    let db = getStore(event);

    db.remove({'key': key});
    db.insert({'key': key, 'value': val}, function (err, newDoc) {
      //if(err == null) event.returnValue = err;
      event.returnValue = newDoc;
    });
  });

  return {
    'getStore': getStore
  };

})();
<commit_msg>app db files are placed in a sub directory of store to prevent contamination with apps.db and repositories.db<commit_after>/*
 *
 *                              ~ Store Lib ~
 *  Enables apps to store persistant data using simple unique key/value pairs.
 */
'use strict';

var process = require('process');
const ipc = require('ipc');
const jetpack = require('fs-jetpack');
const im = require('./instance-manager');
const Datastore = require('nedb');
const meta = require('./app-meta');

module.exports = (function() {

  let getStore = function (event) {
    let id = event.sender.getId();
    let instance = im.get(id);
    let metaContents = meta.contents(instance.app.name);
    let appname = metaContents.name;
    let fn = `${__dirname}/../../store/apps/${appname}.db`;

    let personalDb = new Datastore({
      filename: fn,
      autoload: true
    });

    return personalDb;
  };

  ipc.on('store-get', function(event, key, opt) {
    let db = getStore(event);
    db.findOne({'key': key}, function (err, doc) {
      //if(err != null) event.returnValue = err;
      event.returnValue = doc;
    });

  });

  ipc.on('store-put', function(event, key, val) {
    let db = getStore(event);

    db.remove({'key': key});
    db.insert({'key': key, 'value': val}, function (err, newDoc) {
      //if(err == null) event.returnValue = err;
      event.returnValue = newDoc;
    });
  });

  return {
    'getStore': getStore
  };

})();
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import "../../loading-spinner.js";

export default class SignatureView extends LitElement {

    constructor() {
        super();

        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            signature: {
                type: Object
            },
            mode: {
                type: String // view | plot
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);

        this.mode = "SBS";
    }

    connectedCallback() {
        super.connectedCallback();

        this._config = {...this.getDefaultConfig(), ...this.config};
    }

    updated(changedProperties) {
        if (changedProperties.has("signature")) {
            this.signatureObserver();
        }
    }

    signatureObserver() {
        if (!this.signature || this.signature?.errorState) {
            return;
        }

        const counts = this.signature.counts;
        const categories = counts.map(point => point?.context);
        const data = counts.map(point => point?.total);

        const substitutionClass = string => {
            const [, pair, letter] = string.match(/[ACTG]\[(([ACTG])>[ACTG])\][ACTG]+/);
            return {pair, letter};
        };

        const rearragementClass = string => {
            const fields = string.split("_");
            const pair = fields[0] + "_" + fields[1];
            const letter = fields[2] || "";
            return {pair, letter};
        };

        const dataset = {
            "C>A": {
                color: "#31bef0",
                data: []
            },
            "C>G": {
                color: "#000000",
                data: []
            },
            "C>T": {
                color: "#e62725",
                data: []
            },
            "T>A": {
                color: "#cbcacb",
                data: []
            },
            "T>C": {
                color: "#a1cf63",
                data: []
            },
            "T>G": {
                color: "#edc8c5",
                data: []
            },

            "clustered_del": {
                color: "#31bef0",
                data: []
            },
            "clustered_tds": {
                color: "#000000",
                data: []
            },
            "clustered_inv": {
                color: "#e62725",
                data: []
            },
            "clustered_trans": {
                color: "#cbcacb",
                data: []
            },
            "non-clustered_del": {
                color: "#31bef0",
                data: []
            },
            "non-clustered_tds": {
                color: "#000000",
                data: []
            },
            "non-clustered_inv": {
                color: "#e62725",
                data: []
            },
            "non-clustered_trans": {
                color: "#cbcacb",
                data: []
            },
        };

        counts.forEach(count => {
            if (count) {
                if (this.mode === "SBS") {
                    const {pair} = substitutionClass(count.context);
                    dataset[pair].data.push(count.total);
                } else {
                    const {pair} = rearragementClass(count.context);
                    dataset[pair].data.push(count.total);
                }
            }
        });

        const addRects = chart => {
            $(".rect", this).remove();
            $(".rect-label", this).remove();
            let lastStart = 0;
            Object.keys(dataset).forEach(k => {
                // console.log("chart.categories", chart.xAxis)
                // console.log("k", dataset[k].data.length)
                const xAxis = chart.xAxis[0];
                chart.renderer.rect(xAxis.toPixels(lastStart), 30, xAxis.toPixels(dataset[k].data.length) - xAxis.toPixels(1), 10, 0)
                    .attr({
                        fill: dataset[k].color,
                        zIndex: 2
                    }).addClass("rect")
                    .add();

                // for some reason toPixels(lastStart + dataset[k].data.length / 2) isn't centered
                chart.renderer.label(k, xAxis.toPixels(lastStart - 4 + dataset[k].data.length / 2), 0, "")
                    .css({
                        color: "#000",
                        fontSize: "13px"
                    })
                    .attr({
                        padding: 8,
                        r: 5,
                        zIndex: 3
                    }).addClass("rect-label")
                    .add();

                lastStart += dataset[k].data.length;
            });
        };

        $(`#${this._prefix}SignaturePlot`).highcharts({
            title: "title",
            chart: {
                height: this._config.height, // use plain CSS to avoid resize when <loading-spinner> is visible
                type: "column",
                events: {
                    redraw: function () {
                        addRects(this);
                    },
                    load: function () {
                        addRects(this);
                    }
                },
                marginTop: 70
            },
            credits: {
                enabled: false
            },
            legend: {
                enabled: false
            },
            tooltip: {
                formatter: function () {
                    if (this.x.includes("[")) {
                        const {pair, letter} = substitutionClass(this.x);
                        return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "") + `<strong>: ${this.y}</strong>`;
                    } else {
                        const {pair, letter} = rearragementClass(this.x);
                        return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "") + `<strong>: ${this.y}</strong>`;
                    }
                    // const {pair, letter} = substitutionClass(this.x);
                    // return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("\[", "").replace("\]", "") + `<strong>:${this.y}</strong>`;
                }
            },
            xAxis: {
                categories: categories,
                labels: {
                    rotation: -90,
                    formatter: data => {
                        if (this.mode === "SBS") {
                            const {pair, letter} = substitutionClass(data.value);
                            return data.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "");
                        } else {
                            const {pair, letter} = rearragementClass(data.value);
                            return data.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "");
                        }
                        // const {pair, letter} = substitutionClass(this.value);
                        // return this.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("\[", "").replace("\]", "");
                    }
                }
            },
            colors: Object.keys(dataset).flatMap(key => Array(dataset[key].data.length).fill(dataset[key].color)),
            series: [{
                colorByPoint: "true",
                data: data
            }]
        });
    }

    render() {
        if (this.signature?.errorState) {
            return html`<div class="alert alert-danger">${this.signature.errorState}</div>`;
        }

        return html`

                ${this.signature ? html`

${this.signature.counts.map(s => s.total).reduce((a, b) => a + b, 0)} Substitutions

                ` : html`
                    <loading-spinner></loading-spinner>`
                }

        `;
    }

    getDefaultConfig() {
        return {
            // width: null, width is always 100% of the visible container
            height: 240,
        };
    }

}

customElements.define("signature-view", SignatureView);
<commit_msg>wc: allow displaying fitting bar plot in signature view (#381)<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import "../../loading-spinner.js";

export default class SignatureView extends LitElement {

    constructor() {
        super();

        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            signature: {
                type: Object
            },
            mode: {
                type: String // view | plot
            },
            plots: {
                type: Array,
            },
            config: {
                type: Object
            }
        };
    }

    _init() {
        this._prefix = UtilsNew.randomString(8);
        this.plots = ["counts"];
        this.mode = "SBS";
    }

    connectedCallback() {
        super.connectedCallback();

        this._config = {...this.getDefaultConfig(), ...this.config};
    }

    updated(changedProperties) {
        if (changedProperties.has("signature") && this.plots.includes("counts")) {
            this.signatureCountsObserver();
        }

        if (changedProperties.has("signature") && this.plots.includes("fitting")) {
            this.signatureFittingObserver();
        }
    }

    signatureCountsObserver() {
        if (!this.signature || this.signature?.errorState) {
            return;
        }

        const counts = this.signature.counts;
        const categories = counts.map(point => point?.context);
        const data = counts.map(point => point?.total);

        const substitutionClass = string => {
            const [, pair, letter] = string.match(/[ACTG]\[(([ACTG])>[ACTG])\][ACTG]+/);
            return {pair, letter};
        };

        const rearragementClass = string => {
            const fields = string.split("_");
            const pair = fields[0] + "_" + fields[1];
            const letter = fields[2] || "";
            return {pair, letter};
        };

        const dataset = {
            "C>A": {
                color: "#31bef0",
                data: []
            },
            "C>G": {
                color: "#000000",
                data: []
            },
            "C>T": {
                color: "#e62725",
                data: []
            },
            "T>A": {
                color: "#cbcacb",
                data: []
            },
            "T>C": {
                color: "#a1cf63",
                data: []
            },
            "T>G": {
                color: "#edc8c5",
                data: []
            },

            "clustered_del": {
                color: "#31bef0",
                data: []
            },
            "clustered_tds": {
                color: "#000000",
                data: []
            },
            "clustered_inv": {
                color: "#e62725",
                data: []
            },
            "clustered_trans": {
                color: "#cbcacb",
                data: []
            },
            "non-clustered_del": {
                color: "#31bef0",
                data: []
            },
            "non-clustered_tds": {
                color: "#000000",
                data: []
            },
            "non-clustered_inv": {
                color: "#e62725",
                data: []
            },
            "non-clustered_trans": {
                color: "#cbcacb",
                data: []
            },
        };

        counts.forEach(count => {
            if (count) {
                if (this.mode === "SBS") {
                    const {pair} = substitutionClass(count.context);
                    dataset[pair].data.push(count.total);
                } else {
                    const {pair} = rearragementClass(count.context);
                    dataset[pair].data.push(count.total);
                }
            }
        });

        const addRects = function (chart) {
            $(".rect", this).remove();
            $(".rect-label", this).remove();
            let lastStart = 0;
            Object.keys(dataset).forEach(k => {
                // console.log("chart.categories", chart.xAxis)
                // console.log("k", dataset[k].data.length)
                const xAxis = chart.xAxis[0];
                chart.renderer.rect(xAxis.toPixels(lastStart), 30, xAxis.toPixels(dataset[k].data.length) - xAxis.toPixels(1), 10, 0)
                    .attr({
                        fill: dataset[k].color,
                        zIndex: 2
                    }).addClass("rect")
                    .add();

                // for some reason toPixels(lastStart + dataset[k].data.length / 2) isn't centered
                chart.renderer.label(k, xAxis.toPixels(lastStart - 4 + dataset[k].data.length / 2), 0, "")
                    .css({
                        color: "#000",
                        fontSize: "13px"
                    })
                    .attr({
                        padding: 8,
                        r: 5,
                        zIndex: 3
                    }).addClass("rect-label")
                    .add();

                lastStart += dataset[k].data.length;
            });
        };

        $(`#${this._prefix}SignatureCountsPlot`).highcharts({
            title: "title",
            chart: {
                height: this._config.height, // use plain CSS to avoid resize when <loading-spinner> is visible
                type: "column",
                events: {
                    redraw: function () {
                        addRects(this);
                    },
                    load: function () {
                        addRects(this);
                    }
                },
                marginTop: 70
            },
            credits: {
                enabled: false
            },
            legend: {
                enabled: false
            },
            tooltip: {
                formatter: function () {
                    if (this.x.includes("[")) {
                        const {pair, letter} = substitutionClass(this.x);
                        return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "") + `<strong>: ${this.y}</strong>`;
                    } else {
                        const {pair, letter} = rearragementClass(this.x);
                        return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "") + `<strong>: ${this.y}</strong>`;
                    }
                    // const {pair, letter} = substitutionClass(this.x);
                    // return this.x.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("\[", "").replace("\]", "") + `<strong>:${this.y}</strong>`;
                }
            },
            xAxis: {
                categories: categories,
                labels: {
                    rotation: -90,
                    formatter: data => {
                        if (this.mode === "SBS") {
                            const {pair, letter} = substitutionClass(data.value);
                            return data.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "");
                        } else {
                            const {pair, letter} = rearragementClass(data.value);
                            return data.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("[", "").replace("]", "");
                        }
                        // const {pair, letter} = substitutionClass(this.value);
                        // return this.value.replace(pair, `<span style="color:${dataset[pair].color}">${letter}</span>`).replace("\[", "").replace("\]", "");
                    }
                }
            },
            colors: Object.keys(dataset).flatMap(key => Array(dataset[key].data.length).fill(dataset[key].color)),
            series: [{
                colorByPoint: "true",
                data: data
            }]
        });
    }

    signatureFittingObserver() {
        if (!this.signature?.fitting) {
            return;
        }

        const scores = this.signature.fitting.scores;

        $(`#${this._prefix}SignatureFittingPlot`).highcharts({
            // title: "title",
            chart: {
                height: this._config.height,
                type: "bar",
                events: {
                    // redraw: function () {
                    //     addRects(this);
                    // },
                    // load: function () {
                    //     addRects(this);
                    // }
                },
                marginTop: 70
            },
            title: null,
            credits: {
                enabled: false
            },
            legend: {
                enabled: false
            },
            xAxis: {
                categories: scores.map(score => score.signatureId),
            },
            yAxis: {
                min: 0,
                title: null,
            },
            // colors: Object.keys(dataset).flatMap(key => Array(dataset[key].data.length).fill(dataset[key].color)),
            series: [{
                data: scores.map(score => score.value),
                name: "Value",
            }]
        });

    }

    render() {
        if (this.signature?.errorState) {
            return html`<div class="alert alert-danger">${this.signature.errorState}</div>`;
        }

        return html`

                ${this.signature && this.plots ? html`

                    ${this.plots.includes("counts") ? html `

${this.signature.counts.map(s => s.total).reduce((a, b) => a + b, 0)} Substitutions

                    ` : null}

                    ${this.plots.includes("fitting") ? html`

                    ` : null}

                ` : html`
                    <loading-spinner></loading-spinner>`
                }

        `;
    }

    getDefaultConfig() {
        return {
            // width: null, width is always 100% of the visible container
            height: 240,
        };
    }

}

customElements.define("signature-view", SignatureView);
<|endoftext|>


<commit_before>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../../../languageHandler";
import MatrixClientPeg from "../../../../../MatrixClientPeg";
import sdk from "../../../../..";
import AccessibleButton from "../../../elements/AccessibleButton";
import Modal from "../../../../../Modal";
import dis from "../../../../../dispatcher";

export default class AdvancedRoomSettingsTab extends React.Component {
    static propTypes = {
        roomId: PropTypes.string.isRequired,
        closeSettingsFn: PropTypes.func.isRequired,
    };

    constructor() {
        super();

        this.state = {
            // This is eventually set to the value of room.getRecommendedVersion()
            upgradeRecommendation: null,
        };
    }

    componentWillMount() {
        // we handle lack of this object gracefully later, so don't worry about it failing here.
        const room = MatrixClientPeg.get().getRoom(this.props.roomId);
        room.getRecommendedVersion().then((v) => {
            const tombstone = room.currentState.getStateEvents("m.room.tombstone", "");

            let additionalStateChanges = {};
            const createEvent = room.currentState.getStateEvents("m.room.create", "");
            let predecessor = createEvent ? createEvent.getContent().predecessor : null;
            if (predecessor && predecessor.room_id) {
                additionalStateChanges['oldRoomId'] = predecessor.room_id;
                additionalStateChanges['oldEventId'] = predecessor.event_id;
                additionalStateChanges['hasPreviousRoom'] = true;
            }

            this.setState({
                upgraded: tombstone && tombstone.getContent().replacement_room,
                upgradeRecommendation: v,
                ...additionalStateChanges,
            });
        });
    }

    _upgradeRoom = (e) => {
        const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
        const room = MatrixClientPeg.get().getRoom(this.props.roomId);
        Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: room});
    };

    _openDevtools = (e) => {
        const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
        Modal.createDialog(DevtoolsDialog, {roomId: this.props.roomId});
    };

    _onOldRoomClicked = (e) => {
        e.preventDefault();
        e.stopPropagation();

        dis.dispatch({
            action: 'view_room',
            room_id: this.state.oldRoomId,
            event_id: this.state.oldEventId,
        });
        this.props.closeSettingsFn();
    };

    render() {
        const client = MatrixClientPeg.get();
        const room = client.getRoom(this.props.roomId);

        let unfederatableSection;
        const createEvent = room.currentState.getStateEvents('m.room.create', '');
        if (createEvent && createEvent.getContent()['m.federate'] === false) {
            unfederatableSection =
{_t('This room is not accessible by remote Matrix servers')}
;
        }

        let roomUpgradeButton;
        if (this.state.upgradeRecommendation && this.state.upgradeRecommendation.needsUpgrade && !this.state.upgraded) {
            roomUpgradeButton = (

                        {_t(
                            "Warning: Upgrading a room will not automatically migrate room members " +
                            "to the new version of the room. We'll post a link to the new room in the old " +
                            "version of the room - room members will have to click this link to join the new room.",
                            {}, {
                                "b": (sub) => {sub},
                                "i": (sub) => {sub},
                            },
                        )}

                    <AccessibleButton onClick={this._upgradeRoom} kind='primary'>
                        {_t("Upgrade this room to the recommended room version")}
                    </AccessibleButton>

            );
        }

        let oldRoomLink;
        if (this.state.hasPreviousRoom) {
            oldRoomLink = (

                    {_t(
                        "This is the upgraded version of another room. Click here to visit the old room.",
                        {}, {
                            'a': (sub) => {
                                return (
                                    <AccessibleButton element='a' onClick={this._onOldRoomClicked}>
                                        {sub}
                                    </AccessibleButton>
                                );
                            },
                        },
                    )}

            );
        }

        return (

{_t("Advanced")}

                    {_t("Room information")}

                        {_t("Internal room ID:")}
                        {this.props.roomId}

                    {unfederatableSection}

                    {_t("Room version")}

                        {_t("Room version:")}
                        {room.getVersion()}

                    {oldRoomLink}
                    {roomUpgradeButton}

                    {_t("Developer options")}
                    <AccessibleButton onClick={this._openDevtools} kind='primary'>
                        {_t("Open Devtools")}
                    </AccessibleButton>

        );
    }
}
<commit_msg>let -> const<commit_after>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../../../languageHandler";
import MatrixClientPeg from "../../../../../MatrixClientPeg";
import sdk from "../../../../..";
import AccessibleButton from "../../../elements/AccessibleButton";
import Modal from "../../../../../Modal";
import dis from "../../../../../dispatcher";

export default class AdvancedRoomSettingsTab extends React.Component {
    static propTypes = {
        roomId: PropTypes.string.isRequired,
        closeSettingsFn: PropTypes.func.isRequired,
    };

    constructor() {
        super();

        this.state = {
            // This is eventually set to the value of room.getRecommendedVersion()
            upgradeRecommendation: null,
        };
    }

    componentWillMount() {
        // we handle lack of this object gracefully later, so don't worry about it failing here.
        const room = MatrixClientPeg.get().getRoom(this.props.roomId);
        room.getRecommendedVersion().then((v) => {
            const tombstone = room.currentState.getStateEvents("m.room.tombstone", "");

            const additionalStateChanges = {};
            const createEvent = room.currentState.getStateEvents("m.room.create", "");
            const predecessor = createEvent ? createEvent.getContent().predecessor : null;
            if (predecessor && predecessor.room_id) {
                additionalStateChanges['oldRoomId'] = predecessor.room_id;
                additionalStateChanges['oldEventId'] = predecessor.event_id;
                additionalStateChanges['hasPreviousRoom'] = true;
            }

            this.setState({
                upgraded: tombstone && tombstone.getContent().replacement_room,
                upgradeRecommendation: v,
                ...additionalStateChanges,
            });
        });
    }

    _upgradeRoom = (e) => {
        const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
        const room = MatrixClientPeg.get().getRoom(this.props.roomId);
        Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: room});
    };

    _openDevtools = (e) => {
        const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog');
        Modal.createDialog(DevtoolsDialog, {roomId: this.props.roomId});
    };

    _onOldRoomClicked = (e) => {
        e.preventDefault();
        e.stopPropagation();

        dis.dispatch({
            action: 'view_room',
            room_id: this.state.oldRoomId,
            event_id: this.state.oldEventId,
        });
        this.props.closeSettingsFn();
    };

    render() {
        const client = MatrixClientPeg.get();
        const room = client.getRoom(this.props.roomId);

        let unfederatableSection;
        const createEvent = room.currentState.getStateEvents('m.room.create', '');
        if (createEvent && createEvent.getContent()['m.federate'] === false) {
            unfederatableSection =
{_t('This room is not accessible by remote Matrix servers')}
;
        }

        let roomUpgradeButton;
        if (this.state.upgradeRecommendation && this.state.upgradeRecommendation.needsUpgrade && !this.state.upgraded) {
            roomUpgradeButton = (

                        {_t(
                            "Warning: Upgrading a room will not automatically migrate room members " +
                            "to the new version of the room. We'll post a link to the new room in the old " +
                            "version of the room - room members will have to click this link to join the new room.",
                            {}, {
                                "b": (sub) => {sub},
                                "i": (sub) => {sub},
                            },
                        )}

                    <AccessibleButton onClick={this._upgradeRoom} kind='primary'>
                        {_t("Upgrade this room to the recommended room version")}
                    </AccessibleButton>

            );
        }

        let oldRoomLink;
        if (this.state.hasPreviousRoom) {
            oldRoomLink = (

                    {_t(
                        "This is the upgraded version of another room. Click here to visit the old room.",
                        {}, {
                            'a': (sub) => {
                                return (
                                    <AccessibleButton element='a' onClick={this._onOldRoomClicked}>
                                        {sub}
                                    </AccessibleButton>
                                );
                            },
                        },
                    )}

            );
        }

        return (

{_t("Advanced")}

                    {_t("Room information")}

                        {_t("Internal room ID:")}
                        {this.props.roomId}

                    {unfederatableSection}

                    {_t("Room version")}

                        {_t("Room version:")}
                        {room.getVersion()}

                    {oldRoomLink}
                    {roomUpgradeButton}

                    {_t("Developer options")}
                    <AccessibleButton onClick={this._openDevtools} kind='primary'>
                        {_t("Open Devtools")}
                    </AccessibleButton>

        );
    }
}
<|endoftext|>