<commit_before>'use strict'

const Atomic = require('./atomic')
const utils = require('../utils')

// attrs:
//   - type: text|password|tel|email|url
//   - value
//   - placeholder
//   - disabled
//   - autofocus
function Input (data) {
  const attrs = data.attr || {}
  this.type = attrs.type || 'text'
  this.value = attrs.value
  this.placeholder = attrs.placeholder
  this.autofocus = attrs.autofocus && (attrs.autofocus !== 'false')
  Atomic.call(this, data)
}

Input.prototype = Object.create(Atomic.prototype)

Input.prototype.create = function () {
  const node = document.createElement('input')
  const uuid = Math.floor(10000000000000 * Math.random()) + Date.now()
  this.className = 'weex-ipt-' + uuid
  this.styleId = 'weex-style-' + uuid
  node.classList.add(this.className)
  node.setAttribute('type', this.type)
  node.type = this.type
  // For the consistency of input component's width.
  // The date and time type of input will have a bigger width
  // when the 'box-sizing' is not set to 'border-box'
  node.classList.add('weex-element')
  this.value && (node.value = this.value)
  this.placeholder && (node.placeholder = this.placeholder)
  return node
}

Input.prototype.updateStyle = function (style) {
  Atomic.prototype.updateStyle.call(this, style)
  if (style && style.placeholderColor) {
    this.placeholderColor = style.placeholderColor
    this.setPlaceholderColor()
  }
}

Input.prototype.attr = {
  disabled: function (val) {
    this.node.disabled = val && val !== 'false'
  }
}

Input.prototype.event = {
  input: {
    updator () {
      return {
        attrs: {
          value: this.node.value
        }
      }
    },
    extra () {
      return {
        value: this.node.value,
        timestamp: Date.now()
      }
    }
  },

  change: {
    updator: function () {
      return {
        attrs: {
          value: this.node.value
        }
      }
    },
    extra: function () {
      return {
        value: this.node.value,
        timestamp: Date.now()
      }
    }
  }
}

Input.prototype.setPlaceholderColor = function () {
  if (!this.placeholderColor) {
    return
  }
  const vendors = [
    '::-webkit-input-placeholder',
    ':-moz-placeholder',
    '::-moz-placeholder',
    ':-ms-input-placeholder',
    ':placeholder-shown'
  ]
  let css = ''
  const cssRule = 'color: ' + this.placeholderColor + ';'
  for (let i = 0, l = vendors.length; i < l; i++) {
    css += '.' + this.className + vendors[i] + '{'
           + cssRule + '}'
  }
  utils.appendStyle(css, this.styleId, true)
}

module.exports = Input
<commit_msg>* [html5] able to update input's attrs<commit_after>'use strict'

const Atomic = require('./atomic')
import { appendStyle, extend } from '../utils'

const availableTypes = ['text', 'password', 'tel', 'email', 'url']
const DEFAULT_TYPE = 'text'

// attrs:
//   - type: text|password|tel|email|url
//   - value
//   - placeholder
//   - disabled
//   - autofocus
function Input (data) {
  Atomic.call(this, data)
}

Input.prototype = Object.create(Atomic.prototype)

Input.prototype.create = function () {
  const node = document.createElement('input')
  const uuid = Math.floor(10000000000000 * Math.random()) + Date.now()
  this.className = 'weex-ipt-' + uuid
  this.styleId = 'weex-style-' + uuid
  node.classList.add(this.className)
  node.classList.add('weex-element')
  this.placeholder && (node.placeholder = this.placeholder)
  return node
}

// updatable attributes
Input.prototype.attr = {
  disabled (val) {
    this.node.disabled = !!val
  },

  placeholder (val) {
    this.node.placeholder = val || ''
  },

  value (val) {
    this.node.value = val || ''
  },

  autofocus (val) {
    this.node.autofocus = !!val
  },

  type (val) {
    this.node.type = availableTypes.indexOf(val) !== -1
      ? val
      : DEFAULT_TYPE
  }
}

// updatable styles
Input.prototype.style = extend(
  Object.create(Atomic.prototype.style, {
    placeholderColor: function (val) {
      this.setPlaceholderColor(val)
    }
  }))

// events configurations
Input.prototype.event = {
  input: {
    updator () {
      return {
        attrs: {
          value: this.node.value
        }
      }
    },
    extra () {
      return {
        value: this.node.value,
        timestamp: Date.now()
      }
    }
  },

  change: {
    updator: function () {
      return {
        attrs: {
          value: this.node.value
        }
      }
    },
    extra: function () {
      return {
        value: this.node.value,
        timestamp: Date.now()
      }
    }
  }
}

Input.prototype.setPlaceholderColor = function (placeholderColor) {
  if (!placeholderColor) {
    return
  }
  const vendors = [
    '::-webkit-input-placeholder',
    ':-moz-placeholder',
    '::-moz-placeholder',
    ':-ms-input-placeholder',
    ':placeholder-shown'
  ]
  let css = ''
  const cssRule = 'color: ' + placeholderColor + ';'
  for (let i = 0, l = vendors.length; i < l; i++) {
    css += '.' + this.className + vendors[i] + '{'
           + cssRule + '}'
  }
  appendStyle(css, this.styleId, true)
}

module.exports = Input
<|endoftext|>


