<commit_before>'use:strict';
var _ = require('underscore')
  , d3 = require('d3')
  , barAxis = {}
;
// define d3by5-base-chart for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') {
  module.exports = barAxis;

// define d3by5_PieChart as an AMD module
} else if (typeof define === 'function' && define.amd) {

  define(barAxis);

// define the base in a global namespace d3By5
}

  barAxis.options = {
          axis: {
            linear: {
              show: true,
              rotate: 0,
              label: '',
              ticks: d3.svg.axis().ticks(),
              align: 'left',
              pos: 'bottom',
            },
            ordinal: {
              show: true,
              rotate: 0,
              label: '',
              ticks: d3.svg.axis().ticks(),
              align: 'bottom',
              pos: 'left',
        }
        }
      };

    /**
     * retuns the correct scale to use for the axis
     * @param  {String} scale - What scale to use ( linear | ordinal)
     * @return {d3.scale}     - The correct scale
     */
    barAxis.axis_getScale = function (scale) {

      // the values, normally y
      if (scale === 'linear') {
        if (this.options.anchor === this.ANCHOR_RIGHT || this.options.anchor === this.ANCHOR_BOTTOM) {
          invertedScale = d3.scale.linear()
                            .domain(this.linearScale.domain().reverse())
                            .range(this.linearScale.range());
          return invertedScale;
        }
        return this.linearScale;
      } else {
        if (this.isVertical()) {
          return this.ordinalScale;
        }
        return this.ordinalScale;
      }
    };

    barAxis.axis_getTransform = function (dir) {
      if (dir === 'linear') {
        if (this.isVertical()) {
          return 'translate(' + this.options.margin.left + ',' + this.options.margin.top + ')';
        }
        return 'translate(' + this.options.margin.left + ',' + (this.options.axis.linear.align === 'top' ? 0 : this.getCalculatedHeight()) + ')';
      }

      if (dir === 'ordinal') {
        if (this.isVertical()) {
          return 'translate(' + this.options.margin.left + ',' + (this.options.axis.linear.align === 'top' ? 0 : this.options.height - this.options.margin.bottom ) + ')';
        }
        return 'translate(' + this.options.margin.left + ',' + this.options.margin.top + ')';
      }
    };

    barAxis.drawAxis = function(selection) {
      var axis = {}
        , that = this
        , axisOpt = this.options.axis
        , transform
        , _linearAxis
        , _ordinalAxis
        , ordinalScale
        , linearRotationAttr
      ;

      if(axisOpt.linear.show) {

        axis.linear = d3.svg.axis()
                    .scale(this.axis_getScale('linear'))
                    .orient(axisOpt.linear.align)
                    .ticks(axisOpt.linear.ticks.count)
                    .tickFormat(axisOpt.linear.ticks.format);

          _linearAxis = this.svg.append('g')
              .attr('class', 'y axis')
              .attr('transform', that.axis_getTransform('linear'))
              .call(axis.linear);

          if (axisOpt.linear.rotate) {
            linearRotationAttr = {};
            //negative rotation needs adjustments
            if(axisOpt.linear.rotate < 0) {
              linearRotationAttr.y = -7;
              linearRotationAttr.x = -7;
            } else {
              linearRotationAttr.y = 0;
              linearRotationAttr.x = 0;
            }
            linearRotationAttr.transform = 'rotate(' + axisOpt.linear.rotate + ')';

            _linearAxis.selectAll('text')
                        .attr(linearRotationAttr)
                        .style('text-anchor', axisOpt.linear.rotate < 0 ? 'end' : 'start');
          }

          _linearAxis
              .append('text')
                .attr('class', 'y-label')
                .attr('transform', 'rotate(-90)')
                .attr('y', 6)
                .attr('dy', '.71em')
                .attr('fill', '#777')
                .style('font-size', '0.875rem')
                .style('text-anchor', 'end')
                .text(axisOpt.linear.label);
        }

        //yAxis
        if(axisOpt.ordinal.show) {
          ordinalScale = this.axis_getScale('ordinal');
          axis.ordinal = d3.svg.axis()
                    .scale(ordinalScale)
                    .orient(axisOpt.ordinal.align);

          if (axisOpt.ordinal.ticks.count === 'none') {
            axis.ordinal.tickValues([]);
                    // .ticks(axisOpt.ordinal.ticks.count);
                    // .tickFormat(axisOpt.ordinal.ticks.format);
          } else {
            axis.ordinal.ticks(axisOpt.ordinal.ticks.count);
          }

          _ordinalAxis = this.svg.append('g')
              .attr('class', 'x axis')
              .attr('transform', that.axis_getTransform('ordinal'))
            .call(axis.ordinal);

          if (axisOpt.ordinal.rotate) {
            _ordinalAxis.selectAll('text')
                        .attr('y', axisOpt.ordinal.rotate === 90 ? -6 : 0)
                        .attr('x', 7)
                        // .attr("dy", ".35em")
                        .attr('transform', 'rotate(' + axisOpt.ordinal.rotate + ')')
                        .style('text-anchor', 'start');
          }

          // axis.y = this.axis()
          //             .show(axisOpt.y.show)
          //             .pos(axisOpt.y.pos)
          //             .align(axisOpt.y.align)
          //             .ticks(axisOpt.y.ticks);

          // _yAxis = this.svg.append('g')
          //     .attr('class', 'y axis')
          //     .attr('transform', 'translate(' + (axis.y.pos() === 'right' ? this.getCalculatedWidth() : this.options.margin.left) + ', 0)')
          //     .call(axis.y());

          // if(y.label) {
          //   _yAxis.append('text')
          //     .attr('transform', 'rotate(-90)')
          //     .attr('y', 6)
          //     .attr('dy', '.71em')
          //     .style('text-anchor', 'end')
          //     .text(y.label);
          // }
        }

// return barAxis;
  };

  barAxis.axis = function () {
    var that = this
      , axis = {
        ticks: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: "auto", "none" or a number ');
              return that;
            }
            if (_.has(value, 'linear')) {
              that.options.axis.linear.ticks = that.axis_parseTicks(value.linear);
            }
            if (_.has(value, 'ordinal')) {
              that.options.axis.ordinal.ticks = that.axis_parseTicks(value.ordinal);
            }
            return that;
          }
          return {linear: that.options.axis.linear.ticks, ordinal: that.options.axis.linear.ticks};
        },
        align: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: top | bottom | left | right');
              return that;
            }
            if (value.linear) {
              that.options.axis.linear.align = value.linear;
            }
            if (value.ordinal) {
              that.options.axis.ordinal.align = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.align, ordinal: that.options.axis.linear.align};
        },
        rotate: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: -180 to 180');
              return that;
            }
            if (_.isNumber(value.linear)) {
              that.options.axis.linear.rotate = value.linear;
            }
            if (_.isNumber(value.ordinal)) {
              that.options.axis.ordinal.rotate = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.rotate, ordinal: that.options.axis.linear.rotate};
        },
        label: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: any string');
              return that;
            }
            if (value.linear) {
              that.options.axis.linear.label = value.linear;
            }
            if (value.ordinal) {
              that.options.axis.ordinal.label = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.label, ordinal: that.options.axis.linear.label};
        }
      };
    return axis;
  };

      /**
     * Parse tick options before use
     * @param  {object} ticks {count, format}
     * @return {object}       {count, format}
     */
    barAxis.axis_parseTicks = function() {

      var count = arguments[0]
        , format = arguments[1];

      switch(count) {
        case 'auto':
          count = null;
          break;
        case 'none':
          count = 'none';
          break;
        default:
          count = +count;
          break;
      }

      // TODO: Handfe more formats that just date/time
      switch(format) {
        case undefined:
        case 'auto':
          format = null;
          break;
        default:
          format = d3.time.format(format);
          break;
      }

      return {count:count, format:format};
    };
// };
<commit_msg>Horisontal display of Y axis name on bar charts<commit_after>'use:strict';
var _ = require('underscore')
  , d3 = require('d3')
  , barAxis = {}
;
// define d3by5-base-chart for Node module pattern loaders, including Browserify
if (typeof module === 'object' && typeof module.exports === 'object') {
  module.exports = barAxis;

// define d3by5_PieChart as an AMD module
} else if (typeof define === 'function' && define.amd) {

  define(barAxis);

// define the base in a global namespace d3By5
}

  barAxis.options = {
          axis: {
            linear: {
              show: true,
              rotate: 0,
              label: '',
              ticks: d3.svg.axis().ticks(),
              align: 'left',
              pos: 'bottom',
            },
            ordinal: {
              show: true,
              rotate: 0,
              label: '',
              ticks: d3.svg.axis().ticks(),
              align: 'bottom',
              pos: 'left',
        }
        }
      };

    /**
     * retuns the correct scale to use for the axis
     * @param  {String} scale - What scale to use ( linear | ordinal)
     * @return {d3.scale}     - The correct scale
     */
    barAxis.axis_getScale = function (scale) {

      // the values, normally y
      if (scale === 'linear') {
        if (this.options.anchor === this.ANCHOR_RIGHT || this.options.anchor === this.ANCHOR_BOTTOM) {
          invertedScale = d3.scale.linear()
                            .domain(this.linearScale.domain().reverse())
                            .range(this.linearScale.range());
          return invertedScale;
        }
        return this.linearScale;
      } else {
        if (this.isVertical()) {
          return this.ordinalScale;
        }
        return this.ordinalScale;
      }
    };

    barAxis.axis_getTransform = function (dir) {
      if (dir === 'linear') {
        if (this.isVertical()) {
          return 'translate(' + this.options.margin.left + ',' + this.options.margin.top + ')';
        }
        return 'translate(' + this.options.margin.left + ',' + (this.options.axis.linear.align === 'top' ? 0 : this.getCalculatedHeight()) + ')';
      }

      if (dir === 'ordinal') {
        if (this.isVertical()) {
          return 'translate(' + this.options.margin.left + ',' + (this.options.axis.linear.align === 'top' ? 0 : this.options.height - this.options.margin.bottom ) + ')';
        }
        return 'translate(' + this.options.margin.left + ',' + this.options.margin.top + ')';
      }
    };

    barAxis.drawAxis = function(selection) {
      var axis = {}
        , that = this
        , axisOpt = this.options.axis
        , transform
        , _linearAxis
        , _ordinalAxis
        , ordinalScale
        , linearRotationAttr
      ;

      if(axisOpt.linear.show) {

        axis.linear = d3.svg.axis()
                    .scale(this.axis_getScale('linear'))
                    .orient(axisOpt.linear.align)
                    .ticks(axisOpt.linear.ticks.count)
                    .tickFormat(axisOpt.linear.ticks.format);

          _linearAxis = this.svg.append('g')
              .attr('class', 'y axis')
              .attr('transform', that.axis_getTransform('linear'))
              .call(axis.linear);

          if (axisOpt.linear.rotate) {
            linearRotationAttr = {};
            //negative rotation needs adjustments
            if(axisOpt.linear.rotate < 0) {
              linearRotationAttr.y = -7;
              linearRotationAttr.x = -7;
            } else {
              linearRotationAttr.y = 0;
              linearRotationAttr.x = 0;
            }
            linearRotationAttr.transform = 'rotate(' + axisOpt.linear.rotate + ')';

            _linearAxis.selectAll('text')
                        .attr(linearRotationAttr)
                        .style('text-anchor', axisOpt.linear.rotate < 0 ? 'end' : 'start');
          }

          _linearAxis
              .append('text')
                .attr('class', 'y-label')
                // .attr('transform', 'rotate(-90)')
                .attr('y', -20)
                .attr('dy', '.71em')
                .attr('fill', '#777')
                .style('font-size', '0.875rem')
                .style('text-anchor', 'start')
                .text(axisOpt.linear.label);
        }

        //yAxis
        if(axisOpt.ordinal.show) {
          ordinalScale = this.axis_getScale('ordinal');
          axis.ordinal = d3.svg.axis()
                    .scale(ordinalScale)
                    .orient(axisOpt.ordinal.align);

          if (axisOpt.ordinal.ticks.count === 'none') {
            axis.ordinal.tickValues([]);
                    // .ticks(axisOpt.ordinal.ticks.count);
                    // .tickFormat(axisOpt.ordinal.ticks.format);
          } else {
            axis.ordinal.ticks(axisOpt.ordinal.ticks.count);
          }

          _ordinalAxis = this.svg.append('g')
              .attr('class', 'x axis')
              .attr('transform', that.axis_getTransform('ordinal'))
            .call(axis.ordinal);

          if (axisOpt.ordinal.rotate) {
            _ordinalAxis.selectAll('text')
                        .attr('y', axisOpt.ordinal.rotate === 90 ? -6 : 0)
                        .attr('x', 7)
                        // .attr("dy", ".35em")
                        .attr('transform', 'rotate(' + axisOpt.ordinal.rotate + ')')
                        .style('text-anchor', 'start');
          }

          // axis.y = this.axis()
          //             .show(axisOpt.y.show)
          //             .pos(axisOpt.y.pos)
          //             .align(axisOpt.y.align)
          //             .ticks(axisOpt.y.ticks);

          // _yAxis = this.svg.append('g')
          //     .attr('class', 'y axis')
          //     .attr('transform', 'translate(' + (axis.y.pos() === 'right' ? this.getCalculatedWidth() : this.options.margin.left) + ', 0)')
          //     .call(axis.y());

          // if(y.label) {
          //   _yAxis.append('text')
          //     .attr('transform', 'rotate(-90)')
          //     .attr('y', 6)
          //     .attr('dy', '.71em')
          //     .style('text-anchor', 'end')
          //     .text(y.label);
          // }
        }

// return barAxis;
  };

  barAxis.axis = function () {
    var that = this
      , axis = {
        ticks: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: "auto", "none" or a number ');
              return that;
            }
            if (_.has(value, 'linear')) {
              that.options.axis.linear.ticks = that.axis_parseTicks(value.linear);
            }
            if (_.has(value, 'ordinal')) {
              that.options.axis.ordinal.ticks = that.axis_parseTicks(value.ordinal);
            }
            return that;
          }
          return {linear: that.options.axis.linear.ticks, ordinal: that.options.axis.linear.ticks};
        },
        align: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: top | bottom | left | right');
              return that;
            }
            if (value.linear) {
              that.options.axis.linear.align = value.linear;
            }
            if (value.ordinal) {
              that.options.axis.ordinal.align = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.align, ordinal: that.options.axis.linear.align};
        },
        rotate: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: -180 to 180');
              return that;
            }
            if (_.isNumber(value.linear)) {
              that.options.axis.linear.rotate = value.linear;
            }
            if (_.isNumber(value.ordinal)) {
              that.options.axis.ordinal.rotate = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.rotate, ordinal: that.options.axis.linear.rotate};
        },
        label: function (value) {
          if (arguments.length) {
            if(!_.isObject(value)) {
              console.warn('missing value for align, allowed is {linear OR ordinal}, values: any string');
              return that;
            }
            if (value.linear) {
              that.options.axis.linear.label = value.linear;
            }
            if (value.ordinal) {
              that.options.axis.ordinal.label = value.ordinal;
            }
            return that;
          }
          return {linear: that.options.axis.linear.label, ordinal: that.options.axis.linear.label};
        }
      };
    return axis;
  };

      /**
     * Parse tick options before use
     * @param  {object} ticks {count, format}
     * @return {object}       {count, format}
     */
    barAxis.axis_parseTicks = function() {

      var count = arguments[0]
        , format = arguments[1];

      switch(count) {
        case 'auto':
          count = null;
          break;
        case 'none':
          count = 'none';
          break;
        default:
          count = +count;
          break;
      }

      // TODO: Handfe more formats that just date/time
      switch(format) {
        case undefined:
        case 'auto':
          format = null;
          break;
        default:
          format = d3.time.format(format);
          break;
      }

      return {count:count, format:format};
    };
// };
<|endoftext|>


<commit_before>import { paramByApp } from '../data/dictionaryHelper';

const params = require('./parameters');

function paramToNames(p) {
  const countsAndDetails = paramByApp(p);
  const boardPluralNames = countsAndDetails.boardCounts.map(item => item.plural);
  if (boardPluralNames.length < 4) { boardPluralNames.push('Files'); }
  const detailPluralNames = countsAndDetails.projectDetails.map(item => item.plural);
  if (detailPluralNames.length < 4) { detailPluralNames.push('Files'); }
  return {
    boardPluralNames,
    chartNames: countsAndDetails.chartCounts.map(item => item.name),
    detailPluralNames,
  };
}

/**
 * Setup configuration variables based on the "app" the data-portal is
 * being deployed into (Brain Health Commons, Blood Pack, ...)
 *
 * @param {app, dev, basename, mockStore, hostname} opts overrides for defaults
 */