<commit_before>module.exports = function(app, config, io) {

  var media = require('./controllers/media')(config, io);
  var session = require('./controllers/session')(config);

  // Index page (canvas)
  app.get('/', media.home);

  /**
   * @api {get} /media Get all media
   * @apiGroup Media
   *
   * @apiParam {String} name Media name.
   *
   * @apiSuccess {Object[]} -               List of media.
   * @apiSuccess {String}   -.name          The name.
   * @apiSuccess {Number}   -.x             The x position on canvas.
   * @apiSuccess {Number}   -.y             The y position on canvas.
   * @apiSuccess {Number}   -.scale         The scale.
   * @apiSuccess {String}   -.url           The URL.
   * @apiSuccess {Object}   -.x             The x position on canvas.
   * @apiSuccess {Number}   -.angle         The angle.
   * @apiSuccess {String}   -.type          The type (e.g. 'whiteboard').
   * @apiSuccess {Number}   -.order         The order on canvas (layer).
   * @apiSuccess {Number}   -.session       The session id.
   */
  app.get('/media', media.getAll);

  /**
   * @api {get} /media/:name Get one media
   * @apiGroup Media
   *
   * @apiParam {String}     name              Media name.
   *
   * @apiSuccess {String}   name              The name.
   * @apiSuccess {Number}   x                 The x position on canvas.
   * @apiSuccess {Number}   y                 The y position on canvas.
   * @apiSuccess {Number}   scale             The scale.
   * @apiSuccess {String}   url               The URL.
   * @apiSuccess {Object}   x                 The x position on canvas.
   * @apiSuccess {Number}   angle             The angle.
   * @apiSuccess {String}   type              The type (e.g. 'whiteboard').
   * @apiSuccess {Number}   order             The order on canvas (layer).
   * @apiSuccess {Number}   session           The session id.
   */
  app.get('/media/:name', media.show);

  /**
   * @api {delete} /media/:name Delete one media
   * @apiGroup Media
   *
   * @apiParam {String}     name               Media name.
   *
   * @apiSuccess {String}   message            Return message.
   * @apiSuccess {String}   media_name         Name of deleted media.
   */
  app.delete('/media/:name', media.deleteOne);

  /**
   * @api {put} /media/:name Update media
   * @apiGroup Media
   *
   * @apiExample Example usage:
   *     body:
   *     {
   *       "scale": 0.2,
   *       "x": 30,
   *       "y": 400,
   *       "order": 2
   *     }
   *
   * @apiParam {String}     name                Media name.
   * @apiParam {Number}     scale               The scale factor.
   * @apiParam {Number}     x                   The x position on canvas.
   * @apiParam {Number}     y                   The y position on canvas.
   * @apiParam {Number}     order               The order on canvas (layer).
   */
  app.put('/media/:name', media.update);

  /**
   * @api {post} /media Upload new media
   * @apiGroup Media
   *
   * @apiParam {String}     image_base64        Base64 encoded image in png or jpg.
   *
   * @apiSuccess {String}   message             Return message.
   * @apiSuccess {String}   media               Uploaded media object.
   */
  app.post('/media', media.post);

  /**
   * @api {post} /session Create new session
   * @apiGroup Session
   *
   * @apiParam {String}     [name]              Name for session.
   *
   * @apiSuccess {String}   message             Return message.
   * @apiSuccess {String}   session             Uploaded session object.
   */
  app.post('/session', session.post);

  /**
   * @api {get} /session Get all sessions
   * @apiGroup Session
   *
   * @apiSuccess {Object[]} sessions            List of sessions.
   * @apiSuccess {String}   sessions.id         The id.
   * @apiSuccess {String}   sessions.name       The name.
   * @apiSuccess {Date}     created             Date when created.
   * @apiSuccess {Date}     updated             Date when updated.
   */
  app.get('/session', session.getAll);

  /**
   * @api {delete} /session Delete all sessions
   * @apiGroup Session
   *
   * @apiSuccess {String}   message             Return message.
   */
  app.delete('/session', session.deleteAll);

  /**
   * @api {delete} /session/:id Delete one session
   * @apiGroup Session
   *
   * @apiParam {String} id Session id.
   *
   * @apiSuccess {String}   message             Return message.
   */
  app.delete('/session/:id', session.deleteOne);

  /**
   * @api {get} /session/active Get active session
   * @apiGroup Session

   * @apiSuccess {String}   -                   The session id.
   */
  app.get('/session/active', session.getActive);

  /**
   * @api {put} /session/:id Set active session
   * @apiGroup Session
   *
   * @apiParam {String}     id                  Session id that will be activated.
   *
   * @apiSuccess {String}   message             Return message.
   * @apiSuccess {String}   session             Session object.
   */
  app.put('/session/active/:id', session.setActive);

  /**
   * @api {post} /session/canvas Upload session canvas to active canvas
   * @apiGroup Session
   *
   * @apiParam {String}     image_base64        Base64 encoded image in png or jpg.
   *
   * @apiSuccess {String}   message             Return message.
   */
  app.post('/session/canvas', session.postCanvas);
}
<commit_msg>Revert "Improved comment format for acidic"<commit_after>module.exports = function(app, config, io) {

  var media = require('./controllers/media')(config, io);
  var session = require('./controllers/session')(config);

  // GET index
  app.get('/', media.home);

  /**
   * @api {get} /media Get all media
   * @apiGroup Media
   *
   * @apiParam {String} name Media name.
   *
   * @apiSuccess {Object[]} -               List of media.
   * @apiSuccess {String}   -.name          The name.
   * @apiSuccess {Number}   -.x             The x position on canvas.
   * @apiSuccess {Number}   -.y             The y position on canvas.
   * @apiSuccess {Number}   -.scale         The scale.
   * @apiSuccess {String}   -.url           The URL.
   * @apiSuccess {Object}   -.x             The x position on canvas.
   * @apiSuccess {Number}   -.angle         The angle.
   * @apiSuccess {String}   -.type          The type (e.g. 'whiteboard').
   * @apiSuccess {Number}   -.order         The order on canvas (layer).
   * @apiSuccess {Number}   -.session       The session id.
   */
  app.get('/media', media.getAll);

  /**
   * @api {get} /media/:name Get one media
   * @apiGroup Media
   *
   * @apiParam {String} name Media name.
   *
   * @apiSuccess {String}   name          The name.
   * @apiSuccess {Number}   x             The x position on canvas.
   * @apiSuccess {Number}   y             The y position on canvas.
   * @apiSuccess {Number}   scale         The scale.
   * @apiSuccess {String}   url           The URL.
   * @apiSuccess {Object}   x             The x position on canvas.
   * @apiSuccess {Number}   angle         The angle.
   * @apiSuccess {String}   type          The type (e.g. 'whiteboard').
   * @apiSuccess {Number}   order         The order on canvas (layer).
   * @apiSuccess {Number}   session       The session id.
   */
  app.get('/media/:name', media.show);

  /**
   * @api {delete} /media/:name Delete one media
   * @apiGroup Media
   *
   * @apiParam {String} name Media name.
   *
   * @apiSuccess {String} message Return message.
   * @apiSuccess {String} media_name Name of deleted media.
   */
  app.delete('/media/:name', media.deleteOne);

  /**
   * @api {put} /media/:name Update media
   * @apiGroup Media
   *
   * @apiExample Example usage:
   *     body:
   *     {
   *       "scale": 0.2,
   *       "x": 30,
   *       "y": 400,
   *       "order": 2
   *     }
   *
   * @apiParam {String} name Media name.
   * @apiParam {Number} scale The scale factor.
   * @apiParam {Number} x The x position on canvas.
   * @apiParam {Number} y The y position on canvas.
   * @apiParam {Number} order The order on canvas (layer).
   */
  app.put('/media/:name', media.update);

  /**
   * @api {post} /media Upload new media
   * @apiGroup Media
   *
   * @apiParam {String} image_base64 Base64 encoded image in png or jpg.
   *
   * @apiSuccess {String} message Return message.
   * @apiSuccess {String} media Uploaded media object.
   */
  app.post('/media', media.post);

  /**
   * @api {post} /session Create new session
   * @apiGroup Session
   *
   * @apiParam {String} [name] Name for session.
   *
   * @apiSuccess {String} message Return message.
   * @apiSuccess {String} session Uploaded session object.
   */
  app.post('/session', session.post);

  /**
   * @api {get} /session Get all sessions
   * @apiGroup Session
   *
   * @apiSuccess {Object[]} sessions            List of sessions.
   * @apiSuccess {String}   sessions.id         The id.
   * @apiSuccess {String}   sessions.name       The name.
   * @apiSuccess {Date}     created             Date when created.
   * @apiSuccess {Date}     updated             Date when updated.
   */
  app.get('/session', session.getAll);

  /**
   * @api {delete} /session Delete all sessions
   * @apiGroup Session
   *
   * @apiSuccess {String} message Return message.
   */
  app.delete('/session', session.deleteAll);

  /**
   * @api {delete} /session/:id Delete one session
   * @apiGroup Session
   *
   * @apiParam {String} id Session id.
   *
   * @apiSuccess {String} message Return message.
   */
  app.delete('/session/:id', session.deleteOne);

  /**
   * @api {get} /session/active Get active session
   * @apiGroup Session

   * @apiSuccess {String}   -                   The session id.
   */
  app.get('/session/active', session.getActive);

  /**
   * @api {put} /session/:id Set active session
   * @apiGroup Session
   *
   * @apiParam {String} id Session id.
   *
   * @apiSuccess {String} message Return message.
   * @apiSuccess {String} session Session object.
   */
  app.put('/session/active/:id', session.setActive);

  /**
   * @api {post} /session/canvas Upload session canvas to active canvas
   * @apiGroup Session
   *
   * @apiParam {String} image_base64 Base64 encoded image in png or jpg.
   *
   * @apiSuccess {String} message Return message.
   */
  app.post('/session/canvas', session.postCanvas);
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */

var Address = require('../models/Address'),
  common = require('./common'),
  async = require('async');

var getAddr = function(req, res, next) {
  var a;
  try {
    var addr = req.param('addr');
    a = new Address(addr);
  } catch (e) {
    common.handleErrors({
      message: 'Invalid address:' + e.message,
      code: 1
    }, res, next);
    return null;
  }
  return a;
};

var getAddrs = function(req, res, next) {
  var as = [];
  try {
    var addrStrs = req.param('addrs');
    var s = addrStrs.split(',');
    if (s.length === 0) return as;
    for (var i = 0; i < s.length; i++) {
      var a = new Address(s[i]);
      as.push(a);
    }
  } catch (e) {
    common.handleErrors({
      message: 'Invalid address:' + e.message,
      code: 1
    }, res, next);
    return null;
  }
  return as;
};

exports.show = function(req, res, next) {
  var a = getAddr(req, res, next);

  if (a) {
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a);
      }
    }, req.query.noTxList);
  }
};

exports.utxo = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a) {
    a.getUtxo(function(err, utxo) {
      if (err)
        return common.handleErrors(err, res);
      else {
        return res.jsonp(utxo);
      }
    });
  }
};

exports.multiutxo = function(req, res, next) {
  var as = getAddrs(req, res, next);
  if (as) {
    var utxos = [];
    async.each(as, function(a, callback) {
      a.getUtxo(function(err, utxo) {
        if (err) callback(err);
        utxos = utxos.concat(utxo);
        callback();
      });
    }, function(err) { // finished callback
      if (err) return common.handleErrors(err, res);
      res.jsonp(utxos);
    });
  }
};

exports.balance = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.balanceSat);
      }
    });
};

exports.totalReceived = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.totalReceivedSat);
      }
    });
};

exports.totalSent = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.totalSentSat);
      }
    });
};

exports.unconfirmedBalance = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.unconfirmedBalanceSat);
      }
    });
};
<commit_msg>Normalise address information (json). Just show listed fields<commit_after>'use strict';

/**
 * Module dependencies.
 */

var Address = require('../models/Address'),
  common = require('./common'),
  async = require('async');

var getAddr = function(req, res, next) {
  var a;
  try {
    var addr = req.param('addr');
    a = new Address(addr);
  } catch (e) {
    common.handleErrors({
      message: 'Invalid address:' + e.message,
      code: 1
    }, res, next);
    return null;
  }
  return a;
};

var getAddrs = function(req, res, next) {
  var as = [];
  try {
    var addrStrs = req.param('addrs');
    var s = addrStrs.split(',');
    if (s.length === 0) return as;
    for (var i = 0; i < s.length; i++) {
      var a = new Address(s[i]);
      as.push(a);
    }
  } catch (e) {
    common.handleErrors({
      message: 'Invalid address:' + e.message,
      code: 1
    }, res, next);
    return null;
  }
  return as;
};

var normalizeAddr = function(a) {
  // Normalize json address
  return {
    'addrStr':                  a.addrStr,
    'balance':                  a.balance,
    'balanceSat':               a.balanceSat,
    'totalReceived':            a.totalReceived,
    'totalReceivedSat':         a.totalReceivedSat,
    'totalSent':                a.totalSent,
    'totalSentSat':             a.totalSentSat,
    'unconfirmedBalance':       a.unconfirmedBalance,
    'unconfirmedBalanceSat':    a.unconfirmedBalanceSat,
    'unconfirmedTxApperances':  a.unconfirmedTxApperances,
    'txApperances':             a.txApperances,
    'transactions':             a.transactions
  };
};

exports.show = function(req, res, next) {
  var a = getAddr(req, res, next);

  if (a) {
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(normalizeAddr(a));
      }
    }, req.query.noTxList);
  }
};

exports.utxo = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a) {
    a.getUtxo(function(err, utxo) {
      if (err)
        return common.handleErrors(err, res);
      else {
        return res.jsonp(utxo);
      }
    });
  }
};

exports.multiutxo = function(req, res, next) {
  var as = getAddrs(req, res, next);
  if (as) {
    var utxos = [];
    async.each(as, function(a, callback) {
      a.getUtxo(function(err, utxo) {
        if (err) callback(err);
        utxos = utxos.concat(utxo);
        callback();
      });
    }, function(err) { // finished callback
      if (err) return common.handleErrors(err, res);
      res.jsonp(utxos);
    });
  }
};

exports.balance = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.balanceSat);
      }
    });
};

exports.totalReceived = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.totalReceivedSat);
      }
    });
};

exports.totalSent = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.totalSentSat);
      }
    });
};