function buildConfig(opts) {
  const defaults = {
    dev: !!(process.env.NODE_ENV && process.env.NODE_ENV === 'dev'),
    mockStore: !!(process.env.MOCK_STORE && process.env.MOCK_STORE === 'true'),
    app: process.env.APP || 'generic',
    basename: process.env.BASENAME || '/',
    hostname: typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.hostname}/` : 'http://localhost/',
  };

  //
  // Override default basename if loading via /dev.html
  // dev.html loads bundle.js via https://localhost...
  //
  if (typeof location !== 'undefined' && location.pathname.indexOf(`${defaults.basename}dev.html`) === 0) {
    defaults.basename += 'dev.html';
  }

  const { dev, mockStore, app, basename, hostname } = Object.assign({}, defaults, opts);

  const submissionApiPath = `${hostname}api/v0/submission/`;
  const apiPath = `${hostname}api/`;
  const submissionApiOauthPath = `${hostname}api/v0/oauth2/`;
  // let credentialOauthPath = `${hostname}middleware/oauth2/v0/`;
  const graphqlPath = `${hostname}api/v0/submission/graphql/`;
  let userapiPath = `${hostname}user/`;
  let credentialCdisPath = `${userapiPath}credentials/cdis/`;
  let login = {
    url: `${userapiPath}login/google?redirect=`,
    title: 'Login from Google',
  };
  const loginPath = `${userapiPath}login/`;
  const graphqlSchemaUrl = `${hostname}data/schema.json`;
  // let credentialPath = `${hostname}middleware/aws/v0/access_key/`;

  let appname = 'Unasigned';
  let navItems = [];
  let dashboardIcons = [
    'account_circle',
    'receipt',
    'invert_colors',
    'description',
  ];
  let localTheme = {
    'barGraph.lineColor': '#666666',
    'barGraph.bar1Color': '#8884d8',
    'barGraph.bar2Color': '#82ca9d',
    'summary.borderTopColor': '#c87152',
    'summary.borderColor': '#222222',
    'summary.countColor': '#ff4200',
    'summary.iconColor': '#008000',
    'projectTable.summaryRowColor': '#eeeeee',
    'projectTable.submitButtonColor': '#dddddd',
    tableBarColor: '#7d7474',
  };
  const requiredCerts = [];
  const homepageParams = paramToNames(params);

  if (app === 'bpa') {
    appname = 'BloodPAC Metadata Submission Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'gtex') {
    appname = 'NIH Data Commons Consortium Pilot Phase\nGTEx & TOPMed Data Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'collections', link: 'https://dcp.bionimbus.org/dcp', color: '#a2a2a2', name: 'exploration' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
      { icon: 'dvr', link: 'https://dcp.bionimbus.org/jupyter', color: '#a2a2a2', name: 'workspace' },
    ];
  } else if (app === 'edc') {
    appname = 'Environmental Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
      { icon: 'dvr', link: 'https://portal.occ-data.org/jup', color: '#a2a2a2', name: 'workspace' },
    ];
    dashboardIcons = [
      'satellite',
      'track_changes',
      'description',
      'timeline',
    ];
  } else if (app === 'kf') {
    appname = 'Gabriella Miller Kids First Pediatric Data Coordinating Center Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#A51C30', name: 'home' },
      { icon: 'search', link: '/query', color: '#2D728F', name: 'query' },
      { icon: 'class', link: '/DD', color: '#A51C30', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#2D728F', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#A51C30', name: 'data' },
    ];
    localTheme = {
      'barGraph.lineColor': '#DFDFDF',
      'barGraph.bar1Color': '#00ADEE',
      'barGraph.bar2Color': '#BE1E2D',
      'summary.borderTopColor': '#F6921E',
      'summary.borderColor': '#DFDFDF',
      'summary.countColor': '#F6921E',
      'summary.iconColor': '#00ADEE',
      'projectTable.summaryRowColor': '#DFDFDF',
      'projectTable.submitButtonColor': '#DFDFDF',
      tableBarColor: '#CC3399',
    };
  } else if (app === 'bhc') {
    appname = 'The Brain Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#A51C30', name: 'home' },
      { icon: 'collections', link: 'https://data.braincommons.org/bhc', color: '#a2a2a2', name: 'exploration' },
      { icon: 'search', link: '/query', color: '#2D728F', name: 'query' },
      { icon: 'class', link: '/DD', color: '#A51C30', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#2D728F', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#A51C30', name: 'data' },
      { icon: 'dvr', link: 'https://data.braincommons.org/workspace', color: '#a2a2a2', name: 'workspace' },
      { icon: 'dvr', link: 'https://demo.braincommons.org/', color: '#a2a2a2', name: 'demo' },
    ];
    localTheme = {
      'barGraph.lineColor': '#666666',
      'barGraph.bar1Color': '#6193b1',
      'barGraph.bar2Color': '#94af83',
      'summary.borderTopColor': '#94af83',
      'summary.borderColor': '#222222',
      'summary.countColor': '#d00000',
      'summary.iconColor': '#7aa19b',
      'projectTable.summaryRowColor': '#565656',
      'projectTable.submitButtonColor': '#dddddd',
      tableBarColor: '#7d7474',
    };
  } else if (app === 'acct') {
    appname = 'ACCOuNT Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'genomel') {
    appname = 'GenoMEL Data Commons Portal';
    const userapiPathOut = 'https://login.bionimbus.org/';
    credentialCdisPath = `${userapiPath}credentials/cdis/`;
    // login = {
    //   url: `${userapiPathOut}login/shib?redirect=`,
    //   title: 'Login from NIH',
    // };
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'ndh') {
    appname = 'NIAID Data Hub Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa5Z20', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: 'https://ndh-portal.bionimbus.org', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'gdc') {
    userapiPath = dev === true ? `${hostname}user/` : `${hostname}api/`;
    // credentialPath = `${userapiPath}credentials/cleversafe/`;
    // credentialOauthPath = `${userapiPath}oauth2/`;
    appname = 'GDC Jamboree Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
    ];
    login = {
      url: 'https://itrusteauth.nih.gov/affwebservices/public/saml2sso?SPID=https://bionimbus-pdc.opensciencedatacloud.org/shibboleth&RelayState=',
      title: 'Login from NIH',
    };
  } else {
    appname = 'Generic Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#1d3674', name: 'home' },
      { icon: 'search', link: '/query', color: '#ad7e1c', name: 'query' },
      { icon: 'class', link: '/DD', color: '#1d3674', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#1d3674', name: 'data' },
    ];
  }

  const conf = {
    dev,
    mockStore,
    app,
    basename,
    hostname,
    userapiPath,
    apiPath,
    submissionApiPath,
    submissionApiOauthPath,
    credentialCdisPath,
    graphqlPath,
    graphqlSchemaUrl,
    appname,
    navItems,
    boardPluralNames: homepageParams.boardPluralNames,
    chartNames: homepageParams.chartNames,
    detailPluralNames: homepageParams.detailPluralNames,
    dashboardIcons,
    localTheme,
    login,
    loginPath,
    requiredCerts,
    buildConfig,
  };
  return conf;
}

const defaultConf = buildConfig();
// Commonjs style export, so can load from nodejs into data/gqlSetup
module.exports = defaultConf;
<commit_msg>chore(ndh): add workspace nav<commit_after>import { paramByApp } from '../data/dictionaryHelper';

const params = require('./parameters');

function paramToNames(p) {
  const countsAndDetails = paramByApp(p);
  const boardPluralNames = countsAndDetails.boardCounts.map(item => item.plural);
  if (boardPluralNames.length < 4) { boardPluralNames.push('Files'); }
  const detailPluralNames = countsAndDetails.projectDetails.map(item => item.plural);
  if (detailPluralNames.length < 4) { detailPluralNames.push('Files'); }
  return {
    boardPluralNames,
    chartNames: countsAndDetails.chartCounts.map(item => item.name),
    detailPluralNames,
  };
}

/**
 * Setup configuration variables based on the "app" the data-portal is
 * being deployed into (Brain Health Commons, Blood Pack, ...)
 *
 * @param {app, dev, basename, mockStore, hostname} opts overrides for defaults
 */
function buildConfig(opts) {
  const defaults = {
    dev: !!(process.env.NODE_ENV && process.env.NODE_ENV === 'dev'),
    mockStore: !!(process.env.MOCK_STORE && process.env.MOCK_STORE === 'true'),
    app: process.env.APP || 'generic',
    basename: process.env.BASENAME || '/',
    hostname: typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.hostname}/` : 'http://localhost/',
  };

  //
  // Override default basename if loading via /dev.html
  // dev.html loads bundle.js via https://localhost...
  //
  if (typeof location !== 'undefined' && location.pathname.indexOf(`${defaults.basename}dev.html`) === 0) {
    defaults.basename += 'dev.html';
  }

  const { dev, mockStore, app, basename, hostname } = Object.assign({}, defaults, opts);

  const submissionApiPath = `${hostname}api/v0/submission/`;
  const apiPath = `${hostname}api/`;
  const submissionApiOauthPath = `${hostname}api/v0/oauth2/`;
  // let credentialOauthPath = `${hostname}middleware/oauth2/v0/`;
  const graphqlPath = `${hostname}api/v0/submission/graphql/`;
  let userapiPath = `${hostname}user/`;
  let credentialCdisPath = `${userapiPath}credentials/cdis/`;
  let login = {
    url: `${userapiPath}login/google?redirect=`,
    title: 'Login from Google',
  };
  const loginPath = `${userapiPath}login/`;
  const graphqlSchemaUrl = `${hostname}data/schema.json`;
  // let credentialPath = `${hostname}middleware/aws/v0/access_key/`;

  let appname = 'Unasigned';
  let navItems = [];
  let dashboardIcons = [
    'account_circle',
    'receipt',
    'invert_colors',
    'description',
  ];
  let localTheme = {
    'barGraph.lineColor': '#666666',
    'barGraph.bar1Color': '#8884d8',
    'barGraph.bar2Color': '#82ca9d',
    'summary.borderTopColor': '#c87152',
    'summary.borderColor': '#222222',
    'summary.countColor': '#ff4200',
    'summary.iconColor': '#008000',
    'projectTable.summaryRowColor': '#eeeeee',
    'projectTable.submitButtonColor': '#dddddd',
    tableBarColor: '#7d7474',
  };
  const requiredCerts = [];
  const homepageParams = paramToNames(params);

  if (app === 'bpa') {
    appname = 'BloodPAC Metadata Submission Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'gtex') {
    appname = 'NIH Data Commons Consortium Pilot Phase\nGTEx & TOPMed Data Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'collections', link: `${hostname}dcp`, color: '#a2a2a2', name: 'exploration' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
      { icon: 'dvr', link: `${hostname}jupyter`, color: '#a2a2a2', name: 'workspace' },
    ];
  } else if (app === 'edc') {
    appname = 'Environmental Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
      { icon: 'dvr', link: 'https://portal.occ-data.org/jup', color: '#a2a2a2', name: 'workspace' },
    ];
    dashboardIcons = [
      'satellite',
      'track_changes',
      'description',
      'timeline',
    ];
  } else if (app === 'kf') {
    appname = 'Gabriella Miller Kids First Pediatric Data Coordinating Center Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#A51C30', name: 'home' },
      { icon: 'search', link: '/query', color: '#2D728F', name: 'query' },
      { icon: 'class', link: '/DD', color: '#A51C30', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#2D728F', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#A51C30', name: 'data' },
    ];
    localTheme = {
      'barGraph.lineColor': '#DFDFDF',
      'barGraph.bar1Color': '#00ADEE',
      'barGraph.bar2Color': '#BE1E2D',
      'summary.borderTopColor': '#F6921E',
      'summary.borderColor': '#DFDFDF',
      'summary.countColor': '#F6921E',
      'summary.iconColor': '#00ADEE',
      'projectTable.summaryRowColor': '#DFDFDF',
      'projectTable.submitButtonColor': '#DFDFDF',
      tableBarColor: '#CC3399',
    };
  } else if (app === 'bhc') {
    appname = 'The Brain Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#A51C30', name: 'home' },
      { icon: 'collections', link: `${hostname}bhc`, color: '#a2a2a2', name: 'exploration' },
      { icon: 'search', link: '/query', color: '#2D728F', name: 'query' },
      { icon: 'class', link: '/DD', color: '#A51C30', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#2D728F', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#A51C30', name: 'data' },
      { icon: 'dvr', link: `${hostname}workspace/`, color: '#a2a2a2', name: 'workspace' },
      { icon: 'dvr', link: 'https://demo.braincommons.org/', color: '#a2a2a2', name: 'demo' },
    ];
    localTheme = {
      'barGraph.lineColor': '#666666',
      'barGraph.bar1Color': '#6193b1',
      'barGraph.bar2Color': '#94af83',
      'summary.borderTopColor': '#94af83',
      'summary.borderColor': '#222222',
      'summary.countColor': '#d00000',
      'summary.iconColor': '#7aa19b',
      'projectTable.summaryRowColor': '#565656',
      'projectTable.submitButtonColor': '#dddddd',
      tableBarColor: '#7d7474',
    };
  } else if (app === 'acct') {
    appname = 'ACCOuNT Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'genomel') {
    appname = 'GenoMEL Data Commons Portal';
    const userapiPathOut = 'https://login.bionimbus.org/';
    credentialCdisPath = `${userapiPath}credentials/cdis/`;
    // login = {
    //   url: `${userapiPathOut}login/shib?redirect=`,
    //   title: 'Login from NIH',
    // };
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'search', link: '/query', color: '#daa520', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
    ];
  } else if (app === 'ndh') {
    appname = 'NIAID Data Hub Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
      { icon: 'collections', link: `${hostname}ndh`, color: '#a2a2a2', name: 'exploration' },
      { icon: 'search', link: '/query', color: '#daa5Z20', name: 'query' },
      { icon: 'class', link: '/DD', color: '#a2a2a2', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#a2a2a2', name: 'data' },
      { icon: 'dvr', link: `${hostname}workspace/`, color: '#a2a2a2', name: 'workspace' },
    ];
  } else if (app === 'gdc') {
    userapiPath = dev === true ? `${hostname}user/` : `${hostname}api/`;
    // credentialPath = `${userapiPath}credentials/cleversafe/`;
    // credentialOauthPath = `${userapiPath}oauth2/`;
    appname = 'GDC Jamboree Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#a2a2a2', name: 'home' },
    ];
    login = {
      url: 'https://itrusteauth.nih.gov/affwebservices/public/saml2sso?SPID=https://bionimbus-pdc.opensciencedatacloud.org/shibboleth&RelayState=',
      title: 'Login from NIH',
    };
  } else {
    appname = 'Generic Data Commons Portal';
    navItems = [
      { icon: 'home', link: '/', color: '#1d3674', name: 'home' },
      { icon: 'search', link: '/query', color: '#ad7e1c', name: 'query' },
      { icon: 'class', link: '/DD', color: '#1d3674', name: 'dictionary' },
      { icon: 'face', link: '/identity', color: '#daa520', name: 'profile' },
      { icon: 'content_copy', link: '/files', color: '#1d3674', name: 'data' },
    ];
  }

  const conf = {
    dev,
    mockStore,
    app,
    basename,
    hostname,
    userapiPath,
    apiPath,
    submissionApiPath,
    submissionApiOauthPath,
    credentialCdisPath,
    graphqlPath,
    graphqlSchemaUrl,
    appname,
    navItems,
    boardPluralNames: homepageParams.boardPluralNames,
    chartNames: homepageParams.chartNames,
    detailPluralNames: homepageParams.detailPluralNames,
    dashboardIcons,
    localTheme,
    login,
    loginPath,
    requiredCerts,
    buildConfig,
  };
  return conf;
}