exports.unconfirmedBalance = function(req, res, next) {
  var a = getAddr(req, res, next);
  if (a)
    a.update(function(err) {
      if (err) {
        return common.handleErrors(err, res);
      } else {
        return res.jsonp(a.unconfirmedBalanceSat);
      }
    });
};
<|endoftext|>


<commit_before>import React from 'react';
import Relay from 'react-relay';
import DocumentTitle from 'react-document-title';
import classNames from 'classnames';

import Button from '../shared/Button';
import Emojify from '../shared/Emojify';
import FlashesStore from '../../stores/FlashesStore';
import FriendlyTime from "../shared/FriendlyTime";
import PageWithContainer from '../shared/PageWithContainer';
import Panel from '../shared/Panel';
import PusherStore from '../../stores/PusherStore';
import permissions from '../../lib/permissions';

import AgentStopMutation from '../../mutations/AgentStop';

const CONNECTION_STATE_LABELS = {
  'connected': 'Connected',
  'disconnected': 'Disconnected',
  'never_connected': 'Never Connected',
  'lost': 'Lost Connection',
  'stopped': 'Stopped',
  'stopping': 'Stopping…'
};

class AgentShow extends React.Component {
  static propTypes = {
    agent: React.PropTypes.shape({
      id: React.PropTypes.string.isRequired,
      name: React.PropTypes.string.isRequired,
      connectionState: React.PropTypes.string.isRequired,
      permissions: React.PropTypes.shape({
        agentStop: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired
      }).isRequired
    }),
    relay: React.PropTypes.object.isRequired
  };

  state = {
    stopping: false
  };

  componentDidMount() {
    PusherStore.on("websocket:event", this.handlePusherWebsocketEvent);
  }

  componentWillUnmount() {
    PusherStore.off("websocket:event", this.handlePusherWebsocketEvent);
  }

  handlePusherWebsocketEvent = (payload) => {
    if (payload.event === "agent:updated" && payload.graphql.id === this.props.agent.id) {
      this.props.relay.forceFetch(true);
    }
  };

  renderExtraItem(title, content) {
    return (

{title}: {content}

    );
  }

  renderExtras(agent) {
    const extras = [];

    if (agent.version) {
      extras.push(this.renderExtraItem('Version', agent.version));
    }

    if (agent.hostname) {
      extras.push(this.renderExtraItem('Hostname', agent.hostname));
    }

    if (agent.pid) {
      extras.push(this.renderExtraItem('PID', agent.pid));
    }

    if (agent.ipAddress) {
      extras.push(this.renderExtraItem('IP Address', agent.ipAddress));
    }

    if (agent.userAgent) {
      extras.push(this.renderExtraItem('User Agent', agent.userAgent));
    }

    if (agent.operatingSystem) {
      extras.push(this.renderExtraItem('OS', agent.operatingSystem));
    }

    if (agent.priority) {
      extras.push(this.renderExtraItem('Priority', agent.priority));
    }

    if (agent.job) {
      extras.push(this.renderExtraItem('Running', {agent.job.projectName} - Build {agent.job.buildNumber} / <Emojify>{agent.job.name || agent.job.command}</Emojify>));
    }

    if (agent.connectedAt) {
      extras.push(this.renderExtraItem(
        'Connected',

          <FriendlyTime value={agent.connectedAt} capitalized={true} />
          {agent.pingedAt && agent.connectionState === 'connected' &&
             (last check-in was {<FriendlyTime value={agent.pingedAt} />})
          }

      ));
    }

    if (agent.connectionState === 'disconnected') {
      extras.push(this.renderExtraItem('Disconnected', <FriendlyTime value={agent.disconnectedAt} />));
    } else if (agent.connectionState === 'lost') {
      extras.push(this.renderExtraItem('Lost', <FriendlyTime value={agent.lostAt} />));
    } else if (agent.connectionState === 'stopped' || agent.connectionState === 'stopping') {
      extras.push(this.renderExtraItem('Stopped', <FriendlyTime value={agent.stoppedAt} /> by {agent.stoppedBy.name}));

      // Also show when the agent eventually disconnected
      if (agent.disconnectedAt) {
        extras.push(this.renderExtraItem('Disconnected', <FriendlyTime value={agent.disconnectedAt} />));
      }
    }

    return extras;
  }

  handleStopButtonClick = (evt) => {
    evt.preventDefault();

    this.setState({ stopping: true });

    const mutation = new AgentStopMutation({
      agent: this.props.agent,
      graceful: true
    });

    Relay.Store.commitUpdate(mutation, {
      onSuccess: this.handleMutationSuccess,
      onFailure: this.handleMutationError
    });
  };

  handleMutationSuccess = () => {
    this.setState({ stopping: false });
  };

  handleMutationError = (transaction) => {
    FlashesStore.flash(FlashesStore.ERROR, transaction.getError());

    this.setState({ stopping: false });
  };

  render() {
    const agent = this.props.agent;

    const connectionStateClassName = classNames({
      'lime': agent.connectionState === 'connected',
      'gray': agent.connectionState === 'disconnected' || agent.connectionState === 'never_connected',
      'orange': agent.connectionState !== 'connected' && agent.connectionState !== 'disconnected' && this.props.agent.connectionState !== 'never_connected'
    });

    let metaDataContent = 'None';
    if (agent.metaData && agent.metaData.length) {
      metaDataContent = agent.metaData.sort().join('\n');
    }

    return (
      <DocumentTitle title={`Agents / ${agent.name} · ${agent.organization.name}`}>
        <PageWithContainer>
          <Panel>
            <Panel.Header>{agent.name}</Panel.Header>

            <Panel.Row>

                Status

                {CONNECTION_STATE_LABELS[agent.connectionState]}

                    {this.renderExtras(agent)}

            </Panel.Row>

            <Panel.Row>

                Meta Data

{metaDataContent}

                You can use the agent’s meta-data to target the agent in your pipeline’s step configuration, or to set the agent’s queue. See the Agent Meta-data Documentation and Agent Queues Documentation for more details.

            </Panel.Row>

            {this.renderStopRow()}
          </Panel>
        </PageWithContainer>
      </DocumentTitle>
    );
  }

  renderStopRow() {
    if (this.props.agent.connectionState !== 'connected') {
      return null;
    }

    return permissions(this.props.agent.permissions).collect(
      {
        allowed: "agentStop",
        render: (idx) => (
          <Panel.Row key={idx}>

              <Button theme="default" outline={true} loading={this.state.stopping ? "Stopping…" : false} onClick={this.handleStopButtonClick}>Stop Agent</Button>

              Remotely stop this agent process. Any running build job will be canceled.

          </Panel.Row>
        )
      }
    );
  }
}

export default Relay.createContainer(AgentShow, {
  fragments: {
    agent: () => Relay.QL`
      fragment on Agent {
        ${AgentStopMutation.getFragment('agent')}
        connectedAt
        connectionState
        disconnectedAt
        hostname
        id
        ipAddress
        job
        lostAt
        name
        metaData
        operatingSystem
        organization {
          name
          slug
        }
        permissions {
          agentStop {
            allowed
            code
            message
          }
        }
        pid
        pingedAt
        stoppedAt
        stoppedBy {
          name
        }
        userAgent
        uuid
        version
      }
    `
  }
});
<commit_msg>Improve formatting of agent view<commit_after>import React from 'react';
import Relay from 'react-relay';
import DocumentTitle from 'react-document-title';
import classNames from 'classnames';

import Button from '../shared/Button';
import Emojify from '../shared/Emojify';
import FlashesStore from '../../stores/FlashesStore';
import FriendlyTime from "../shared/FriendlyTime";
import PageWithContainer from '../shared/PageWithContainer';
import Panel from '../shared/Panel';
import PusherStore from '../../stores/PusherStore';
import permissions from '../../lib/permissions';

import AgentStopMutation from '../../mutations/AgentStop';

const CONNECTION_STATE_LABELS = {
  'connected': 'Connected',
  'disconnected': 'Disconnected',
  'never_connected': 'Never Connected',
  'lost': 'Lost Connection',
  'stopped': 'Stopped',
  'stopping': 'Stopping…'
};

class AgentShow extends React.Component {
  static propTypes = {
    agent: React.PropTypes.shape({
      id: React.PropTypes.string.isRequired,
      name: React.PropTypes.string.isRequired,
      connectionState: React.PropTypes.string.isRequired,
      permissions: React.PropTypes.shape({
        agentStop: React.PropTypes.shape({
          allowed: React.PropTypes.bool.isRequired
        }).isRequired
      }).isRequired
    }),
    relay: React.PropTypes.object.isRequired
  };

  state = {
    stopping: false
  };

  componentDidMount() {
    PusherStore.on("websocket:event", this.handlePusherWebsocketEvent);
  }

  componentWillUnmount() {
    PusherStore.off("websocket:event", this.handlePusherWebsocketEvent);
  }

  handlePusherWebsocketEvent = (payload) => {
    if (payload.event === "agent:updated" && payload.graphql.id === this.props.agent.id) {
      this.props.relay.forceFetch(true);
    }
  };

  renderExtraItem(title, content) {
    return (

{title}: {content}

    );
  }

  renderExtras(agent) {
    const extras = [];

    if (agent.version) {
      extras.push(this.renderExtraItem('Version', agent.version));
    }

    if (agent.hostname) {
      extras.push(this.renderExtraItem('Hostname', agent.hostname));
    }

    if (agent.pid) {
      extras.push(this.renderExtraItem('PID', agent.pid));
    }

    if (agent.ipAddress) {
      extras.push(this.renderExtraItem('IP Address', agent.ipAddress));
    }

    if (agent.userAgent) {
      extras.push(this.renderExtraItem('User Agent', agent.userAgent));
    }

    if (agent.operatingSystem) {
      extras.push(this.renderExtraItem('OS', agent.operatingSystem));
    }

    if (agent.priority) {
      extras.push(this.renderExtraItem('Priority', agent.priority));
    }

    if (agent.job) {
      extras.push(this.renderExtraItem('Running', {agent.job.projectName} - Build {agent.job.buildNumber} / <Emojify>{agent.job.name || agent.job.command}</Emojify>));
    }

    if (agent.connectedAt) {
      extras.push(this.renderExtraItem(
        'Connected',

          <FriendlyTime value={agent.connectedAt} capitalized={true} />
          {agent.pingedAt && agent.connectionState === 'connected' &&
             (last check-in was {<FriendlyTime value={agent.pingedAt} />})
          }

      ));
    }

    if (agent.connectionState === 'disconnected') {
      extras.push(this.renderExtraItem('Disconnected', <FriendlyTime value={agent.disconnectedAt} />));
    } else if (agent.connectionState === 'lost') {
      extras.push(this.renderExtraItem('Lost', <FriendlyTime value={agent.lostAt} />));
    } else if (agent.connectionState === 'stopped' || agent.connectionState === 'stopping') {
      extras.push(this.renderExtraItem('Stopped', <FriendlyTime value={agent.stoppedAt} /> by {agent.stoppedBy.name}));

      // Also show when the agent eventually disconnected
      if (agent.disconnectedAt) {
        extras.push(this.renderExtraItem('Disconnected', <FriendlyTime value={agent.disconnectedAt} />));
      }
    }

    return extras;
  }

  handleStopButtonClick = (evt) => {
    evt.preventDefault();

    this.setState({ stopping: true });

    const mutation = new AgentStopMutation({
      agent: this.props.agent,
      graceful: true
    });

    Relay.Store.commitUpdate(mutation, {
      onSuccess: this.handleMutationSuccess,
      onFailure: this.handleMutationError
    });
  };

  handleMutationSuccess = () => {
    this.setState({ stopping: false });
  };

  handleMutationError = (transaction) => {
    FlashesStore.flash(FlashesStore.ERROR, transaction.getError());

    this.setState({ stopping: false });
  };

  render() {
    const agent = this.props.agent;

    const connectionStateClassName = classNames({
      'lime': agent.connectionState === 'connected',
      'gray': agent.connectionState === 'disconnected' || agent.connectionState === 'never_connected',
      'orange': agent.connectionState !== 'connected' && agent.connectionState !== 'disconnected' && this.props.agent.connectionState !== 'never_connected'
    });

    let metaDataContent = 'None';
    if (agent.metaData && agent.metaData.length) {
      metaDataContent = agent.metaData.sort().join('\n');
    }

    return (
      <DocumentTitle title={`Agents / ${agent.name} · ${agent.organization.name}`}>
        <PageWithContainer>
          <Panel>
            <Panel.Header>{agent.name}</Panel.Header>

            <Panel.Row>

                Status

                {CONNECTION_STATE_LABELS[agent.connectionState]}

                    {this.renderExtras(agent)}

            </Panel.Row>

            <Panel.Row>

                Meta Data

{metaDataContent}

                You can use the agent’s meta-data to target the agent in your pipeline’s step configuration, or to set the agent’s queue. See the Agent Meta-data Documentation and Agent Queues Documentation for more details.

            </Panel.Row>

            {this.renderStopRow()}
          </Panel>
        </PageWithContainer>
      </DocumentTitle>
    );
  }

  renderStopRow() {
    if (this.props.agent.connectionState !== 'connected') {
      return null;
    }

    return permissions(this.props.agent.permissions).collect(
      {
        allowed: "agentStop",
        render: (idx) => (
          <Panel.Row key={idx}>

              <Button theme="default" outline={true} loading={this.state.stopping ? "Stopping…" : false} onClick={this.handleStopButtonClick}>Stop Agent</Button>

              Remotely stop this agent process. Any running build job will be canceled.

          </Panel.Row>
        )
      }
    );
  }
}

export default Relay.createContainer(AgentShow, {
  fragments: {
    agent: () => Relay.QL`
      fragment on Agent {
        ${AgentStopMutation.getFragment('agent')}
        connectedAt
        connectionState
        disconnectedAt
        hostname
        id
        ipAddress
        job
        lostAt
        name
        metaData
        operatingSystem
        organization {
          name
          slug
        }
        permissions {
          agentStop {
            allowed
            code
            message
          }
        }
        pid
        pingedAt
        stoppedAt
        stoppedBy {
          name
        }
        userAgent
        uuid
        version
      }
    `
  }
});
<|endoftext|>


<commit_before>/* global __dirname */
var env = require('config/environment.js');
var path = require('path');
var auth = require('./middleware/auth')

module.exports = function(app, router) {
    'use strict';

    // middleware to use for all requests
    router.use(auth);

    // register all modules
    require('./modules/authentication/auth-controller')(router);
    require('./modules/blog/blog-controller')(router);
    require('./modules/portfolio/portfolio-controller')(router);
    require('./modules/photos/photo-controller')(router);
    require('./modules/adventure/climbing/climbing-controller')(router);
    require('./modules/adventure/travel/travel-controller')(router);
    require('./modules/adventure/todo/todo-controller')(router);
    require('./modules/adventure/places/places-controller')(router);
    require('./modules/gaming/diablo/diablo-controller')(router);
    require('./modules/gaming/starcraft/starcraft-controller')(router);
    require('./modules/gaming/warcraft/warcraft-controller')(router);
    require('./modules/gaming/hots/hots-controller')(router);

    // test route to make sure everything is working (accessed at GET http://localhost:8080/api)
    router.get('/', function(req, res) {
        res.json({ message: 'Welcome to the ianlamb.com web API' });
    });

    // register api routes prefixed with /api
    app.use('/api', router);

    // frontend routes =========================================================
    app.get('*', function(req, res) {
        res.sendFile(path.join(__dirname, '..', env.assetsRoot, 'index.html'));
    });

};<commit_msg>fix jshint error<commit_after>/* global __dirname */
var env = require('config/environment.js');
var path = require('path');
var auth = require('./middleware/auth');

module.exports = function(app, router) {
    'use strict';

    // middleware to use for all requests
    router.use(auth);

    // register all modules
    require('./modules/authentication/auth-controller')(router);
    require('./modules/blog/blog-controller')(router);
    require('./modules/portfolio/portfolio-controller')(router);
    require('./modules/photos/photo-controller')(router);
    require('./modules/adventure/climbing/climbing-controller')(router);
    require('./modules/adventure/travel/travel-controller')(router);
    require('./modules/adventure/todo/todo-controller')(router);
    require('./modules/adventure/places/places-controller')(router);
    require('./modules/gaming/diablo/diablo-controller')(router);
    require('./modules/gaming/starcraft/starcraft-controller')(router);
    require('./modules/gaming/warcraft/warcraft-controller')(router);
    require('./modules/gaming/hots/hots-controller')(router);

    // test route to make sure everything is working (accessed at GET http://localhost:8080/api)
    router.get('/', function(req, res) {
        res.json({ message: 'Welcome to the ianlamb.com web API' });
    });

    // register api routes prefixed with /api
    app.use('/api', router);

    // frontend routes =========================================================
    app.get('*', function(req, res) {
        res.sendFile(path.join(__dirname, '..', env.assetsRoot, 'index.html'));
    });

};
<|endoftext|>


<commit_before>'use strict';