const defaultConf = buildConfig();
// Commonjs style export, so can load from nodejs into data/gqlSetup
module.exports = defaultConf;
<|endoftext|>


<commit_before>'use strict';

var ListDragon = require('list-dragon');

var Local = require('./Local');
var DataModelDecorator = require('./DataModelDecorator');
var DataModelJSON = require('../dataModels/JSON');
var features = require('../features/index');
var addStylesheet = require('../../css/stylesheets');
//var aggregations = require('hyper-analytics').util.aggregations;
//var aggregations = require('../local_node_modules/hyper-analytics').util.aggregations;
var aggregations = require('../local_node_modules/finanalytics').aggregations;

/**
 * @name behaviors.JSON
 * @desc > Same parameters as {@link behaviors.Behavior#initialize|initialize}, which is called by this constructor.
 * @constructor
 */
var JSON = Local.extend('behaviors.JSON', {

    /**
     * @summary Constructor logic, called _after_{@link Behavior#initialize|Behavior.initialize()}.
     * @desc This method will be called upon instantiation of this class or of any class that extends from this class.
     * > All `initialize()` methods in the inheritance chain are called, in turn, each with the same parameters that were passed to the constructor, beginning with that of the most "senior" class through that of the class of the new instance.
     *
     * @param grid - the hypergrid
     * @param {object[]} dataRows - array of uniform data objects
     * @memberOf behaviors.JSON.prototype
     */
    initialize: function(grid, dataRows) {
        this.setData(dataRows);
    },

    features: [
        features.CellSelection,
        features.KeyPaging,
        features.ColumnPicker,
        features.ColumnResizing,
        features.RowResizing,
        features.Filters,
        features.RowSelection,
        features.ColumnSelection,
        features.ColumnMoving,
        features.ColumnSorting,
        features.CellEditing,
        features.CellClick,
        features.OnHover
    ],

    aggregations: aggregations,

    createColumns: function() {
        var dataModel = this.getDataModel();
        var columnCount = dataModel.getColumnCount();
        var headers = dataModel.getHeaders();
        var fields = dataModel.getFields();
        this.clearColumns();
        for (var i = 0; i < columnCount; i++) {
            var header = headers[i];
            var column = this.addColumn(i, header);
            var properties = column.getProperties();
            properties.field = fields[i];
            properties.header = header;
            properties.complexFilter = null;
        }
    },

    getDefaultDataModel: function() {
        var model = new DataModelJSON();
        var wrapper = new DataModelDecorator(this.grid, model);
        wrapper.setComponent(model); // TODO: Redundant? Already performed in DataModelDecorator()?
        return wrapper;
    },

    applyFilters: function() {
        this.dataModel.applyFilters();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the header labels.
     * @param {string[]} headerLabels - The header labels.
     */
    setHeaders: function(headerLabels) {
        this.getDataModel().setHeaders(headerLabels);
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @desc * @returns {string[]} The header labels.
     */
    getHeaders: function() {
        return this.getDataModel().getHeaders();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the fields array.
     * @param {string[]} fieldNames - The field names.
     */
    setFields: function(fieldNames) {
        //were defining the columns based on field names....
        //we must rebuild the column definitions
        this.getDataModel().setFields(fieldNames);
        this.createColumns();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Get the field names.
     * @returns {string[]}
     */
    getFields: function() {
        return this.getDataModel().getFields();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the data field.
     * @param {object[]} objects - An array of uniform objects, each being a row in the grid.
     */
    setData: function(dataRows) {
        this.getDataModel().setData(dataRows);
        this.createColumns();
        var self = this;
        if (this.grid.isColumnAutosizing()) {
            setTimeout(function() {
                self.autosizeAllColumns();
            }, 100);
            self.changed();
        } else {
            setTimeout(function() {
                self.allColumns[-1].checkColumnAutosizing(true);
                self.changed();
            });
        }
    },

    /**
     * @summary Set the top totals.
     * @memberOf behaviors.JSON.prototype
     * @param {Array<Array>} totalRows - array of rows (arrays) of totals
     */
    setTopTotals: function(totalRows) {
        this.getDataModel().setTopTotals(totalRows);
    },

    /**
     * @summary Get the top totals.
     * @memberOf behaviors.JSON.prototype
     * @returns {Array<Array>}
     */
    getTopTotals: function() {
        return this.getDataModel().getTopTotals();
    },

    /**
     * @summary Set the bottom totals.
     * @memberOf behaviors.JSON.prototype
     * @param {Array<Array>} totalRows - array of rows (arrays) of totals
     */
    setBottomTotals: function(totalRows) {
        this.getDataModel().setBottomTotals(totalRows);
    },

    /**
     * @summary Get the bottom totals.
     * @memberOf behaviors.JSON.prototype
     * @returns {Array<Array>}
     */
    getBottomTotals: function() {
        return this.getDataModel().getBottomTotals();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Build the fields and headers from the supplied column definitions.
     * ```javascript
     * myJsonBehavior.setColumns([
     *     { title: 'Stock Name', field: 'short_description' },
     *     { title: 'Status', field: 'trading_phase' },
     *     { title: 'Reference Price', field: 'reference_price' }
     * ]);
     * ```
     * @param {Array} columnDefinitions - an array of objects with fields 'title', and 'field'
     */
    setColumns: function(columnDefinitions) {
        this.getDataModel().setColumns(columnDefinitions);
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Enhance the double-click event just before it's broadcast to listeners.
     * @param {Point} event
     */
    enhanceDoubleClickEvent: function(event) {
        event.row = this.getRow(event.gridCell.y);
    },

    setDataProvider: function(dataProvider) {
        this.getDataModel().setDataProvider(dataProvider);
    },

    hasHierarchyColumn: function() {
        return this.getDataModel().hasHierarchyColumn();
    },

    getColumnAlignment: function(x) {
        if (x === 0 && this.hasHierarchyColumn()) {
            return 'left';
        } else {
            return 'center';
        }
    },

    getRowSelectionMatrix: function(selectedRows) {
        return this.getDataModel().getRowSelectionMatrix(selectedRows);
    },

    getColumnSelectionMatrix: function(selectedColumns) {
        return this.getDataModel().getColumnSelectionMatrix(selectedColumns);
    },

    getSelectionMatrix: function(selections) {
        return this.getDataModel().getSelectionMatrix(selections);
    },

    getRowSelection: function() {
        var selectedRows = this.getSelectedRows();
        return this.getDataModel().getRowSelection(selectedRows);
    },

    getColumnSelection: function() {
        var selectedColumns = this.getSelectedColumns();
        return this.getDataModel().getColumnSelection(selectedColumns);
    },

    getSelection: function() {
        var selections = this.getSelections();
        return this.getDataModel().getSelection(selections);
    },

    buildColumnPicker: function(div) {
        if (!this.isColumnReorderable()) {
            return false;
        }

        var listOptions = {
            cssStylesheetReferenceElement: div
        };

        var groups = { models: this.getGroups(), title: 'Groups' },
            availableGroups = { models: this.getAvailableGroups(), title: 'Available Groups' },
            hiddenColumns = { models: this.getHiddenColumns(), title: 'Hidden Columns' },
            visibleColumns = { models: this.getVisibleColumns(), title: 'Visible Columns'},
            groupLists = new ListDragon([groups, availableGroups], listOptions),
            columnLists = new ListDragon([hiddenColumns, visibleColumns], listOptions),
            listSets = [groupLists, columnLists];

        addStylesheet('list-dragon', div);

        listSets.forEach(function(listSet) {
            listSet.modelLists.forEach(function(list) {
                div.appendChild(list.container);
            });
        });

        //attach for later retrieval
        div.lists = {
            group: groups.models,
            availableGroups: availableGroups.models,
            hidden: hiddenColumns.models,
            visible: visibleColumns.models
        };

        return true;
    },
    getGroups: function() {
        return this.getDataModel().getGroups();
    },
    getAvailableGroups: function() {
        return this.getDataModel().getAvailableGroups();
    },
    getHiddenColumns: function() {
        return this.getDataModel().getHiddenColumns();
    },
    getVisibleColumns: function() {
        return this.getDataModel().getVisibleColumns();
    },
    setColumnDescriptors: function(lists) {
        //assumes there is one row....
        var tree = this.columns[0];
        this.columns.length = 0;
        if (tree && tree.label === 'Tree') {
            this.columns.push(tree);
        }
        for (var i = 0; i < lists.visible.length; i++) {
            this.columns.push(lists.visible[i]);
        }

        var groupBys = lists.group.map(function(e) {
            return e.id;
        });
        this.getDataModel().setGroups(groupBys);

        this.changed();
    },

    getSelectedRows: function() {
        var offset = -this.grid.getHeaderRowCount();
        var selections = this.grid.selectionModel.getSelectedRows();
        var result = selections.map(function(each) {
            return each + offset;
        });
        return result;
    },

    getSelectedColumns: function() {
        return this.grid.selectionModel.getSelectedColumns();
    },

    getSelections: function() {
        return this.grid.selectionModel.getSelections();
    }

});

module.exports = JSON;
<commit_msg>GRID-115: Row selections corrupted after filtering/sorting<commit_after>'use strict';

var ListDragon = require('list-dragon');

var Local = require('./Local');
var DataModelDecorator = require('./DataModelDecorator');
var DataModelJSON = require('../dataModels/JSON');
var features = require('../features/index');
var addStylesheet = require('../../css/stylesheets');
//var aggregations = require('hyper-analytics').util.aggregations;
//var aggregations = require('../local_node_modules/hyper-analytics').util.aggregations;
var aggregations = require('../local_node_modules/finanalytics').aggregations;

/**
 * @name behaviors.JSON
 * @desc > Same parameters as {@link behaviors.Behavior#initialize|initialize}, which is called by this constructor.
 * @constructor
 */
var JSON = Local.extend('behaviors.JSON', {

    /**
     * @summary Constructor logic, called _after_{@link Behavior#initialize|Behavior.initialize()}.
     * @desc This method will be called upon instantiation of this class or of any class that extends from this class.
     * > All `initialize()` methods in the inheritance chain are called, in turn, each with the same parameters that were passed to the constructor, beginning with that of the most "senior" class through that of the class of the new instance.
     *
     * @param grid - the hypergrid
     * @param {object[]} dataRows - array of uniform data objects
     * @memberOf behaviors.JSON.prototype
     */
    initialize: function(grid, dataRows) {
        this.setData(dataRows);
    },

    features: [
        features.CellSelection,
        features.KeyPaging,
        features.ColumnPicker,
        features.ColumnResizing,
        features.RowResizing,
        features.Filters,
        features.RowSelection,
        features.ColumnSelection,
        features.ColumnMoving,
        features.ColumnSorting,
        features.CellEditing,
        features.CellClick,
        features.OnHover
    ],

    aggregations: aggregations,

    createColumns: function() {
        var dataModel = this.getDataModel();
        var columnCount = dataModel.getColumnCount();
        var headers = dataModel.getHeaders();
        var fields = dataModel.getFields();
        this.clearColumns();
        for (var i = 0; i < columnCount; i++) {
            var header = headers[i];
            var column = this.addColumn(i, header);
            var properties = column.getProperties();
            properties.field = fields[i];
            properties.header = header;
            properties.complexFilter = null;
        }
    },

    getDefaultDataModel: function() {
        var model = new DataModelJSON();
        var wrapper = new DataModelDecorator(this.grid, model);
        wrapper.setComponent(model); // TODO: Redundant? Already performed in DataModelDecorator()?
        return wrapper;
    },

    applyFilters: function() {
        var dataRows, selectedRows, selectedDataRows, offset, index,
            sm = this.grid.selectionModel,
            hasRowSelections = sm.hasRowSelections();

        // Make note of the actual objects backing the currently selected rows.
        if (hasRowSelections) {
            dataRows = this.getDataModel().getFilteredData();
            selectedRows = this.getSelectedRows();
            selectedDataRows = [];
            selectedRows.forEach(function(selectedRowIndex) {
                selectedDataRows.push(dataRows[selectedRowIndex]);
            });
        }

        // Filter the rows...
        this.dataModel.applyFilters();

        // Re-establish grid row selections based on actual data row objects noted above.
        if (hasRowSelections) {
            sm.clearRowSelection();
            offset = this.grid.getHeaderRowCount();
            dataRows = this.getDataModel().getFilteredData();
            selectedDataRows.forEach(function(dataRow) {
                index = dataRows.indexOf(dataRow);
                if (index >= 0) {
                    sm.selectRow(offset + index);
                }
            });
        }
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the header labels.
     * @param {string[]} headerLabels - The header labels.
     */
    setHeaders: function(headerLabels) {
        this.getDataModel().setHeaders(headerLabels);
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @desc * @returns {string[]} The header labels.
     */
    getHeaders: function() {
        return this.getDataModel().getHeaders();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the fields array.
     * @param {string[]} fieldNames - The field names.
     */
    setFields: function(fieldNames) {
        //were defining the columns based on field names....
        //we must rebuild the column definitions
        this.getDataModel().setFields(fieldNames);
        this.createColumns();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Get the field names.
     * @returns {string[]}
     */
    getFields: function() {
        return this.getDataModel().getFields();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Set the data field.
     * @param {object[]} objects - An array of uniform objects, each being a row in the grid.
     */
    setData: function(dataRows) {
        this.getDataModel().setData(dataRows);
        this.createColumns();
        var self = this;
        if (this.grid.isColumnAutosizing()) {
            setTimeout(function() {
                self.autosizeAllColumns();
            }, 100);
            self.changed();
        } else {
            setTimeout(function() {
                self.allColumns[-1].checkColumnAutosizing(true);
                self.changed();
            });
        }
    },

    /**
     * @summary Set the top totals.
     * @memberOf behaviors.JSON.prototype
     * @param {Array<Array>} totalRows - array of rows (arrays) of totals
     */
    setTopTotals: function(totalRows) {
        this.getDataModel().setTopTotals(totalRows);
    },

    /**
     * @summary Get the top totals.
     * @memberOf behaviors.JSON.prototype
     * @returns {Array<Array>}
     */
    getTopTotals: function() {
        return this.getDataModel().getTopTotals();
    },

    /**
     * @summary Set the bottom totals.
     * @memberOf behaviors.JSON.prototype
     * @param {Array<Array>} totalRows - array of rows (arrays) of totals
     */
    setBottomTotals: function(totalRows) {
        this.getDataModel().setBottomTotals(totalRows);
    },

    /**
     * @summary Get the bottom totals.
     * @memberOf behaviors.JSON.prototype
     * @returns {Array<Array>}
     */
    getBottomTotals: function() {
        return this.getDataModel().getBottomTotals();
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Build the fields and headers from the supplied column definitions.
     * ```javascript
     * myJsonBehavior.setColumns([
     *     { title: 'Stock Name', field: 'short_description' },
     *     { title: 'Status', field: 'trading_phase' },
     *     { title: 'Reference Price', field: 'reference_price' }
     * ]);
     * ```
     * @param {Array} columnDefinitions - an array of objects with fields 'title', and 'field'
     */
    setColumns: function(columnDefinitions) {
        this.getDataModel().setColumns(columnDefinitions);
    },

    /**
     * @memberOf behaviors.JSON.prototype
     * @description Enhance the double-click event just before it's broadcast to listeners.
     * @param {Point} event
     */
    enhanceDoubleClickEvent: function(event) {
        event.row = this.getRow(event.gridCell.y);
    },

    setDataProvider: function(dataProvider) {
        this.getDataModel().setDataProvider(dataProvider);
    },

    hasHierarchyColumn: function() {
        return this.getDataModel().hasHierarchyColumn();
    },

    getColumnAlignment: function(x) {
        if (x === 0 && this.hasHierarchyColumn()) {
            return 'left';
        } else {
            return 'center';
        }
    },

    getRowSelectionMatrix: function(selectedRows) {
        return this.getDataModel().getRowSelectionMatrix(selectedRows);
    },

    getColumnSelectionMatrix: function(selectedColumns) {
        return this.getDataModel().getColumnSelectionMatrix(selectedColumns);
    },

    getSelectionMatrix: function(selections) {
        return this.getDataModel().getSelectionMatrix(selections);
    },

    getRowSelection: function() {
        var selectedRows = this.getSelectedRows();
        return this.getDataModel().getRowSelection(selectedRows);
    },

    getColumnSelection: function() {
        var selectedColumns = this.getSelectedColumns();
        return this.getDataModel().getColumnSelection(selectedColumns);
    },

    getSelection: function() {
        var selections = this.getSelections();
        return this.getDataModel().getSelection(selections);
    },

    buildColumnPicker: function(div) {
        if (!this.isColumnReorderable()) {
            return false;
        }

        var listOptions = {
            cssStylesheetReferenceElement: div
        };

        var groups = { models: this.getGroups(), title: 'Groups' },
            availableGroups = { models: this.getAvailableGroups(), title: 'Available Groups' },
            hiddenColumns = { models: this.getHiddenColumns(), title: 'Hidden Columns' },
            visibleColumns = { models: this.getVisibleColumns(), title: 'Visible Columns'},
            groupLists = new ListDragon([groups, availableGroups], listOptions),
            columnLists = new ListDragon([hiddenColumns, visibleColumns], listOptions),
            listSets = [groupLists, columnLists];

        addStylesheet('list-dragon', div);

        listSets.forEach(function(listSet) {
            listSet.modelLists.forEach(function(list) {
                div.appendChild(list.container);
            });
        });

        //attach for later retrieval
        div.lists = {
            group: groups.models,
            availableGroups: availableGroups.models,
            hidden: hiddenColumns.models,
            visible: visibleColumns.models
        };

        return true;
    },
    getGroups: function() {
        return this.getDataModel().getGroups();
    },
    getAvailableGroups: function() {
        return this.getDataModel().getAvailableGroups();
    },
    getHiddenColumns: function() {
        return this.getDataModel().getHiddenColumns();
    },
    getVisibleColumns: function() {
        return this.getDataModel().getVisibleColumns();
    },
    setColumnDescriptors: function(lists) {
        //assumes there is one row....
        var tree = this.columns[0];
        this.columns.length = 0;
        if (tree && tree.label === 'Tree') {
            this.columns.push(tree);
        }
        for (var i = 0; i < lists.visible.length; i++) {
            this.columns.push(lists.visible[i]);
        }

        var groupBys = lists.group.map(function(e) {
            return e.id;
        });
        this.getDataModel().setGroups(groupBys);

        this.changed();
    },

    getSelectedRows: function() {
        var offset = -this.grid.getHeaderRowCount();
        var selections = this.grid.selectionModel.getSelectedRows();
        var result = selections.map(function(each) {
            return each + offset;
        });
        return result;
    },

    getSelectedColumns: function() {
        return this.grid.selectionModel.getSelectedColumns();
    },

    getSelections: function() {
        return this.grid.selectionModel.getSelections();
    }

});

module.exports = JSON;
<|endoftext|>


<commit_before>'use strict';

const utilities = require('../brain/utilities');

/**
 * Verifies that request actually coming from Slack
 * not currently in use
 *
 * @param req
 * @param res
 */
// function verify() {
//   console.log("Nothing to see here.")
// }

/**
 * Makes array of generic request objects from incoming context
 *
 * @param context
 */
function translateRequestToGenericFormats(context) {
  let text = context.userRequest.text;
  // let verifyToken = context.config.slackVerifyToken;
  // let incomingToken = context.userRequest.token;
  let genericRequests = [{
    reqType: 'user-input',
    userInput: '',
    context: context
  }];

  // TODO: See why this does not match
  // // checking for valid token from Slack
  // // (export to function?)
  // if (verifyToken !== incomingToken) {
  //   console.log('Slack access token mismatch! Ignoring incoming request.');
  //   console.log('Incoming Token: ' + incomingToken);
  //   console.log('Verify Token: ' + verifyToken);
  //   return [];
  // }
  // console.log('Slack access token match! It\'s all good, man.');

  if (text) {
    genericRequests[0].userInput = text;
  }
  if (text.toLowerCase() === 'help') {
    console.log('Detected user input of \"help\"');
    genericRequests[0].reqType = 'help';
  }

  // console.log('Slack bot has prepared these generic requests: ' + JSON.stringify(genericRequests));
  return genericRequests;
}

/**
 * Takes generic response data and structures payloads for Slack sending
 *
 * @param genericResponse
 * @return {payloads}
 */
function generateResponsePayloads(genericResponse) {
  console.log("About to begin generating payloads from genericResponse.");
  // form basic payload
  let payloads = formBasicPayload(genericResponse);
  let type = genericResponse.type;

  // if a False object passed in, passes down False to next step
  if (!genericResponse) {
    return false;
  };

  // Refactor to switch statement?
  // Case: no user input
  if (type === 'no-input') {
    console.log('No user input flag detected in genericResponse.');
    payloads[0].json.text = 'Tell me the company you would like to contact.';
    return payloads;
  } else if (type === 'help') {
    // Case: Help user
    console.log('Help flag detected in genericResponse.');
    payloads[0].json.text = 'It looks like you need some help. Please tell me the name of the company you want to reach, and I will provide you with a list of the top issues for customers of this company, the company\'s contact info, and a list of other companies you may want to search for.';
    return payloads;
  } else if (type === 'nothing-found') {
    // Case: nothing returned from Companies search / junk input
    console.log('No Company Results flag detected in genericResponse.');
    payloads[0].json.text = 'I couldn\'t tell what you meant by \"' + genericResponse.userInput + '\". Please tell me company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
    return payloads;
  } else if (type === 'standard') {
    // do we need the explicit type check after the first two, or just 'else'?
    // Refactor inner parts of this case to a function?
    console.log('Standard type flag detected in genericResponse.');
    let name = genericResponse.data.name || '';
    let posts = genericResponse.data.posts || [];
    let otherCompanies = genericResponse.data.otherCompanies || [];
    let topContacts = formatContacts(genericResponse.data.contactMethods);
    if (posts && posts.length) {
      payloads = loadPostsAttachments(payloads, posts, name);
      console.log('Posts info pushed into Payloads');
    }
    if (topContacts) {
      payloads = loadContactsAttachments(payloads, topContacts, name);
      console.log('Company Contact Info pushed into Payloads');
    }
    if (otherCompanies && otherCompanies.length) {
      payloads = loadOtherCompaniesAttachments(payloads, otherCompanies, name);
      console.log('Other Companies info pushed into Payloads');
    }
    if (!payloads[0].json.attachments.length) {
        payloads[0].json.text = 'I couldn\'t find anything for \"' + name + '\". Please tell me which company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
        console.log('No card info found for Companies, returning Nothing Found text.');
    }
    return payloads;
  }
}

/**
 * Forms base payload for Slack response
 *
 * @param genericResponse
 * @return {payloads}
 */
 // **** Needs to acces specific webhook path for team that made request *****
function formBasicPayload(genericResponse) {
  var firebaseData = genericResponse.context.firebaseData;
  console.log("About to form basic payload with Firebase Data: " + firebaseData);
  // var parsedFBD = JSON.parse(firebaseData);
  // console.log("Parsed version of Firebase Data: " + parsedFBD);

  let url = firebaseData.slack.teams[teamId].incoming_webhook.url;
  let channel = firebaseData.slack.teams[teamId].channel_id;
  let payloads = [{
    uri: url,
    method: 'POST',
    json: {
      channel: channel,
      username: 'GetHuman',
      icon_emoji: ':gethuman:',
      text: '',
      attachments: []
    }
  }];
  return payloads;
};

/**
 * Forms payload attachment for Posts information
 *
 * @param payloads
 * @param posts
 * @param name
 * @return {payloads}
 */
function loadPostsAttachments(payloads, posts, name) {
  let colors = utilities.colors;
  payloads[0].json.text = 'Top issues for ' + name + ':';
  for (let i = 0; i < posts.length; i++) {
      let title = posts[i].title || '';
      let urlId = posts[i].urlId || '';
      let color = colors[i];
      let singleAttachment = {
          "fallback": "Issue for " + name,
          "title": title,
          "color": color,
          "fields": [
              {
                  "value": "<https://gethuman.com?company=" + encodeURIComponent(name) + "|Solve for me - $20>",
                  "short": true
              },
              {
                  "value": "<https://answers.gethuman.co/_" + encodeURIComponent(urlId) + "|More info ...>",
                  "short": true
              }
          ]
      };
      payloads[0].json.attachments.push(singleAttachment);
  };
  return payloads;
};

/**
 * Forms payload attachment for Contact information
 *
 * @param payloads
 * @param topContacts
 * @param name
 * @return {payloads}
 */
function loadContactsAttachments(payloads, topContacts, name) {
  payloads[0].json.attachments.push({
      fallback: 'Contact info for ' + name,
      title: 'Best ways to contact ' + name,
      color: '#999999',
      text: topContacts,
  });
  return payloads;
}

/**
 * Forms payload attachment for Other Companies information
 *
 * @param payloads
 * @param otherCompanies
 * @param name
 * @return {payloads}
 */
function loadOtherCompaniesAttachments(payloads, otherCompanies, name) {
  let otherCompaniesList = convertArrayToBoldList(otherCompanies);
  payloads[0].json.attachments.push({
      fallback: 'Other solutions',
      title: 'Were you talking about ' + name + '?',
      color: '#BBBBBB',
      text: 'Or maybe you meant ' + otherCompaniesList + '?',
      mrkdwn_in: ["text"]
  });
  return payloads;
}

/**
 * Takes contact methods, forms a structured string of <= 3 items for display
 *
 * @param contactMethods
 */
function formatContacts(contactMethods) {
  let topContacts = '';
  let counter = 1;
  for(let key in contactMethods) {
    if (contactMethods.hasOwnProperty(key) && (counter <= 3) && (contactMethods[key])) {
      switch(key) {
          case 'twitter':
              topContacts = topContacts + '<https://twitter.com/' + contactMethods[key] +'|Twitter> | ';
              break;
          case 'web':
              topContacts = topContacts + '<' + contactMethods[key] +'|Web> | ';
              break;
          case 'chat':
              topContacts = topContacts + '<' + contactMethods[key] +'|Chat> | ';
              break;
          case 'facebook':
              topContacts = topContacts + '<' + contactMethods[key] +'|Facebook> | ';
              break;
          default:
              topContacts = topContacts + contactMethods[key] + ' | ';
      }
      counter += 1;
    }
  }
  if (topContacts) {
    topContacts = topContacts.slice(0, -3);
  }
  console.log("Formatted string for Slack contact methods: " + topContacts);
  return topContacts;
}

/**
 * convert an array of strings to one string separated by commas, with each entry *bolded*
 *
 * @param arrayOfStrings
 * @return {otherCompaniesList}
 */
function convertArrayToBoldList(arrayOfStrings) {
  let otherCompaniesList = '*';
  otherCompaniesList = otherCompaniesList + arrayOfStrings.join('*, *') + "*";
  return otherCompaniesList;
}

module.exports = {
  // verify: verify,
  translateRequestToGenericFormats: translateRequestToGenericFormats,
  generateResponsePayloads: generateResponsePayloads,
  formBasicPayload: formBasicPayload,
  loadPostsAttachments: loadPostsAttachments,
  loadContactsAttachments: loadContactsAttachments,
  loadOtherCompaniesAttachments: loadOtherCompaniesAttachments,
  formatContacts: formatContacts,
  convertArrayToBoldList: convertArrayToBoldList
};
<commit_msg>debug<commit_after>'use strict';

const utilities = require('../brain/utilities');

/**
 * Verifies that request actually coming from Slack
 * not currently in use
 *
 * @param req
 * @param res
 */
// function verify() {
//   console.log("Nothing to see here.")
// }

/**
 * Makes array of generic request objects from incoming context
 *
 * @param context
 */
function translateRequestToGenericFormats(context) {
  let text = context.userRequest.text;
  // let verifyToken = context.config.slackVerifyToken;
  // let incomingToken = context.userRequest.token;
  let genericRequests = [{
    reqType: 'user-input',
    userInput: '',
    context: context
  }];

  // TODO: See why this does not match
  // // checking for valid token from Slack
  // // (export to function?)
  // if (verifyToken !== incomingToken) {
  //   console.log('Slack access token mismatch! Ignoring incoming request.');
  //   console.log('Incoming Token: ' + incomingToken);
  //   console.log('Verify Token: ' + verifyToken);
  //   return [];
  // }
  // console.log('Slack access token match! It\'s all good, man.');

  if (text) {
    genericRequests[0].userInput = text;
  }
  if (text.toLowerCase() === 'help') {
    console.log('Detected user input of \"help\"');
    genericRequests[0].reqType = 'help';
  }

  // console.log('Slack bot has prepared these generic requests: ' + JSON.stringify(genericRequests));
  return genericRequests;
}

/**
 * Takes generic response data and structures payloads for Slack sending
 *
 * @param genericResponse
 * @return {payloads}
 */
function generateResponsePayloads(genericResponse) {
  console.log("About to begin generating payloads from genericResponse.");
  // form basic payload
  let payloads = formBasicPayload(genericResponse);
  let type = genericResponse.type;

  // if a False object passed in, passes down False to next step
  if (!genericResponse) {
    return false;
  };

  // Refactor to switch statement?
  // Case: no user input
  if (type === 'no-input') {
    console.log('No user input flag detected in genericResponse.');
    payloads[0].json.text = 'Tell me the company you would like to contact.';
    return payloads;
  } else if (type === 'help') {
    // Case: Help user
    console.log('Help flag detected in genericResponse.');
    payloads[0].json.text = 'It looks like you need some help. Please tell me the name of the company you want to reach, and I will provide you with a list of the top issues for customers of this company, the company\'s contact info, and a list of other companies you may want to search for.';
    return payloads;
  } else if (type === 'nothing-found') {
    // Case: nothing returned from Companies search / junk input
    console.log('No Company Results flag detected in genericResponse.');
    payloads[0].json.text = 'I couldn\'t tell what you meant by \"' + genericResponse.userInput + '\". Please tell me company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
    return payloads;
  } else if (type === 'standard') {
    // do we need the explicit type check after the first two, or just 'else'?
    // Refactor inner parts of this case to a function?
    console.log('Standard type flag detected in genericResponse.');
    let name = genericResponse.data.name || '';
    let posts = genericResponse.data.posts || [];
    let otherCompanies = genericResponse.data.otherCompanies || [];
    let topContacts = formatContacts(genericResponse.data.contactMethods);
    if (posts && posts.length) {
      payloads = loadPostsAttachments(payloads, posts, name);
      console.log('Posts info pushed into Payloads');
    }
    if (topContacts) {
      payloads = loadContactsAttachments(payloads, topContacts, name);
      console.log('Company Contact Info pushed into Payloads');
    }
    if (otherCompanies && otherCompanies.length) {
      payloads = loadOtherCompaniesAttachments(payloads, otherCompanies, name);
      console.log('Other Companies info pushed into Payloads');
    }
    if (!payloads[0].json.attachments.length) {
        payloads[0].json.text = 'I couldn\'t find anything for \"' + name + '\". Please tell me which company you are looking for. (ex: \"/gethuman Verizon Wireless\")';
        console.log('No card info found for Companies, returning Nothing Found text.');
    }
    return payloads;
  }
}

/**
 * Forms base payload for Slack response
 *
 * @param genericResponse
 * @return {payloads}
 */
 // **** Needs to acces specific webhook path for team that made request *****
function formBasicPayload(genericResponse) {
  var teamId = genericResponse.context.userRequest.team_id;
  var firebaseData = genericResponse.context.firebaseData;
  console.log("About to form basic payload with Firebase Data: " + JSON.stringify(firebaseData));
  // var parsedFBD = JSON.parse(firebaseData);
  // console.log("Parsed version of Firebase Data: " + parsedFBD);

  let url = firebaseData.slack.teams[teamId].incoming_webhook.url;
  let channel = firebaseData.slack.teams[teamId].channel_id;
  let payloads = [{
    uri: url,
    method: 'POST',
    json: {
      channel: channel,
      username: 'GetHuman',
      icon_emoji: ':gethuman:',
      text: '',
      attachments: []
    }
  }];
  return payloads;
};

/**
 * Forms payload attachment for Posts information
 *
 * @param payloads
 * @param posts
 * @param name
 * @return {payloads}
 */
function loadPostsAttachments(payloads, posts, name) {
  let colors = utilities.colors;
  payloads[0].json.text = 'Top issues for ' + name + ':';
  for (let i = 0; i < posts.length; i++) {
      let title = posts[i].title || '';
      let urlId = posts[i].urlId || '';
      let color = colors[i];
      let singleAttachment = {
          "fallback": "Issue for " + name,
          "title": title,
          "color": color,
          "fields": [
              {
                  "value": "<https://gethuman.com?company=" + encodeURIComponent(name) + "|Solve for me - $20>",
                  "short": true
              },
              {
                  "value": "<https://answers.gethuman.co/_" + encodeURIComponent(urlId) + "|More info ...>",
                  "short": true
              }
          ]
      };
      payloads[0].json.attachments.push(singleAttachment);
  };
  return payloads;
};

/**
 * Forms payload attachment for Contact information
 *
 * @param payloads
 * @param topContacts
 * @param name
 * @return {payloads}
 */
function loadContactsAttachments(payloads, topContacts, name) {
  payloads[0].json.attachments.push({
      fallback: 'Contact info for ' + name,
      title: 'Best ways to contact ' + name,
      color: '#999999',
      text: topContacts,
  });
  return payloads;
}

/**
 * Forms payload attachment for Other Companies information
 *
 * @param payloads
 * @param otherCompanies
 * @param name
 * @return {payloads}
 */
function loadOtherCompaniesAttachments(payloads, otherCompanies, name) {
  let otherCompaniesList = convertArrayToBoldList(otherCompanies);
  payloads[0].json.attachments.push({
      fallback: 'Other solutions',
      title: 'Were you talking about ' + name + '?',
      color: '#BBBBBB',
      text: 'Or maybe you meant ' + otherCompaniesList + '?',
      mrkdwn_in: ["text"]
  });
  return payloads;
}

/**
 * Takes contact methods, forms a structured string of <= 3 items for display
 *
 * @param contactMethods
 */
function formatContacts(contactMethods) {
  let topContacts = '';
  let counter = 1;
  for(let key in contactMethods) {
    if (contactMethods.hasOwnProperty(key) && (counter <= 3) && (contactMethods[key])) {
      switch(key) {
          case 'twitter':
              topContacts = topContacts + '<https://twitter.com/' + contactMethods[key] +'|Twitter> | ';
              break;
          case 'web':
              topContacts = topContacts + '<' + contactMethods[key] +'|Web> | ';
              break;
          case 'chat':
              topContacts = topContacts + '<' + contactMethods[key] +'|Chat> | ';
              break;
          case 'facebook':
              topContacts = topContacts + '<' + contactMethods[key] +'|Facebook> | ';
              break;
          default:
              topContacts = topContacts + contactMethods[key] + ' | ';
      }
      counter += 1;
    }
  }
  if (topContacts) {
    topContacts = topContacts.slice(0, -3);
  }
  console.log("Formatted string for Slack contact methods: " + topContacts);
  return topContacts;
}

/**
 * convert an array of strings to one string separated by commas, with each entry *bolded*
 *
 * @param arrayOfStrings
 * @return {otherCompaniesList}
 */
function convertArrayToBoldList(arrayOfStrings) {
  let otherCompaniesList = '*';
  otherCompaniesList = otherCompaniesList + arrayOfStrings.join('*, *') + "*";
  return otherCompaniesList;
}

module.exports = {
  // verify: verify,
  translateRequestToGenericFormats: translateRequestToGenericFormats,
  generateResponsePayloads: generateResponsePayloads,
  formBasicPayload: formBasicPayload,
  loadPostsAttachments: loadPostsAttachments,
  loadContactsAttachments: loadContactsAttachments,
  loadOtherCompaniesAttachments: loadOtherCompaniesAttachments,
  formatContacts: formatContacts,
  convertArrayToBoldList: convertArrayToBoldList
};
<|endoftext|>


<commit_before>import { join } from "path"
import express, { Router } from "express"
import webpack from "webpack"
import webpackDevMiddleware from "webpack-dev-middleware"
import webpackHotMiddleware from "webpack-hot-middleware"
import WebpackErrorNotificationPlugin from "webpack-error-notification"

import opn from "opn"
import debug from "debug"
import portFinder from "portfinder"

import collection from "../content-loader/cache.js"
import urlAsHtml from "../static/to-html/url-as-html"
import * as pagesActions from "../redux/modules/pages"
import cleanNodeCache from "../_utils/clean-node-cache"
import joinUri from "../_utils/join-uri"
import redBoxRenderer from "../_utils/redbox-renderer"

const log = debug("statinamic:builder:server")

let firstRun = true

export default (options = {}) => {
  options = {
    noDevEntriesTest: /^tests/,
    ...options,
  }
  const { config } = options
  const { webpackConfigClient: webpackConfig } = config

  if (!config.baseUrl) {
    throw new Error(
      "You must provide a 'baseUrl' object that contains the following keys:" +
      "'href', 'port', 'hostname'. See https://nodejs.org/api/url.html"
    )
  }

  const server = express()

  if (config.static && config.server) {
    server.use(
      config.baseUrl.pathname,
      express.static(join(config.cwd, config.destination))
    )
  }
  else {
    const devEntries = [
      require.resolve("webpack-hot-middleware/client"),
    ]

    const devConfig = {
      ...webpackConfig,
      // debug: true,
      // watch: true,
      // colors: true,
      entry: {
        // add devEntries
        ...Object.keys(webpackConfig.entry)
          .reduce(
            (acc, key) => {
              // some entries do not need extra stuff
              acc[key] = key.match(options.noDevEntriesTest) !== null
                ? webpackConfig.entry[key]
                : [
                  ...devEntries,
                  ...Array.isArray(webpackConfig.entry[key])
                    ? webpackConfig.entry[key]
                    : [ webpackConfig.entry[key] ],
                ]
              return acc
            },
            {}
          ),
      },
      plugins: [
        ...(webpackConfig.plugins || []),
        ...(options.plugins || []),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new WebpackErrorNotificationPlugin(),
      ],
      eslint: {
        ...webpackConfig.eslint,
        emitWarning: true,
      },
    }

    // webpack requirements
    const webpackCompiler = webpack(devConfig)

    server.use(webpackDevMiddleware(webpackCompiler, {
      publicPath: webpackConfig.output.publicPath,
      noInfo: !config.verbose,
      ...devConfig.devServer,
    }))

    // HMR
    server.use(webpackHotMiddleware(webpackCompiler))

    let entries = []
    webpackCompiler.plugin("done", function(stats) {
      // reset entries
      entries = []
      const namedChunks = stats.compilation.namedChunks
      Object.keys(namedChunks).forEach((chunkName) => {
        entries = [
          ...entries,
          ...namedChunks[chunkName].files.filter(
            (file) => !file.endsWith(".hot-update.js")
          ),
        ]
      })
    })

    // user static assets
    if (config.assets) {
      server.use(
        config.baseUrl.pathname + config.assets.route,
        express.static(config.assets.path)
      )
    }

    // routing for the part we want (starting to the baseUrl pathname)
    const router = Router()
    server.use(config.baseUrl.pathname, router)

    // webpack static ressources
    router.get("*", express.static(webpackConfig.output.path))

    // prerender pages when possible
    const memoryFs = webpackCompiler.outputFileSystem
    router.get("*", (req, res, next) => {
      let item = getItemOrContinue(
        collection,
        config.baseUrl,
        req,
        res
      )

      // try 404.html if there is any
      if (!item) {
        req.url = "/404.html"
        item = getItemOrContinue(
          collection,
          config.baseUrl,
          req,
          res
        )
      }

      if (!item) {
        next()
        return
      }
      const filepath = join(config.cwd, config.destination, item.__dataUrl)
      const fileContent = memoryFs.readFileSync(filepath)
      const json = JSON.parse(fileContent.toString())

      options.store.dispatch({
        type: pagesActions.SET,
        page: item.__url,
        response: {
          json,
        },
      })

      if (!firstRun) {
        cleanNodeCache(config.cwd)
      }
      firstRun = false

      urlAsHtml(item.__url, {
        exports: options.exports,
        store: options.store,
        collection,
        baseUrl: config.baseUrl,
        assetsFiles: {
          js: entries,
          css: !config.dev,
        },
      })
      .then(
        (html) => {
          res.setHeader("Content-Type", "text/html")
          res.end(html)
        }
      )
      .catch((err) => {
        log(err)
        res.setHeader("Content-Type", "text/html")
        res.end(redBoxRenderer(err))
      })
    })
  }

  // THAT'S IT
  const { devHost, devPort } = config

  portFinder.basePort = devPort

  portFinder.getPort((err, port) => {
    if (err) {
      throw err
    }

    if (port !== devHost) {
      log(`Port ${ devPort } is not available. Using port ${ port } instead.`)
    }
    server.listen(port, devHost, (err) => {
      if (err) {
        throw err
      }
      const href = `http://${ devHost }:${ port }${ config.baseUrl.pathname }`
      log(`Dev server started on ${ href }`)
      if (config.open) {
        opn(href.replace(devHost, "localhost"))
      }
    })
  })
}

export function getItemOrContinue(collection, baseUrl, req, res) {
  const __url = req.url
    .replace(/index\.html$/, "")
  const item = collection.find((item) => item.__url === __url)
  if (!item) {
    log("%s not found", __url)
    const folderUrl = __url + "/"
    if (collection.find((item) => item.__url === folderUrl)) {
      const newUrl = req.url + "/"
      log("Redirecting to %s", newUrl)
      res.redirect(joinUri(baseUrl.pathname, newUrl))
    }
    return false
  }

  return item
}
<commit_msg>fix: Wrong log message when port is avaiable (#373)<commit_after>import { join } from "path"
import express, { Router } from "express"
import webpack from "webpack"
import webpackDevMiddleware from "webpack-dev-middleware"
import webpackHotMiddleware from "webpack-hot-middleware"
import WebpackErrorNotificationPlugin from "webpack-error-notification"

import opn from "opn"
import debug from "debug"
import portFinder from "portfinder"

import collection from "../content-loader/cache.js"
import urlAsHtml from "../static/to-html/url-as-html"
import * as pagesActions from "../redux/modules/pages"
import cleanNodeCache from "../_utils/clean-node-cache"
import joinUri from "../_utils/join-uri"
import redBoxRenderer from "../_utils/redbox-renderer"

const log = debug("statinamic:builder:server")

let firstRun = true

export default (options = {}) => {
  options = {
    noDevEntriesTest: /^tests/,
    ...options,
  }
  const { config } = options
  const { webpackConfigClient: webpackConfig } = config

  if (!config.baseUrl) {
    throw new Error(
      "You must provide a 'baseUrl' object that contains the following keys:" +
      "'href', 'port', 'hostname'. See https://nodejs.org/api/url.html"
    )
  }

  const server = express()

  if (config.static && config.server) {
    server.use(
      config.baseUrl.pathname,
      express.static(join(config.cwd, config.destination))
    )
  }
  else {
    const devEntries = [
      require.resolve("webpack-hot-middleware/client"),
    ]

    const devConfig = {
      ...webpackConfig,
      // debug: true,
      // watch: true,
      // colors: true,
      entry: {
        // add devEntries
        ...Object.keys(webpackConfig.entry)
          .reduce(
            (acc, key) => {
              // some entries do not need extra stuff
              acc[key] = key.match(options.noDevEntriesTest) !== null
                ? webpackConfig.entry[key]
                : [
                  ...devEntries,
                  ...Array.isArray(webpackConfig.entry[key])
                    ? webpackConfig.entry[key]
                    : [ webpackConfig.entry[key] ],
                ]
              return acc
            },
            {}
          ),
      },
      plugins: [
        ...(webpackConfig.plugins || []),
        ...(options.plugins || []),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new WebpackErrorNotificationPlugin(),
      ],
      eslint: {
        ...webpackConfig.eslint,
        emitWarning: true,
      },
    }

    // webpack requirements
    const webpackCompiler = webpack(devConfig)

    server.use(webpackDevMiddleware(webpackCompiler, {
      publicPath: webpackConfig.output.publicPath,
      noInfo: !config.verbose,
      ...devConfig.devServer,
    }))

    // HMR
    server.use(webpackHotMiddleware(webpackCompiler))

    let entries = []
    webpackCompiler.plugin("done", function(stats) {
      // reset entries
      entries = []
      const namedChunks = stats.compilation.namedChunks
      Object.keys(namedChunks).forEach((chunkName) => {
        entries = [
          ...entries,
          ...namedChunks[chunkName].files.filter(
            (file) => !file.endsWith(".hot-update.js")
          ),
        ]
      })
    })

    // user static assets
    if (config.assets) {
      server.use(
        config.baseUrl.pathname + config.assets.route,
        express.static(config.assets.path)
      )
    }

    // routing for the part we want (starting to the baseUrl pathname)
    const router = Router()
    server.use(config.baseUrl.pathname, router)

    // webpack static ressources
    router.get("*", express.static(webpackConfig.output.path))

    // prerender pages when possible
    const memoryFs = webpackCompiler.outputFileSystem
    router.get("*", (req, res, next) => {
      let item = getItemOrContinue(
        collection,
        config.baseUrl,
        req,
        res
      )

      // try 404.html if there is any
      if (!item) {
        req.url = "/404.html"
        item = getItemOrContinue(
          collection,
          config.baseUrl,
          req,
          res
        )
      }

      if (!item) {
        next()
        return
      }
      const filepath = join(config.cwd, config.destination, item.__dataUrl)
      const fileContent = memoryFs.readFileSync(filepath)
      const json = JSON.parse(fileContent.toString())

      options.store.dispatch({
        type: pagesActions.SET,
        page: item.__url,
        response: {
          json,
        },
      })

      if (!firstRun) {
        cleanNodeCache(config.cwd)
      }
      firstRun = false

      urlAsHtml(item.__url, {
        exports: options.exports,
        store: options.store,
        collection,
        baseUrl: config.baseUrl,
        assetsFiles: {
          js: entries,
          css: !config.dev,
        },
      })
      .then(
        (html) => {
          res.setHeader("Content-Type", "text/html")
          res.end(html)
        }
      )
      .catch((err) => {
        log(err)
        res.setHeader("Content-Type", "text/html")
        res.end(redBoxRenderer(err))
      })
    })
  }

  // THAT'S IT
  const { devHost, devPort } = config

  portFinder.basePort = devPort

  portFinder.getPort((err, port) => {
    if (err) {
      throw err
    }

    if (port !== devPort) {
      log(`Port ${ devPort } is not available. Using port ${ port } instead.`)
    }
    server.listen(port, devHost, (err) => {
      if (err) {
        throw err
      }
      const href = `http://${ devHost }:${ port }${ config.baseUrl.pathname }`
      log(`Dev server started on ${ href }`)
      if (config.open) {
        opn(href.replace(devHost, "localhost"))
      }
    })
  })
}

export function getItemOrContinue(collection, baseUrl, req, res) {
  const __url = req.url
    .replace(/index\.html$/, "")
  const item = collection.find((item) => item.__url === __url)
  if (!item) {
    log("%s not found", __url)
    const folderUrl = __url + "/"
    if (collection.find((item) => item.__url === folderUrl)) {
      const newUrl = req.url + "/"
      log("Redirecting to %s", newUrl)
      res.redirect(joinUri(baseUrl.pathname, newUrl))
    }
    return false
  }

  return item
}
<|endoftext|>