angular
  .module('myApp.api', [])
  .service('LdsIoApi', [
    '$window'
  , '$timeout'
  , '$q'
  , '$http'
  , 'StApiCache'
  , function LdsIoApi($window, $timeout, $q, $http, StApiCache) {
    var providerBase = 'https://lds.io';
    var apiPrefix = providerBase + '/api/ldsio';
    var promises = {};

    /*
    function batchApiCall(ids, url, handler) {
      // freshIds, staleIds = ids.filter()
      // get url but don't cache
      handler(result, function (id, data) {
        // put id into result set
      });
    }
    */

    function realGet(session, id, url) {
      if (promises[id]) {
        return promises[id];
      }

      promises[id] = $http.get(
        url
      , { headers: { 'Authorization': 'Bearer ' + session.token } }
      ).then(function (resp) {
        delete promises[id];

        if (!resp.data) {
          window.alert("[SANITY FAIL] '" + url + "' returned nothing (not even an error)");
          return;
        }

        if (resp.data.error) {
          console.error('[ERROR]', url);
          console.error(resp.data);
          window.alert("[DEVELOPER ERROR] '" + url + "' returned an error (is the url correct? did you check login first?)");
          return;
        }

        return resp.data;
      }, function (err) {
        delete promises[id];

        return $q.reject(err);
      });

      return promises[id];
    }

    function promiseApiCall(session, id, url, opts) {
      opts = opts || {};
      return StApiCache.read(id, url, function () {
        var d = $q.defer();

        var token = $timeout(function () {
          if (opts.tried) {
            d.reject(new Error("timed out (twice) when attempting to get data"));
            return;
          }

          opts.tried = true;
          return promiseApiCall(session, id, url, opts).then(d.resolve, d.reject);
        }, opts.tried && 16000 || 8000);

        realGet(session, id, url).then(function (data) {
          $timeout.cancel(token);
          return d.resolve(data);
        }, function (err) {
          $timeout.cancel(token);
          return d.reject(err);
        });

        return d.promise;
      }, opts).then(function (data) {
        return data.value;
      });
    }

    return {
      profile: function (session, opts) {
        var id = session.id + '.me';
        var url = apiPrefix + '/' + session.id + '/me';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , stake: function (session, stakeId, opts) {
        var id = session.id + 'stake.' + stakeId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId;

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , stakePhotos: function (session, stakeId, opts) {
        var id = session.id + 'stake.' + stakeId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/photos';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , ward: function (session, stakeId, wardId, opts) {
        var id = session.id + 'stake.' + stakeId + '.ward.' + wardId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/wards/' + wardId;

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , wardPhotos: function (session, stakeId, wardId, opts) {
        var id = session.id + 'stake.' + stakeId + '.ward.' + wardId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/wards/' + wardId + '/photos';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , photoUrl: function (session, photo, type, size) {
        // https://lds.io/api/ldsio/<accountId>/photos/individual/<individualId>/<date>/medium/<whatever>.jpg
        return apiPrefix + '/' + session.id
          + '/photos/' + type
          + '/' + photo.id + '/' + photo.updated_at
          + '/' + size + '/' + photo.id + '.jpg'
          ;
      }
    };
  }])
  ;
<commit_msg>fix photo url<commit_after>'use strict';

angular
  .module('myApp.api', [])
  .service('LdsIoApi', [
    '$window'
  , '$timeout'
  , '$q'
  , '$http'
  , 'StApiCache'
  , function LdsIoApi($window, $timeout, $q, $http, StApiCache) {
    var providerBase = 'https://lds.io';
    var apiPrefix = providerBase + '/api/ldsio';
    var promises = {};

    /*
    function batchApiCall(ids, url, handler) {
      // freshIds, staleIds = ids.filter()
      // get url but don't cache
      handler(result, function (id, data) {
        // put id into result set
      });
    }
    */

    function realGet(session, id, url) {
      if (promises[id]) {
        return promises[id];
      }

      promises[id] = $http.get(
        url
      , { headers: { 'Authorization': 'Bearer ' + session.token } }
      ).then(function (resp) {
        delete promises[id];

        if (!resp.data) {
          window.alert("[SANITY FAIL] '" + url + "' returned nothing (not even an error)");
          return;
        }

        if (resp.data.error) {
          console.error('[ERROR]', url);
          console.error(resp.data);
          window.alert("[DEVELOPER ERROR] '" + url + "' returned an error (is the url correct? did you check login first?)");
          return;
        }

        return resp.data;
      }, function (err) {
        delete promises[id];

        return $q.reject(err);
      });

      return promises[id];
    }

    function promiseApiCall(session, id, url, opts) {
      opts = opts || {};
      return StApiCache.read(id, url, function () {
        var d = $q.defer();

        var token = $timeout(function () {
          if (opts.tried) {
            d.reject(new Error("timed out (twice) when attempting to get data"));
            return;
          }

          opts.tried = true;
          return promiseApiCall(session, id, url, opts).then(d.resolve, d.reject);
        }, opts.tried && 16000 || 8000);

        realGet(session, id, url).then(function (data) {
          $timeout.cancel(token);
          return d.resolve(data);
        }, function (err) {
          $timeout.cancel(token);
          return d.reject(err);
        });

        return d.promise;
      }, opts).then(function (data) {
        return data.value;
      });
    }

    return {
      profile: function (session, opts) {
        var id = session.id + '.me';
        var url = apiPrefix + '/' + session.id + '/me';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , stake: function (session, stakeId, opts) {
        var id = session.id + 'stake.' + stakeId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId;

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , stakePhotos: function (session, stakeId, opts) {
        var id = session.id + 'stake.' + stakeId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/photos';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , ward: function (session, stakeId, wardId, opts) {
        var id = session.id + 'stake.' + stakeId + '.ward.' + wardId;
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/wards/' + wardId;

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , wardPhotos: function (session, stakeId, wardId, opts) {
        var id = session.id + 'stake.' + stakeId + '.ward.' + wardId + '.photos';
        var url = apiPrefix + '/' + session.id + '/stakes/' + stakeId + '/wards/' + wardId + '/photos';

        return promiseApiCall(
          session
        , id
        , url
        , opts
        );
      }
    , photoUrl: function (session, photo, size, type) {
        // https://lds.io/api/ldsio/<accountId>/photos/individual/<individualId>/<date>/medium/<whatever>.jpg
        return apiPrefix + '/' + session.id
          + '/photos/' + (type || photo.type)
          + '/' + (photo.app_scoped_id || photo.id) + '/' + photo.updated_at
          + '/' + (size || 'medium') + '/' + (photo.app_scoped_id || photo.id) + '.jpg'
          + '?access_token=' + session.token
          ;
      }
    };
  }])
  ;
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const mime = require('mime-types')

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath).filter(function(file) {
    return fs.statSync(path.join(srcpath, file)).isDirectory()
  })
}

function createFileList(dir) {
  const str = dir.substr(dir.lastIndexOf('/') + 1) + '$'
  const rootpath = dir.replace(new RegExp(str), '')
  const paths = getFilepaths(dir, [], rootpath)
  return paths.map(path => {
    return createFile(path, path.replace(rootpath, ''))
  })
}

function getFilepaths(dir, files_) {
  files_ = files_ || []
  const files = fs.readdirSync(dir)
  files.map(file => `${dir}/${file}`)
    .map(path => isDirectory(path)
      ? getFilepaths(path, files_)
      : files_.push(path)
    )
  return files_
}

function isDirectory(path) {
  const pathStat = fs.lstatSync(path)
  let isDir = pathStat.isDirectory()
  if (pathStat.isSymbolicLink()) {
    try {
      var targetPath = fs.realpathSync(path)
      isDir = fs.lstatSync(targetPath).isDirectory()
    } catch (err) {
      isDir = false
    }
  }
  return isDir
}

function addFileList(input, file_paths) {
  if (typeof file_paths === 'string')
    file_paths = [file_paths]
  else if (!Array.isArray(file_paths)) {
    throw new Error('file_paths needs to be a file path string or an Array of file path strings')
  }

  const file_list = file_paths.map(fp => createFile(fp))
  file_list.__proto__ = Object.create(FileList.prototype)

  Object.defineProperty(input, 'files', {
    value: file_list,
    writable: false,
  })

  return input
}

function createFile(file_path, relativePath) {
  const file = fs.statSync(file_path)

  const browserFile = new File(
    [new fs.readFileSync(file_path)],
    path.basename(file_path),
    { lastModified: file.mtimeMs }
  )
  browserFile.webkitRelativePath = relativePath || file_path
  browserFile.type = mime.lookup(file_path) || ''
  return browserFile
}

module.exports = {
  addFileList,
  createFile,
  createFileList,
  getDirectories
}<commit_msg>add comment clarifying env/FileList<commit_after>/**
 * for use in test suites using File & FileList browser APIs in jsdom environment
 */

const fs = require('fs')
const path = require('path')
const mime = require('mime-types')

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath).filter(function(file) {
    return fs.statSync(path.join(srcpath, file)).isDirectory()
  })
}

function createFileList(dir) {
  const str = dir.substr(dir.lastIndexOf('/') + 1) + '$'
  const rootpath = dir.replace(new RegExp(str), '')
  const paths = getFilepaths(dir, [], rootpath)
  return paths.map(path => {
    return createFile(path, path.replace(rootpath, ''))
  })
}

function getFilepaths(dir, files_) {
  files_ = files_ || []
  const files = fs.readdirSync(dir)
  files.map(file => `${dir}/${file}`)
    .map(path => isDirectory(path)
      ? getFilepaths(path, files_)
      : files_.push(path)
    )
  return files_
}

function isDirectory(path) {
  const pathStat = fs.lstatSync(path)
  let isDir = pathStat.isDirectory()
  if (pathStat.isSymbolicLink()) {
    try {
      var targetPath = fs.realpathSync(path)
      isDir = fs.lstatSync(targetPath).isDirectory()
    } catch (err) {
      isDir = false
    }
  }
  return isDir
}

function addFileList(input, file_paths) {
  if (typeof file_paths === 'string')
    file_paths = [file_paths]
  else if (!Array.isArray(file_paths)) {
    throw new Error('file_paths needs to be a file path string or an Array of file path strings')
  }

  const file_list = file_paths.map(fp => createFile(fp))
  file_list.__proto__ = Object.create(FileList.prototype)

  Object.defineProperty(input, 'files', {
    value: file_list,
    writable: false,
  })

  return input
}

function createFile(file_path, relativePath) {
  const file = fs.statSync(file_path)

  const browserFile = new File(
    [new fs.readFileSync(file_path)],
    path.basename(file_path),
    { lastModified: file.mtimeMs }
  )
  browserFile.webkitRelativePath = relativePath || file_path
  browserFile.type = mime.lookup(file_path) || ''
  return browserFile
}

module.exports = {
  addFileList,
  createFile,
  createFileList,
  getDirectories
}<|endoftext|>


<commit_before>//=============================================================================
// TitleVideo.js v1.0.0
// https://github.com/nanowizard/rmmv-title-video
//=============================================================================

/*
Copyright 2017 Ryan Sivek

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*:
 * @plugindesc Adds a video above the static image for the main title screen.
 * @author Ryan Sivek
 *
 * @param Video Name
 * @desc Filename for the video WITHOUT FILE EXTENSION (.webm, .mp4, etc)
 * @default TitleMovie
 *
 * @param Muted
 * @desc Whether video audio should be muted (yes/no)
 * @default no
 *
 * @param Width
 * @desc Width of the video sprite ("auto", "video", or a positive number)
 * @default auto
 *
 * @param Height
 * @desc Height of the video sprite ("auto", "video", or a positive number)
 * @default auto
 *
 * @param X
 * @desc X coordinate of the video in the title scene
 * @default 0
 *
 * @param Y
 * @desc Y coordinate of the video in the title scene
 * @default 0
 *
 * @param Loop
 * @desc Whether to loop the video (yes/no)
 * @default true
 *
 * @param Playback Rate
 * @desc Playback rate for the video. (Default: 1.0)
 * @default 1.0
 *
 * @param Blend Mode
 * @desc Blend option for the video sprite. (NORMAL, ADD, MULTIPLY, SCREEN, etc.)
 * @default NORMAL
 *
 * @param Opacity
 * @desc Opacity for the video sprite. (0.0 - 1.0)
 * @default 1.0
 *
 * @param Tint
 * @desc Tint for the video sprite as a hex value. (Default: 0xffffff)
 * @default 0xffffff
 *
 * @help
 *
 * Place the video files for your target platforms into the project's
 * "movies" directory and this plugin will automatically select the video
 * file using the same criteria RMMV uses to determine video compatibility
 * on the current platform.
 *
 * Make sure the Video Name parameter has the filename WITHOUT EXTENSION. For
 * example, if you have a video named "TitleMovie.webm" in your movies folder,
 * the Video Name parameter should be set to "TitleMovie".
 *
 * RMMV currently supported movie formats are .webm and .mp4. So for wide
 * distribution you should include both file types.
 *
 * Width and Height can be set to "auto" (window dimensions), "video"
 * (original video dimensions), or a specific number.
 *
 * For Playback Rate, Values between 0 and 1 cause the video to play in
 * slow motion. Values greater than 1 play in fast forward.
 *
 * See PIXI.js documentation for compatible blend modes:
 * http://pixijs.download/dev/docs/PIXI.html#.BLEND_MODES
 *
 * See http://www.color-hex.com/ for hex color samples if you want to
 * modify the tint for the video sprite
 *
 */

(function() {
    var parameters = PluginManager.parameters('TitleVideo');
    var filepath = parameters['Video Name'];
    var muted = parameters.Muted;
    var w = parameters.Width;
    var h = parameters.Height;
    var x = parameters.X;
    var y = parameters.Y;
    var loop = parameters.Loop;
    var playbackRate = parameters['Playback Rate'];
    var blendMode = parameters['Blend Mode'];
    var opacity = parameters.Opacity;
    var tint = parameters.Tint;

    console.log('Params', parameters);

    var ST_createBackground = Scene_Title.prototype.createBackground;

    Scene_Title.prototype.createBackground = function() {
        ST_createBackground.call(this);

        var ext = Game_Interpreter.prototype.videoFileExt();
        var vidTexture = PIXI.Texture.fromVideo('movies/'+ filepath + ext);
        var vidSprite = new PIXI.Sprite(vidTexture);
        var vid = vidTexture.baseTexture.source;

        vidSprite.blendMode = PIXI.BLEND_MODES[blendMode.toUpperCase()] || PIXI.BLEND_MODES.NORMAL;

        vid.addEventListener('loadedmetadata', function() {
            if(w === 'video') {
                vidSprite.width = vid.videoWidth;
            }
            if(h === 'video') {
                vidSprite.height = vid.videoHeight;
            }
        });

        vidSprite.width = w === 'auto' ? Graphics.width : (parseInt(w) || Graphics.width);
        vidSprite.height = h === 'auto' ? Graphics.height : (parseInt(h) || Graphics.height);
        vidSprite.x = parseInt(x) || 0;
        vidSprite.y = parseInt(y) || 0;
        vidSprite.alpha = parseFloat(opacity) || 1.0;
        vidSprite.tint = parseInt(tint) || 0xffffff;

        vid.loop = loop === 'no' ? false : true;
        vid.muted = muted === 'yes' ? true : false;
        vid.playbackRate = parseFloat(playbackRate) || 1.0;

        vidSprite.update = function() {
            vidTexture.update();
        }

        this.addChild(vidSprite);
    };

})();<commit_msg>remove log statement<commit_after>//=============================================================================
// TitleVideo.js v1.0.0
// https://github.com/nanowizard/rmmv-title-video
//=============================================================================

/*
Copyright 2017 Ryan Sivek

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*:
 * @plugindesc Adds a video above the static image for the main title screen.
 * @author Ryan Sivek
 *
 * @param Video Name
 * @desc Filename for the video WITHOUT FILE EXTENSION (.webm, .mp4, etc)
 * @default TitleMovie
 *
 * @param Muted
 * @desc Whether video audio should be muted (yes/no)
 * @default no
 *
 * @param Width
 * @desc Width of the video sprite ("auto", "video", or a positive number)
 * @default auto
 *
 * @param Height
 * @desc Height of the video sprite ("auto", "video", or a positive number)
 * @default auto
 *
 * @param X
 * @desc X coordinate of the video in the title scene
 * @default 0
 *
 * @param Y
 * @desc Y coordinate of the video in the title scene
 * @default 0
 *
 * @param Loop
 * @desc Whether to loop the video (yes/no)
 * @default true
 *
 * @param Playback Rate
 * @desc Playback rate for the video. (Default: 1.0)
 * @default 1.0
 *
 * @param Blend Mode
 * @desc Blend option for the video sprite. (NORMAL, ADD, MULTIPLY, SCREEN, etc.)
 * @default NORMAL
 *
 * @param Opacity
 * @desc Opacity for the video sprite. (0.0 - 1.0)
 * @default 1.0
 *
 * @param Tint
 * @desc Tint for the video sprite as a hex value. (Default: 0xffffff)
 * @default 0xffffff
 *
 * @help
 *
 * Place the video files for your target platforms into the project's
 * "movies" directory and this plugin will automatically select the video
 * file using the same criteria RMMV uses to determine video compatibility
 * on the current platform.
 *
 * Make sure the Video Name parameter has the filename WITHOUT EXTENSION. For
 * example, if you have a video named "TitleMovie.webm" in your movies folder,
 * the Video Name parameter should be set to "TitleMovie".
 *
 * RMMV currently supported movie formats are .webm and .mp4. So for wide
 * distribution you should include both file types.
 *
 * Width and Height can be set to "auto" (window dimensions), "video"
 * (original video dimensions), or a specific number.
 *
 * For Playback Rate, Values between 0 and 1 cause the video to play in
 * slow motion. Values greater than 1 play in fast forward.
 *
 * See PIXI.js documentation for compatible blend modes:
 * http://pixijs.download/dev/docs/PIXI.html#.BLEND_MODES
 *
 * See http://www.color-hex.com/ for hex color samples if you want to
 * modify the tint for the video sprite
 *
 */

(function() {
    var parameters = PluginManager.parameters('TitleVideo');
    var filepath = parameters['Video Name'];
    var muted = parameters.Muted;
    var w = parameters.Width;
    var h = parameters.Height;
    var x = parameters.X;
    var y = parameters.Y;
    var loop = parameters.Loop;
    var playbackRate = parameters['Playback Rate'];
    var blendMode = parameters['Blend Mode'];
    var opacity = parameters.Opacity;
    var tint = parameters.Tint;

    var ST_createBackground = Scene_Title.prototype.createBackground;

    Scene_Title.prototype.createBackground = function() {
        ST_createBackground.call(this);

        var ext = Game_Interpreter.prototype.videoFileExt();
        var vidTexture = PIXI.Texture.fromVideo('movies/'+ filepath + ext);
        var vidSprite = new PIXI.Sprite(vidTexture);
        var vid = vidTexture.baseTexture.source;

        vidSprite.blendMode = PIXI.BLEND_MODES[blendMode.toUpperCase()] || PIXI.BLEND_MODES.NORMAL;

        vid.addEventListener('loadedmetadata', function() {
            if(w === 'video') {
                vidSprite.width = vid.videoWidth;
            }
            if(h === 'video') {
                vidSprite.height = vid.videoHeight;
            }
        });

        vidSprite.width = w === 'auto' ? Graphics.width : (parseInt(w) || Graphics.width);
        vidSprite.height = h === 'auto' ? Graphics.height : (parseInt(h) || Graphics.height);
        vidSprite.x = parseInt(x) || 0;
        vidSprite.y = parseInt(y) || 0;
        vidSprite.alpha = parseFloat(opacity) || 1.0;
        vidSprite.tint = parseInt(tint) || 0xffffff;

        vid.loop = loop === 'no' ? false : true;
        vid.muted = muted === 'yes' ? true : false;
        vid.playbackRate = parseFloat(playbackRate) || 1.0;

        vidSprite.update = function() {
            vidTexture.update();
        }

        this.addChild(vidSprite);
    };

})();<|endoftext|>


<commit_before>/* eslint-disable react/prop-types, react/jsx-no-bind, react/no-array-index-key, jsx-a11y/label-has-for */
import React from 'react';
import { render } from 'react-dom';
import { FieldSet, FieldList, FieldBoolean, FieldNumber, FieldString } from '../../lib/index';
import { Wrapper, composeFilter, ErrorBlock, FieldCheckBox, FieldInput, FieldRadio, Info, numberGTE, patternFloat, priceAdd, priceRemove, required, toFixed, toFloat } from '../utils';

// filters
const initialValue = {
  main_radio: 'some-1',
  nested_fields: {
    nested_field_bool: true
  },
  value: 33,
  price: 23,
  array_fields: [
    {
      counter: 0,
      array_fields_item_number: 0,
      array_fields_item_text: 'param pam pam 0'
    }
  ]
};

const DEBUG = false;

const ExampleBasicUsage = (props) => {
  /*eslint-disable react/jsx-handler-names*/
  return (
    <FieldSet debug={DEBUG} initialValue={initialValue} {...props}>
      {({ value, $state, $field, ...other }) => (
        <form onSubmit={other.triggerSubmit}>
          <ErrorBlock hasException={other.hasException} error={other.error} valid={other.valid} />

              <Info label="FORM value" data={value} open />

              <Info label="FORM meta" data={other} open />
              <Info label="FORM $state" data={$state} />
              <Info label="FORM $field" data={$field} />

          <button type="button" onClick={other.triggerSubmit}>Submit!</button>

              <FieldString name="main_radio" id="main_radio">
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[main_radio] 1 (related)" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-1'} value="some-1">Some 1</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-2'} value="some-2">Some 2</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-3'} value="some-3">Some 3</FieldRadio>
                  </Wrapper>
                )}
              </FieldString>

              <FieldString name="main_radio" id="main_radio">
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[main_radio] 2 (related)" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-1'} value="some-1">Some 1</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-2'} value="some-2">Some 2</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-3'} value="some-3">Some 3</FieldRadio>
                  </Wrapper>
                )}
              </FieldString>

              <FieldSet name="nested_fields" validate={() => value && value.main_radio === 'some-1' ? undefined : 'main_radio must be "some-1" only!'}>
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[nested_fields]" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />

                    <ErrorBlock hasException={other.hasException} valid={other.valid} error={other.error} />

                      <FieldString postponeInvalid name="nested_field_text">
                        {({ $state, $field, value, ...other }) => (
                          <Wrapper>
                            <Info label="[nested_field_text]" data={value} open />
                            <Info label="meta" data={other} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />
                            <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                          </Wrapper>
                        )}
                      </FieldString>

                      <FieldBoolean name="nested_field_bool">
                        {({ control, value, ...other }) => (
                          <Wrapper>
                            <Info label="[nested_field_bool]" data={value} open />
                            <Info label="meta" data={other} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />
                            <FieldCheckBox hasException={other.hasException} valid={other.valid} error={other.error} {...control} checked={Boolean(value)}>nested_field_bool</FieldCheckBox>
                          </Wrapper>
                        )}
                      </FieldBoolean>

                  </Wrapper>
                )}
              </FieldSet>

              <FieldNumber
                name="value"
                validate={[ required(), numberGTE(3) ]}
                normalize={toFloat()}
              >
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[value]" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                  </Wrapper>
                )}
              </FieldNumber>

              <FieldNumber
                name="price"
                validate={[ required(), numberGTE(3) ]}
              >
                {({ $state, $field, value, ...other }) => (
                  <Wrapper>
                    <Info label="price" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <ErrorBlock hasException={other.hasException} valid={other.valid} error={other.error} />
                    <FieldNumber
                      value={value}
                      postponeInvalid
                      onChange={other.triggerChange}
                      validate={[ (value) => patternFloat()(priceRemove('USD')(value)) ]}
                      normalize={composeFilter(priceRemove('USD'), toFloat())}
                      format={composeFilter(toFixed(2), priceAdd('USD'))}
                    >
                      {({ value, $state, $field, ...other }) => (
                        <Wrapper>
                          <Info label="price2 INNER" data={value} open />
                          <Info label="meta" data={other} />
                          <Info label="$field" data={$field} />
                          <Info label="$state" data={$state} />
                          <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                        </Wrapper>
                      )}
                    </FieldNumber>
                  </Wrapper>
                )}
              </FieldNumber>

              <FieldList name="array_fields">
                {({ value, $state, $field, ...listOther }) => (
                  <Wrapper>
                    <Info label="array_fields" data={value} open />
                    <Info label="meta" data={listOther} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />

                    <ErrorBlock hasException={listOther.hasException} valid={listOther.valid} error={listOther.error} />

                    {listOther.items.map((item, index) => (
                      <FieldSet key={index} name={index}>
                        {({ value, $state, $field, ...itemOther }) => (
                          <Wrapper>
                            <Info label={`array_fields[${index}]`} data={value} open />
                            <Info label="meta" data={listOther} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />

                            <ErrorBlock hasException={itemOther.hasException} valid={itemOther.valid} error={itemOther.error} />

                              <FieldNumber name="array_fields_item_number" format={(value) => isNaN(parseFloat(value)) ? '' : parseFloat(value)} normalize={(value) => isNaN(parseFloat(value)) ? undefined : parseFloat(value)} validate={required()}>
                                {({ control, value, valid, error, hasException, $state }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_number`} data={value} open />
                                    <FieldInput hasException={hasException} valid={valid} error={error} type="number" {...control} />
                                  </Wrapper>
                                )}
                              </FieldNumber>

                              <FieldString name="array_fields_item_text">
                                {({ control, value, valid, error, hasException, $state }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_text`} data={value} open />
                                    <FieldInput hasException={hasException} valid={valid} error={error} {...control} />
                                  </Wrapper>
                                )}
                              </FieldString>

                              <FieldNumber name="counter">
                                {({ value }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_text`} data={value} open />
                                  </Wrapper>
                                )}
                              </FieldNumber>

                            <button type="button" onClick={() => listOther.removeItems(index)}>remove this</button>
                          </Wrapper>
                        )}
                      </FieldSet>
                    ))}

                    <button type="button" onClick={() => listOther.appendItems({ counter: listOther.items.length, array_fields_item_number: listOther.items.length || undefined, array_fields_item_text: `param pam pam ${listOther.items.length}` })}>Add one</button>
                  </Wrapper>
                )}
              </FieldList>

        </form>
      )}
    </FieldSet>
  );
};

const el = window.document.createElement('div');

window.document.body.appendChild(el);

render(

    <ExampleBasicUsage />

,
  el
);
<commit_msg>add dynamic fields to examples<commit_after>/* eslint-disable react/prop-types, react/jsx-no-bind, react/no-array-index-key, jsx-a11y/label-has-for */
import React from 'react';
import { render } from 'react-dom';
import omit from 'lodash/omit';
import { FieldSet, FieldList, FieldBoolean, FieldNumber, FieldString } from '../../lib/index';
import { Wrapper, composeFilter, ErrorBlock, FieldCheckBox, FieldInput, FieldRadio, Info, numberGTE, patternFloat, priceAdd, priceRemove, required, toFixed, toFloat } from '../utils';

// filters
const initialValue = {
  main_radio: 'some-1',
  nested_fields: {
    nested_field_bool: true
  },
  dynamic_fields: {
    some_1: 'predefined'
  },
  value: 33,
  price: 23,
  array_fields: [
    {
      counter: 0,
      array_fields_item_number: 0,
      array_fields_item_text: 'param pam pam 0'
    }
  ]
};

const DEBUG = false;

let counter = 0;

const styles = {
  row: { padding: 20 },
  column1: { float: 'left', width: '48%' },
  column2: { float: 'right', width: '48%' },
  columnReset: { clear: 'both' }
};

const ExampleBasicUsage = (props) => {
  /*eslint-disable react/jsx-handler-names*/
  return (
    <FieldSet debug={DEBUG} initialValue={initialValue} {...props}>
      {({ value, $state, $field, ...other }) => (
        <form onSubmit={other.triggerSubmit}>
          <ErrorBlock hasException={other.hasException} error={other.error} valid={other.valid} />

              <Info label="FORM value" data={value} open />

              <Info label="FORM meta" data={other} open />
              <Info label="FORM $state" data={$state} />
              <Info label="FORM $field" data={$field} />

            <button type="button" onClick={other.triggerSubmit}>Submit!</button>

                <FieldSet name="dynamic_fields">
                  {({ value: dynamicFieldsValue, ...dynamicFieldsOther }) => (
                    <Wrapper>
                      <Info label="dynamic_fields" data={dynamicFieldsValue} open />
                      <Info label="meta" data={dynamicFieldsOther} />
                      <Info label="$field" data={$field} />
                      <Info label="$state" data={$state} />

                      {Object.keys(dynamicFieldsValue).sort().map((name) => ( // eslint-disable-line fp/no-mutating-methods
                        <FieldString name={name} key={name}>
                          {({ value, $state, $field, ...other }) => (
                            <Wrapper>
                              <Info label={name} data={value} open />
                              <Info label="meta" data={other} />
                              <Info label="$field" data={$field} />
                              <Info label="$state" data={$state} />
                              <FieldInput
                                hasException={other.hasException}
                                valid={other.valid}
                                error={other.error}
                                {...other.control}
                              />
                              <button type="button" onClick={() => dynamicFieldsOther.triggerChange(omit(dynamicFieldsValue, name))}>Remove</button>
                            </Wrapper>
                          )}
                        </FieldString>
                      ))}

                      <button type="button" onClick={() => dynamicFieldsOther.triggerChange({ ...dynamicFieldsValue, [`dynamic_field_${Object.keys(dynamicFieldsValue).length}_${++counter}`]: String(counter) })}>Add new dynamic field</button>
                    </Wrapper>
                  )}
                </FieldSet>

              <FieldString name="main_radio" id="main_radio">
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[main_radio] 1 (related)" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-1'} value="some-1">Some 1</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-2'} value="some-2">Some 2</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-3'} value="some-3">Some 3</FieldRadio>
                  </Wrapper>
                )}
              </FieldString>

              <FieldString name="main_radio" id="main_radio">
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[main_radio] 2 (related)" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-1'} value="some-1">Some 1</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-2'} value="some-2">Some 2</FieldRadio>
                    <FieldRadio hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} checked={other.control.value === 'some-3'} value="some-3">Some 3</FieldRadio>
                  </Wrapper>
                )}
              </FieldString>

              <FieldSet name="nested_fields" validate={() => value && value.main_radio === 'some-1' ? undefined : 'main_radio must be "some-1" only!'}>
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[nested_fields]" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />

                    <ErrorBlock hasException={other.hasException} valid={other.valid} error={other.error} />

                      <FieldString postponeInvalid name="nested_field_text">
                        {({ $state, $field, value, ...other }) => (
                          <Wrapper>
                            <Info label="[nested_field_text]" data={value} open />
                            <Info label="meta" data={other} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />
                            <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                          </Wrapper>
                        )}
                      </FieldString>

                      <FieldBoolean name="nested_field_bool">
                        {({ control, value, ...other }) => (
                          <Wrapper>
                            <Info label="[nested_field_bool]" data={value} open />
                            <Info label="meta" data={other} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />
                            <FieldCheckBox hasException={other.hasException} valid={other.valid} error={other.error} {...control} checked={Boolean(value)}>nested_field_bool</FieldCheckBox>
                          </Wrapper>
                        )}
                      </FieldBoolean>

                  </Wrapper>
                )}
              </FieldSet>

              <FieldNumber
                name="value"
                validate={[ required(), numberGTE(3) ]}
                normalize={toFloat()}
              >
                {({ value, $state, $field, ...other }) => (
                  <Wrapper>
                    <Info label="[value]" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                  </Wrapper>
                )}
              </FieldNumber>

              <FieldNumber
                name="price"
                validate={[ required(), numberGTE(3) ]}
              >
                {({ $state, $field, value, ...other }) => (
                  <Wrapper>
                    <Info label="price" data={value} open />
                    <Info label="meta" data={other} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />
                    <ErrorBlock hasException={other.hasException} valid={other.valid} error={other.error} />
                    <FieldNumber
                      value={value}
                      postponeInvalid
                      onChange={other.triggerChange}
                      validate={[ (value) => patternFloat()(priceRemove('USD')(value)) ]}
                      normalize={composeFilter(priceRemove('USD'), toFloat())}
                      format={composeFilter(toFixed(2), priceAdd('USD'))}
                    >
                      {({ value, $state, $field, ...other }) => (
                        <Wrapper>
                          <Info label="price2 INNER" data={value} open />
                          <Info label="meta" data={other} />
                          <Info label="$field" data={$field} />
                          <Info label="$state" data={$state} />
                          <FieldInput hasException={other.hasException} valid={other.valid} error={other.error} {...other.control} />
                        </Wrapper>
                      )}
                    </FieldNumber>
                  </Wrapper>
                )}
              </FieldNumber>

              <FieldList name="array_fields">
                {({ value, $state, $field, ...listOther }) => (
                  <Wrapper>
                    <Info label="array_fields" data={value} open />
                    <Info label="meta" data={listOther} />
                    <Info label="$field" data={$field} />
                    <Info label="$state" data={$state} />

                    <ErrorBlock hasException={listOther.hasException} valid={listOther.valid} error={listOther.error} />

                    {listOther.items.map((item, index) => (
                      <FieldSet key={index} name={index}>
                        {({ value, $state, $field, ...itemOther }) => (
                          <Wrapper>
                            <Info label={`array_fields[${index}]`} data={value} open />
                            <Info label="meta" data={listOther} />
                            <Info label="$field" data={$field} />
                            <Info label="$state" data={$state} />

                            <ErrorBlock hasException={itemOther.hasException} valid={itemOther.valid} error={itemOther.error} />

                              <FieldNumber name="array_fields_item_number" format={(value) => isNaN(parseFloat(value)) ? '' : parseFloat(value)} normalize={(value) => isNaN(parseFloat(value)) ? undefined : parseFloat(value)} validate={required()}>
                                {({ control, value, valid, error, hasException, $state }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_number`} data={value} open />
                                    <FieldInput hasException={hasException} valid={valid} error={error} type="number" {...control} />
                                  </Wrapper>
                                )}
                              </FieldNumber>

                              <FieldString name="array_fields_item_text">
                                {({ control, value, valid, error, hasException, $state }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_text`} data={value} open />
                                    <FieldInput hasException={hasException} valid={valid} error={error} {...control} />
                                  </Wrapper>
                                )}
                              </FieldString>

                              <FieldNumber name="counter">
                                {({ value }) => (
                                  <Wrapper>
                                    <Info label={`array_fields[${index}].array_fields_item_text`} data={value} open />
                                  </Wrapper>
                                )}
                              </FieldNumber>

                            <button type="button" onClick={() => listOther.removeItems(index)}>remove this</button>
                          </Wrapper>
                        )}
                      </FieldSet>
                    ))}

                    <button type="button" onClick={() => listOther.appendItems({ counter: listOther.items.length, array_fields_item_number: listOther.items.length || undefined, array_fields_item_text: `param pam pam ${listOther.items.length}` })}>Add one</button>
                  </Wrapper>
                )}
              </FieldList>

        </form>
      )}
    </FieldSet>
  );
};

const el = window.document.createElement('div');

window.document.body.appendChild(el);

render(

    <ExampleBasicUsage />

,
  el
);
<|endoftext|>


<commit_before>import _ from "lodash";
import {kindToViewState, initialiseData} from "../common";

const initData = {
    statistic: {
        definition: null,
        summary: null,
        values: []
    },
    relatedDefinitions: null,
    summaries: [],
    navItems: [],
    selectedNavItem: null,
    parentStateRef: '.',
    visibility: {
        related: false
    }
};

function updateUrlWithoutReload($state, navItem) {
    $state.go('.', {id: navItem.id}, {notify: false});
}

function hasRelatedDefinitions(defs) {
    const relatedCount = defs.children.length
        + (defs.parent
            ? 1
            : 0)
        + defs.siblings.length;

    return relatedCount > 0;
}

function controller($q,
                    $state,
                    $stateParams,
                    bookmarkStore,
                    entityStatisticUtilities,
                    entityStatisticStore) {
    const vm = initialiseData(this, initData);

    const statId = $stateParams.statId;
    const entityKind = $stateParams.kind;
    const entityId = $stateParams.id;

    const statRef = {
        id: statId,
        kind: 'ENTITY_STATISTIC'
    };

    bookmarkStore
        .findByParent(statRef)
        .then(bs => vm.bookmarks = bs);

    const definitionPromise = entityStatisticStore
        .findRelatedStatDefinitions(statId)
        .then(ds => vm.relatedDefinitions = ds)
        .then(ds => vm.statistic.definition = ds.self)
        .then(() => vm.visibility.related = hasRelatedDefinitions(vm.relatedDefinitions));

    const navItemPromise = entityStatisticUtilities
        .findAllForKind(entityKind)
        .then(xs => vm.navItems = xs);

    $q.all([navItemPromise, definitionPromise])
        .then(() => /* boot */ vm.onSelectNavItem(_.find(vm.navItems, { id: entityId })));

    function resetValueData() {
        const clearData = _.cloneDeep(initData);
        vm.statistic.summary = clearData.statistic.summary;
        vm.statistic.values = clearData.statistic.values;
        vm.summaries = clearData.summaries;
    }

    vm.onSelectNavItem = (navItem) => {
        resetValueData();

        vm.selectedNavItem = navItem;

        const entityReference = {
            id: navItem.id,
            kind: entityKind
        };
        vm.parentRef = entityReference;

        const selector = {
            scope: 'CHILDREN',
            entityReference
        };

        entityStatisticStore
            .findStatTallies(vm.relatedDefinitions, selector)
            .then(summaries => vm.summaries = summaries)
            .then(summaries => vm.statistic.summary = _.find(summaries, { entityReference: { id: statId }}));

        entityStatisticStore
            .findStatValuesByIdSelector(statId, selector)
            .then(stats => vm.statistic.values = stats);

        updateUrlWithoutReload($state, navItem);
    };

    vm.goToParent = () => {
        const stateName = kindToViewState(entityKind);
        const navId = vm.selectedNavItem.id;
        $state.go(stateName, { id: navId });
    };
}

controller.$inject = [
    '$q',
    '$state',
    '$stateParams',
    'BookmarkStore',
    'EntityStatisticUtilities',
    'EntityStatisticStore'
];

const view = {
    template: require('./entity-statistic-view.html'),
    controller,
    controllerAs: 'ctrl',
    bindToController: true,
    scope: {}
};

export default view;<commit_msg>- fix for old values in ent stat view spilling over to new criteria  #339<commit_after>import _ from "lodash";
import {kindToViewState, initialiseData} from "../common";

const initData = {
    statistic: {
        definition: null,
        summary: null,
        values: []
    },
    relatedDefinitions: null,
    summaries: [],
    navItems: [],
    selectedNavItem: null,
    parentStateRef: '.',
    visibility: {
        related: false
    }
};

function updateUrlWithoutReload($state, navItem) {
    $state.go('.', {id: navItem.id}, {notify: false});
}

function hasRelatedDefinitions(defs) {
    const relatedCount = defs.children.length
        + (defs.parent
            ? 1
            : 0)
        + defs.siblings.length;

    return relatedCount > 0;
}

function controller($q,
                    $state,
                    $stateParams,
                    bookmarkStore,
                    entityStatisticUtilities,
                    entityStatisticStore) {
    const vm = initialiseData(this, initData);

    const statId = $stateParams.statId;
    const entityKind = $stateParams.kind;
    const entityId = $stateParams.id;

    const statRef = {
        id: statId,
        kind: 'ENTITY_STATISTIC'
    };

    bookmarkStore
        .findByParent(statRef)
        .then(bs => vm.bookmarks = bs);

    const definitionPromise = entityStatisticStore
        .findRelatedStatDefinitions(statId)
        .then(ds => vm.relatedDefinitions = ds)
        .then(ds => vm.statistic.definition = ds.self)
        .then(() => vm.visibility.related = hasRelatedDefinitions(vm.relatedDefinitions));

    const navItemPromise = entityStatisticUtilities
        .findAllForKind(entityKind)
        .then(xs => vm.navItems = xs);

    $q.all([navItemPromise, definitionPromise])
        .then(() => /* boot */ vm.onSelectNavItem(_.find(vm.navItems, { id: entityId })));

    function resetValueData() {
        const clearData = initialiseData({}, initData);
        vm.statistic.summary = clearData.statistic.summary;
        vm.statistic.values = clearData.statistic.values;
        vm.summaries = clearData.summaries;
    }

    vm.onSelectNavItem = (navItem) => {
        resetValueData();

        vm.selectedNavItem = navItem;

        const entityReference = {
            id: navItem.id,
            kind: entityKind
        };
        vm.parentRef = entityReference;

        const selector = {
            scope: 'CHILDREN',
            entityReference
        };

        entityStatisticStore
            .findStatTallies(vm.relatedDefinitions, selector)
            .then(summaries => vm.summaries = summaries)
            .then(summaries => vm.statistic.summary = _.find(summaries, { entityReference: { id: statId }}));

        entityStatisticStore
            .findStatValuesByIdSelector(statId, selector)
            .then(stats => vm.statistic.values = stats);

        updateUrlWithoutReload($state, navItem);
    };

    vm.goToParent = () => {
        const stateName = kindToViewState(entityKind);
        const navId = vm.selectedNavItem.id;
        $state.go(stateName, { id: navId });
    };
}

controller.$inject = [
    '$q',
    '$state',
    '$stateParams',
    'BookmarkStore',
    'EntityStatisticUtilities',
    'EntityStatisticStore'
];

const view = {
    template: require('./entity-statistic-view.html'),
    controller,
    controllerAs: 'ctrl',
    bindToController: true,
    scope: {}
};

export default view;<|endoftext|>