<commit_before>var React = require('react'),
  ReactDom = require('react-dom'),
  Tile = require('./Tile'),
  Animate = require('rc-animate')
;

var minSizes = {
  column: 200, // For column wrappers this is the minimun height of a row
  row: 320 // For row wrappers this is the minumum width of a column
};

var sizeTypes = {
  column: 'clientHeight',
  row: 'clientWidth'
}

var TileWrapper = React.createClass({
  getInitialState: function(){
    return {
      sizes: this.getInitialSizes( this.props.layout.children.length ),
      updatingSizes: false,
      resizing: false
    };
  },
  getInitialSizes( count ){
    var i = 0,
      sizes = []
    ;

    while( i++ < count ){
      sizes.push( 100 / count );
    }

    return sizes;
  },
  render: function(){
    var wrapperClass = [
        'tilewrapper',
        'tile' + this.props.layout.type,
        this.props.layout.id,
        this.state.updatingSizes ? 'tileResizing' : ''
      ].join(' '),
      dimensions = this.props.dimensions,
      style
    ;

    if( this.props.layout.type === 'column' ){
      style = {
        height: dimensions.height,
        width: this.isNumeric(dimensions.width) ? '100%' : dimensions.width
      }
    }
    else {
      style = {
        height: this.isNumeric(dimensions.height) ? '100%' : dimensions.height,
        width: '100%'
      }
    }

    return (
      <Animate component="div" className={ wrapperClass } style={ style } transitionName={ this.props.layout.type + '-trans' }>
        { this.renderChildren() }
        { this.renderSeparators() }
      </Animate>
    )
  },
  renderChildren: function(){
    var me = this,
      props = this.props,
      layout = props.layout,
      sizes = this.state.sizes,
      i = 0
    ;

    return layout.children.map( function( child ){
      var Component = child.type === 'tile' ? Tile : TileWrapper,
        dimensions
      ;

      if( layout.type === 'column' ){
        dimensions = {
          height: sizes[i++] + '%',
          width: props.dimensions.width
        }
      }
      else {
        dimensions = {
          height: props.dimensions.height,
          width: sizes[i++] + '%'
        }
      }

      return <Component {...props}
        layout={child}
        key={ child.id }
        dimensions={ dimensions }
        onResizeStart={ me.props.onResizeStart.bind( me ) }
        onResizeEnd={ me.props.onResizeEnd.bind( me ) } />;
    });
  },
  renderSeparators: function(){
    var separators = [],
      acc = 0,
      dim = this.props.layout.type === 'row' ? 'left' : 'top',
      className = 'separator separator-' + this.props.layout.type,
      style
    ;
    for( var i=0; i < this.state.sizes.length - 1; i++){
      style = {};
      acc += this.state.sizes[i];
      style[dim] = acc + '%';
      separators.push(
)
    }
    return separators;
  },

  isNumeric: function( n ){
    return parseFloat(n) === n;
  },
  calculateSizes: function( separatorIndex, nextPercent ){
    var updatingSizes = this.state.updatingSizes,
      sizes = updatingSizes.sizes,
      nextSizes = new Array( sizes.length ),
      prevPercent = updatingSizes.initialPercent,
      remaining, i, factor, nextPercentage
    ;

    if( nextPercent < 0 || nextPercent > 100 ){
      return;
    }

    // We want to respect the minimum size, so let's check the
    // tiles that are shrinking
    if( prevPercent > nextPercent ){
      // Moving left/up
      remaining = nextPercent;
      for( i = 0; i<=separatorIndex; i++ ){
        factor = remaining / prevPercent;
        // Min needed to not to increase the cell with the minPercentage
        nextPercentage = Math.min(sizes[i], Math.max(sizes[i] * factor, updatingSizes.minPercentage));
        nextSizes[i] = nextPercentage;
        remaining -= nextPercentage;
        prevPercent -= nextPercentage;
      }

      factor = (100 - nextPercent + remaining) /*current remaining*/ / (100 - updatingSizes.initialPercent) /*previous remaning*/;
      for( i = separatorIndex + 1; i < sizes.length; i++ ){
        nextSizes[i] = sizes[i] * factor;
      }
    }
    else {
      // Moving right/down
      remaining = 100 - nextPercent;
      prevPercent = 100 - prevPercent;
      for( i = sizes.length - 1; i>separatorIndex; i-- ){
        factor = remaining / prevPercent;

        // Min needed to not to increase the cell with the minPercentage
        nextPercentage = Math.min(sizes[i], Math.max(sizes[i] * factor, updatingSizes.minPercentage));
        nextSizes[i] = nextPercentage;
        remaining -= nextPercentage;
        prevPercent -= nextPercentage
      }

      factor = (nextPercent + remaining) /*current remaining*/ / updatingSizes.initialPercent /*previous remaining*/;
      for( i = separatorIndex; i >= 0; i-- ){
        nextSizes[i] = sizes[i] * factor;
      }
    }

    this.setState({sizes: nextSizes});
  },
  updateSizesStart: function( separatorIndex, e ){
    var me = this,
      type = this.props.layout.type,
      offset = type === 'row' ? 'left' : 'top',
      size = type === 'row' ? 'width' : 'height',
      dimension = type === 'row' ? 'clientX' : 'clientY',
      wrapper = ReactDom.findDOMNode(this).getBoundingClientRect(),
      updatingSizes = {
        wrapperOffset: wrapper[offset],
        wrapperSize: wrapper[size],
        separatorIndex: separatorIndex,
        minPercentage: minSizes[ this.props.layout.type ] / wrapper[size] * 100,
        sizes: this.state.sizes,
        startingPoint: e[dimension],
        initialPercent: 0
      },
      mm, mu
    ;

    for( var i = 0; i <= separatorIndex; i++ ) {
      updatingSizes.initialPercent += this.state.sizes[i];
    }

    this.props.onResizeStart();

    this.setState( {
      updatingSizes: updatingSizes,
      resizing: false
    });
    console.log( updatingSizes );

    window.addEventListener( 'mousemove', mm = function( e ){
      var sizes = me.state.updatingSizes;
      var nextPercent = (e[dimension] - sizes.wrapperOffset) / sizes.wrapperSize * 100;
      if( !me.state.resizing && Math.abs(sizes.startingPoint - e[dimension] ) > 5){
        me.setState({resizing: true});
        // console.log( 'Resizing', nextPercent );
        me.calculateSizes( separatorIndex, nextPercent );
      }
      else if( me.state.resizing ){
        // console.log( nextPercent );
        me.calculateSizes( separatorIndex, nextPercent );
      }
    });
    window.addEventListener( 'mouseup', mu = function( e ){
      me.setState({updatingSizes: false, resizing: false});
      console.log( me.state );
      me.props.onResizeEnd();
      window.removeEventListener( 'mousemove', mm );
      window.removeEventListener( 'mouseup', mu );
    });
  },
  componentWillReceiveProps: function( nextProps ){
    var childrenCount = nextProps.layout.children.length;
    if( childrenCount !== this.props.layout.children.length ){
      this.setState({ sizes: this.getInitialSizes(childrenCount) });
    }
  }
});

module.exports = TileWrapper;
<commit_msg>Updates the resizing to make easier resize central tiles<commit_after>var React = require('react'),
  ReactDom = require('react-dom'),
  Tile = require('./Tile'),
  Animate = require('rc-animate')
;

var minSizes = {
  column: 200, // For column wrappers this is the minimun height of a row
  row: 320 // For row wrappers this is the minumum width of a column
};

var sizeTypes = {
  column: 'clientHeight',
  row: 'clientWidth'
}

var TileWrapper = React.createClass({
  getInitialState: function(){
    return {
      sizes: this.getInitialSizes( this.props.layout.children.length ),
      updatingSizes: false,
      resizing: false
    };
  },
  getInitialSizes( count ){
    var i = 0,
      sizes = []
    ;

    while( i++ < count ){
      sizes.push( 100 / count );
    }

    return sizes;
  },
  render: function(){
    var wrapperClass = [
        'tilewrapper',
        'tile' + this.props.layout.type,
        this.props.layout.id,
        this.state.updatingSizes ? 'tileResizing' : ''
      ].join(' '),
      dimensions = this.props.dimensions,
      style
    ;

    if( this.props.layout.type === 'column' ){
      style = {
        height: dimensions.height,
        width: this.isNumeric(dimensions.width) ? '100%' : dimensions.width
      }
    }
    else {
      style = {
        height: this.isNumeric(dimensions.height) ? '100%' : dimensions.height,
        width: '100%'
      }
    }

    return (
      <Animate component="div" className={ wrapperClass } style={ style } transitionName={ this.props.layout.type + '-trans' }>
        { this.renderChildren() }
        { this.renderSeparators() }
      </Animate>
    )
  },
  renderChildren: function(){
    var me = this,
      props = this.props,
      layout = props.layout,
      sizes = this.state.sizes,
      i = 0
    ;

    return layout.children.map( function( child ){
      var Component = child.type === 'tile' ? Tile : TileWrapper,
        dimensions
      ;

      if( layout.type === 'column' ){
        dimensions = {
          height: sizes[i++] + '%',
          width: props.dimensions.width
        }
      }
      else {
        dimensions = {
          height: props.dimensions.height,
          width: sizes[i++] + '%'
        }
      }

      return <Component {...props}
        layout={child}
        key={ child.id }
        dimensions={ dimensions }
        onResizeStart={ me.props.onResizeStart.bind( me ) }
        onResizeEnd={ me.props.onResizeEnd.bind( me ) } />;
    });
  },
  renderSeparators: function(){
    var separators = [],
      acc = 0,
      dim = this.props.layout.type === 'row' ? 'left' : 'top',
      className = 'separator separator-' + this.props.layout.type,
      style
    ;
    for( var i=0; i < this.state.sizes.length - 1; i++){
      style = {};
      acc += this.state.sizes[i];
      style[dim] = acc + '%';
      separators.push(
)
    }
    return separators;
  },

  isNumeric: function( n ){
    return parseFloat(n) === n;
  },
  calculateSizes: function( separatorIndex, nextPercent ){
    var updatingSizes = this.state.updatingSizes,
      sizes = updatingSizes.sizes,
      nextSizes = new Array( sizes.length ),
      prevPercent = updatingSizes.initialPercent,
      remaining, i, factor, nextPercentage
    ;

    if( nextPercent < 0 || nextPercent > 100 ){
      return;
    }

    // We want to respect the minimum size, so let's check the
    // tiles that are shrinking
    if( prevPercent > nextPercent ){
      // Moving left/up
      remaining = nextPercent;
      for( i = 0; i<=separatorIndex; i++ ){
        factor = remaining / prevPercent;
        // Min needed to not to increase the cell with the minPercentage
        nextPercentage = Math.min(sizes[i], Math.max(sizes[i] * factor, updatingSizes.minPercentage));
        nextSizes[i] = nextPercentage;
        remaining -= nextPercentage;
        prevPercent -= nextPercentage;
      }

      factor = (100 - nextPercent + remaining) /*current remaining*/ - (100 - updatingSizes.initialPercent) /*previous remaning*/;
      for( i = separatorIndex + 1; i < sizes.length; i++ ){
        if( i == separatorIndex + 1){
          nextSizes[i] = sizes[i] + factor;
        }
        else {
          nextSizes[i] = sizes[i];
        }
      }
    }
    else {
      // Moving right/down
      remaining = 100 - nextPercent;
      prevPercent = 100 - prevPercent;
      for( i = sizes.length - 1; i>separatorIndex; i-- ){
        factor = remaining / prevPercent;

        // Min needed to not to increase the cell with the minPercentage
        nextPercentage = Math.min(sizes[i], Math.max(sizes[i] * factor, updatingSizes.minPercentage));
        nextSizes[i] = nextPercentage;
        remaining -= nextPercentage;
        prevPercent -= nextPercentage
      }

      factor = (nextPercent + remaining) /*current remaining*/ - updatingSizes.initialPercent /*previous remaining*/;
      for( i = separatorIndex; i >= 0; i-- ){
        if( i == separatorIndex){
          nextSizes[i] = sizes[i] + factor;
        }
        else {
          nextSizes[i] = sizes[i];
        }
      }
    }

    this.setState({sizes: nextSizes});
  },
  updateSizesStart: function( separatorIndex, e ){
    var me = this,
      type = this.props.layout.type,
      offset = type === 'row' ? 'left' : 'top',
      size = type === 'row' ? 'width' : 'height',
      dimension = type === 'row' ? 'clientX' : 'clientY',
      wrapper = ReactDom.findDOMNode(this).getBoundingClientRect(),
      updatingSizes = {
        wrapperOffset: wrapper[offset],
        wrapperSize: wrapper[size],
        separatorIndex: separatorIndex,
        minPercentage: minSizes[ this.props.layout.type ] / wrapper[size] * 100,
        sizes: this.state.sizes,
        startingPoint: e[dimension],
        initialPercent: 0
      },
      mm, mu
    ;

    for( var i = 0; i <= separatorIndex; i++ ) {
      updatingSizes.initialPercent += this.state.sizes[i];
    }

    this.props.onResizeStart();

    this.setState( {
      updatingSizes: updatingSizes,
      resizing: false
    });
    console.log( updatingSizes );

    window.addEventListener( 'mousemove', mm = function( e ){
      var sizes = me.state.updatingSizes;
      var nextPercent = (e[dimension] - sizes.wrapperOffset) / sizes.wrapperSize * 100;
      if( !me.state.resizing && Math.abs(sizes.startingPoint - e[dimension] ) > 5){
        me.setState({resizing: true});
        // console.log( 'Resizing', nextPercent );
        me.calculateSizes( separatorIndex, nextPercent );
      }
      else if( me.state.resizing ){
        // console.log( nextPercent );
        me.calculateSizes( separatorIndex, nextPercent );
      }
    });
    window.addEventListener( 'mouseup', mu = function( e ){
      me.setState({updatingSizes: false, resizing: false});
      console.log( me.state );
      me.props.onResizeEnd();
      window.removeEventListener( 'mousemove', mm );
      window.removeEventListener( 'mouseup', mu );
    });
  },
  componentWillReceiveProps: function( nextProps ){
    var childrenCount = nextProps.layout.children.length;
    if( childrenCount !== this.props.layout.children.length ){
      this.setState({ sizes: this.getInitialSizes(childrenCount) });
    }
  }
});

module.exports = TileWrapper;
<|endoftext|>


<commit_before>import React from 'react';
import {graphql, compose, withApollo} from 'react-apollo';
import {
  Checkbox,
  Confirm,
  Container,
  Dropdown,
  Button,
  Grid,
  Icon,
  Input,
  Popup,
  Transition,
} from 'semantic-ui-react';
import RunFeed from '../components/RunFeed';
import RunFiltersRedux from './RunFiltersRedux';
import RunColumnsSelector from '../components/RunColumnsSelector';
import ViewModifier from './ViewModifier';
import HelpIcon from '../components/HelpIcon';
import {MODIFY_RUNS} from '../graphql/runs';
import {MODEL_UPSERT} from '../graphql/models';
import {connect} from 'react-redux';
import queryString from 'query-string';
import _ from 'lodash';
import {
  sortRuns,
  flatKeySuggestions,
  defaultViews,
  parseBuckets,
  setupKeySuggestions,
} from '../util/runhelpers.js';
import {MAX_HISTORIES_LOADED} from '../util/constants.js';
import {bindActionCreators} from 'redux';
import {setColumns, setFilters} from '../actions/run';
import {
  resetViews,
  setServerViews,
  setBrowserViews,
  setActiveView,
  addView,
} from '../actions/view';
import update from 'immutability-helper';
import {BOARD} from '../util/board';
import withRunsDataLoader from '../containers/RunsDataLoader';
import withRunsQueryRedux from '../containers/RunsQueryRedux';
import * as Filter from '../util/filters';
import * as Selection from '../util/selections';

class Runs extends React.Component {
  state = {showFailed: false, activeTab: 0, showFilters: false};

  componentDidUpdate() {
    window.Prism.highlightAll();
  }

  onSort = (column, order = 'descending') => {
    this.props.refetch({order: [column, order].join(' ')});
  };

  _shareableUrl(props) {
    let query = {};
    if (!_.isEmpty(props.runFilters)) {
      query.filters = Filter.toURL(props.runFilters);
    }
    if (!_.isEmpty(props.runSelections)) {
      query.selections = Filter.toURL(props.runSelections);
    }
    if (!_.isNil(props.activeView)) {
      query.activeView = props.activeView;
    }
    return (
      `${window.location.protocol}//${window.location.host}${
        window.location.pathname
      }` +
      '?' +
      queryString.stringify(query)
    );
  }

  _readUrl(props) {
    var parsed = queryString.parse(window.location.search);
    if (!parsed) {
      return;
    }
    let filterFilters;
    if (parsed.filters) {
      filterFilters = Filter.fromURL(parsed.filters);
    } else if (parsed.filter) {
      let filts = parsed.filter;
      if (!_.isArray(filts)) {
        filts = [filts];
      }
      filterFilters = Filter.fromOldURL(filts);
    }
    let selectFilters;
    if (parsed.selections) {
      selectFilters = Filter.fromURL(parsed.selections);
    } else if (parsed.select) {
      let filts = parsed.select;
      if (!_.isArray(filts)) {
        filts = [filts];
      }
      selectFilters = Filter.fromOldURL(filts);
    }

    if (filterFilters) {
      this.props.setFilters('filter', filterFilters);
    } else {
      this.props.setFilters('filter', {
        op: 'OR',
        filters: [
          {
            op: 'AND',
            filters: [
              {key: {section: 'tags', name: 'hidden'}, op: '=', value: false},
            ],
          },
        ],
      });
    }

    if (selectFilters) {
      this.props.setFilters('select', selectFilters);
    } else {
      this.props.setFilters('select', Selection.all());
    }

    if (!_.isNil(parsed.activeView)) {
      this.props.setActiveView('runs', parseInt(parsed.activeView, 10));
    }
  }

  componentWillMount() {
    this.props.resetViews();
    this._readUrl(this.props);
  }

  componentDidMount() {
    this.doneLoading = false;
  }

  componentWillReceiveProps(nextProps) {
    if (
      !this.doneLoading &&
      nextProps.loading === false &&
      nextProps.data.base.length > 0
    ) {
      this.doneLoading = true;
      let defaultColumns = {
        Description: true,
        Ran: true,
        Runtime: true,
        _ConfigAuto: true,
        Sweep: _.indexOf(nextProps.data.columnNames, 'Sweep') !== -1,
      };
      let summaryColumns = nextProps.data.columnNames.filter(col =>
        _.startsWith(col, 'summary')
      );
      for (var col of summaryColumns) {
        defaultColumns[col] = true;
      }
      this.props.setColumns(defaultColumns);
    }
    // Setup views loaded from server.
    if (
      nextProps.data.base.length > 0 &&
      (nextProps.views === null || !nextProps.views.runs) &&
      _.isEmpty(this.props.reduxServerViews.runs.views) &&
      _.isEmpty(this.props.reduxBrowserViews.runs.views)
    ) {
      // no views on server, provide a default
      this.props.setBrowserViews(
        defaultViews((nextProps.buckets.edges[0] || {}).node)
      );
    } else if (
      nextProps.views &&
      nextProps.views.runs &&
      !_.isEqual(nextProps.views, this.props.reduxServerViews)
    ) {
      if (
        _.isEqual(this.props.reduxServerViews, this.props.reduxBrowserViews)
      ) {
        this.props.setBrowserViews(nextProps.views);
      }
      this.props.setServerViews(nextProps.views);
    }
  }

  handleTabChange = (e, {activeIndex}) =>
    this.setState({activeTab: activeIndex});

  render() {
    let ModelInfo = this.props.ModelInfo;
    const filterCount = Filter.countIndividual(this.props.runFilters);
    return (
      <Container>
        <Confirm
          open={this.state.showConfirm}
          onCancel={this.state.handleCancel}
          onConfirm={this.state.handleConfirm}
          content={this.state.confirmText}
          confirmButton={this.state.confirmButton}
        />
        <Grid>
          <Grid.Row divided columns={2}>
            <Grid.Column>{ModelInfo}</Grid.Column>
            <Grid.Column textAlign="right">

                <Popup
                  content={
                    <Input
                      style={{minWidth: 520}}
                      value={this._shareableUrl(this.props)}
                    />
                  }
                  style={{width: '100%'}}
                  on="click"
                  position="bottom right"
                  wide="very"
                  trigger={
                    <Button
                      style={{marginRight: 6}}
                      icon="linkify"
                      size="mini"
                    />
                  }
                />
                {this.props.data.base.length} total runs,{' '}
                {this.props.data.filtered.length} filtered,{' '}
                {this.props.data.selectedRuns.length} selected

                    this.setState({showFilters: !this.state.showFilters})
                  }>
                  <Icon
                    rotated={this.state.showFilters ? null : 'counterclockwise'}
                    name="dropdown"
                  />
                  {filterCount + ' Filter' + (filterCount === 1 ? '' : 's')}

            </Grid.Column>
          </Grid.Row>
          <Grid.Row>
            <Grid.Column>
              <Transition.Group
                className="ui grid"
                animation="slide right"
                duration={200}>
                {this.state.showFilters && (
                  <Grid.Row>
                    <Grid.Column width={16}>

                        Filters{' '}
                        <HelpIcon text="Filters limit the set of runs that will be displayed in charts and tables on this page." />

                      <RunFiltersRedux
                        kind="filter"
                        buttonText="Add Filter"
                        keySuggestions={flatKeySuggestions(
                          this.props.data.keys
                        )}
                        runs={this.props.data.base}
                        filteredRuns={this.props.data.filtered}
                      />
                    </Grid.Column>
                  </Grid.Row>
                )}
              </Transition.Group>
            </Grid.Column>
          </Grid.Row>
          <Grid.Column width={16}>
            {this.props.haveViews && (
              <ViewModifier
                viewType="runs"
                data={this.props.data}
                pageQuery={this.props.query}
                updateViews={views =>
                  this.props.updateModel({
                    entityName: this.props.match.params.entity,
                    name: this.props.match.params.model,
                    id: this.props.projectID,
                    views: views,
                  })
                }
              />
            )}
          </Grid.Column>
          <Grid.Column width={16} style={{zIndex: 2}}>
            <Popup
              trigger={
                <Button
                  disabled={this.props.loading}
                  floated="right"
                  icon="columns"
                  content="Columns"
                />
              }
              content={
                <RunColumnsSelector columnNames={this.props.data.columnNames} />
              }
              on="click"
              position="bottom left"
            />
            {!this.props.haveViews && (
              <Button
                floated="right"
                content="Add Charts"
                disabled={this.props.loading}
                icon="area chart"
                onClick={() => this.props.addView('runs', 'New View', [])}
              />
            )}
            <Button
              floated="right"
              disabled={this.props.data.selectedRuns.length === 0}
              onClick={e => {
                // TODO(adrian): this should probably just be a separate component
                e.preventDefault();

                this.setState({
                  showConfirm: true,
                  confirmText:
                    'Are you sure you would like to hide these runs? You can reverse this later by removing the "hidden" label.',
                  confirmButton: `Hide ${
                    this.props.data.selectedRuns.length
                  } run(s)`,
                  handleConfirm: e => {
                    e.preventDefault();
                    this.props.modifyRuns({
                      ids: this.props.data.selectedRuns.map(run => run.id),
                      addTags: ['hidden'],
                    });
                    this.setState({
                      showConfirm: false,
                      handleConfirm: null,
                      handleCancel: null,
                    });
                  },
                  handleCancel: e => {
                    e.preventDefault();
                    this.setState({
                      showConfirm: false,
                      handleConfirm: null,
                      handleCancel: null,
                    });
                  },
                });
              }}>
              <Icon name="trash" />
              Hide {this.props.data.selectedRuns.length} run(s)
            </Button>
            <Dropdown
              icon={null}
              trigger={
                <Button>
                  <Icon
                    name={
                      this.props.data.selectedRuns.length === 0
                        ? 'square outline'
                        : this.props.data.selectedRuns.length ===
                          this.props.data.filtered.length
                          ? 'checkmark box'
                          : 'minus square outline'
                    }
                  />
                  Select
                </Button>
              }
              onClick={(e, {value}) => console.log('dropdown click', value)}>
              <Dropdown.Menu>
                <Dropdown.Item
                  onClick={() =>
                    this.props.setFilters('select', Selection.all())
                  }>
                  <Icon
                    style={{marginRight: 4}}
                    color="grey"
                    name="checkmark box"
                  />{' '}
                  All
                </Dropdown.Item>
                <Dropdown.Item
                  onClick={() =>
                    this.props.setFilters('select', Selection.none())
                  }>
                  <Icon
                    style={{marginRight: 4}}
                    color="grey"
                    name="square outline"
                  />{' '}
                  None
                </Dropdown.Item>
              </Dropdown.Menu>
            </Dropdown>
            {/*

              Select
              all
              none

 */}
          </Grid.Column>
        </Grid>
        <RunFeed
          admin={this.props.user && this.props.user.admin}
          loading={this.props.loading}
          runs={this.props.data.filtered}
          project={this.props.model}
          onSort={this.onSort}
          showFailed={this.state.showFailed}
          selectable={true}
          selectedRuns={this.props.data.selectedRunsById}
          columnNames={this.props.data.columnNames}
          limit={this.props.limit}
        />
      </Container>
    );
  }
}

const withMutations = compose(
  graphql(MODEL_UPSERT, {
    props: ({mutate}) => ({
      updateModel: variables =>
        mutate({
          variables: {...variables},
          updateQueries: {
            Model: (prev, {mutationResult}) => {
              const newModel = mutationResult.data.upsertModel.model;
              return update(prev, {model: {$set: newModel}});
            },
          },
        }),
    }),
  }),
  graphql(MODIFY_RUNS, {
    props: ({mutate}) => ({
      modifyRuns: variables => {
        mutate({
          variables: {...variables},
        });
      },
    }),
  })
);

function mapStateToProps(state, ownProps) {
  return {
    jobId: state.runs.currentJob,
    runFilters: state.runs.filters.filter,
    runSelections: state.runs.filters.select,
    user: state.global.user,
    sort: state.runs.sort,
    filterModel: state.runs.filterModel,
    reduxServerViews: state.views.server,
    reduxBrowserViews: state.views.browser,
    activeView: state.views.other.runs.activeView,
    haveViews:
      !_.isEqual(state.views.browser, state.views.server) ||
      state.views.browser.runs.tabs.length > 0,
  };
}

// export dumb component for testing purposes
export {Runs};

const mapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators(
    {
      setColumns,
      setFilters,
      setServerViews,
      setBrowserViews,
      setActiveView,
      resetViews,
      addView,
    },
    dispatch
  );
};

export default connect(mapStateToProps, mapDispatchToProps)(
  withMutations(withRunsQueryRedux(withRunsDataLoader(Runs)))
);
<commit_msg>New hide icon<commit_after>import React from 'react';
import {graphql, compose, withApollo} from 'react-apollo';
import {
  Checkbox,
  Confirm,
  Container,
  Dropdown,
  Button,
  Grid,
  Icon,
  Input,
  Popup,
  Transition,
} from 'semantic-ui-react';
import RunFeed from '../components/RunFeed';
import RunFiltersRedux from './RunFiltersRedux';
import RunColumnsSelector from '../components/RunColumnsSelector';
import ViewModifier from './ViewModifier';
import HelpIcon from '../components/HelpIcon';
import {MODIFY_RUNS} from '../graphql/runs';
import {MODEL_UPSERT} from '../graphql/models';
import {connect} from 'react-redux';
import queryString from 'query-string';
import _ from 'lodash';
import {
  sortRuns,
  flatKeySuggestions,
  defaultViews,
  parseBuckets,
  setupKeySuggestions,
} from '../util/runhelpers.js';
import {MAX_HISTORIES_LOADED} from '../util/constants.js';
import {bindActionCreators} from 'redux';
import {setColumns, setFilters} from '../actions/run';
import {
  resetViews,
  setServerViews,
  setBrowserViews,
  setActiveView,
  addView,
} from '../actions/view';
import update from 'immutability-helper';
import {BOARD} from '../util/board';
import withRunsDataLoader from '../containers/RunsDataLoader';
import withRunsQueryRedux from '../containers/RunsQueryRedux';
import * as Filter from '../util/filters';
import * as Selection from '../util/selections';

class Runs extends React.Component {
  state = {showFailed: false, activeTab: 0, showFilters: false};

  componentDidUpdate() {
    window.Prism.highlightAll();
  }

  onSort = (column, order = 'descending') => {
    this.props.refetch({order: [column, order].join(' ')});
  };

  _shareableUrl(props) {
    let query = {};
    if (!_.isEmpty(props.runFilters)) {
      query.filters = Filter.toURL(props.runFilters);
    }
    if (!_.isEmpty(props.runSelections)) {
      query.selections = Filter.toURL(props.runSelections);
    }
    if (!_.isNil(props.activeView)) {
      query.activeView = props.activeView;
    }
    return (
      `${window.location.protocol}//${window.location.host}${
        window.location.pathname
      }` +
      '?' +
      queryString.stringify(query)
    );
  }

  _readUrl(props) {
    var parsed = queryString.parse(window.location.search);
    if (!parsed) {
      return;
    }
    let filterFilters;
    if (parsed.filters) {
      filterFilters = Filter.fromURL(parsed.filters);
    } else if (parsed.filter) {
      let filts = parsed.filter;
      if (!_.isArray(filts)) {
        filts = [filts];
      }
      filterFilters = Filter.fromOldURL(filts);
    }
    let selectFilters;
    if (parsed.selections) {
      selectFilters = Filter.fromURL(parsed.selections);
    } else if (parsed.select) {
      let filts = parsed.select;
      if (!_.isArray(filts)) {
        filts = [filts];
      }
      selectFilters = Filter.fromOldURL(filts);
    }

    if (filterFilters) {
      this.props.setFilters('filter', filterFilters);
    } else {
      this.props.setFilters('filter', {
        op: 'OR',
        filters: [
          {
            op: 'AND',
            filters: [
              {key: {section: 'tags', name: 'hidden'}, op: '=', value: false},
            ],
          },
        ],
      });
    }

    if (selectFilters) {
      this.props.setFilters('select', selectFilters);
    } else {
      this.props.setFilters('select', Selection.all());
    }

    if (!_.isNil(parsed.activeView)) {
      this.props.setActiveView('runs', parseInt(parsed.activeView, 10));
    }
  }

  componentWillMount() {
    this.props.resetViews();
    this._readUrl(this.props);
  }

  componentDidMount() {
    this.doneLoading = false;
  }

  componentWillReceiveProps(nextProps) {
    if (
      !this.doneLoading &&
      nextProps.loading === false &&
      nextProps.data.base.length > 0
    ) {
      this.doneLoading = true;
      let defaultColumns = {
        Description: true,
        Ran: true,
        Runtime: true,
        _ConfigAuto: true,
        Sweep: _.indexOf(nextProps.data.columnNames, 'Sweep') !== -1,
      };
      let summaryColumns = nextProps.data.columnNames.filter(col =>
        _.startsWith(col, 'summary')
      );
      for (var col of summaryColumns) {
        defaultColumns[col] = true;
      }
      this.props.setColumns(defaultColumns);
    }
    // Setup views loaded from server.
    if (
      nextProps.data.base.length > 0 &&
      (nextProps.views === null || !nextProps.views.runs) &&
      _.isEmpty(this.props.reduxServerViews.runs.views) &&
      _.isEmpty(this.props.reduxBrowserViews.runs.views)
    ) {
      // no views on server, provide a default
      this.props.setBrowserViews(
        defaultViews((nextProps.buckets.edges[0] || {}).node)
      );
    } else if (
      nextProps.views &&
      nextProps.views.runs &&
      !_.isEqual(nextProps.views, this.props.reduxServerViews)
    ) {
      if (
        _.isEqual(this.props.reduxServerViews, this.props.reduxBrowserViews)
      ) {
        this.props.setBrowserViews(nextProps.views);
      }
      this.props.setServerViews(nextProps.views);
    }
  }

  handleTabChange = (e, {activeIndex}) =>
    this.setState({activeTab: activeIndex});

  render() {
    let ModelInfo = this.props.ModelInfo;
    const filterCount = Filter.countIndividual(this.props.runFilters);
    return (
      <Container>
        <Confirm
          open={this.state.showConfirm}
          onCancel={this.state.handleCancel}
          onConfirm={this.state.handleConfirm}
          content={this.state.confirmText}
          confirmButton={this.state.confirmButton}
        />
        <Grid>
          <Grid.Row divided columns={2}>
            <Grid.Column>{ModelInfo}</Grid.Column>
            <Grid.Column textAlign="right">

                <Popup
                  content={
                    <Input
                      style={{minWidth: 520}}
                      value={this._shareableUrl(this.props)}
                    />
                  }
                  style={{width: '100%'}}
                  on="click"
                  position="bottom right"
                  wide="very"
                  trigger={
                    <Button
                      style={{marginRight: 6}}
                      icon="linkify"
                      size="mini"
                    />
                  }
                />
                {this.props.data.base.length} total runs,{' '}
                {this.props.data.filtered.length} filtered,{' '}
                {this.props.data.selectedRuns.length} selected

                    this.setState({showFilters: !this.state.showFilters})
                  }>
                  <Icon
                    rotated={this.state.showFilters ? null : 'counterclockwise'}
                    name="dropdown"
                  />
                  {filterCount + ' Filter' + (filterCount === 1 ? '' : 's')}

            </Grid.Column>
          </Grid.Row>
          <Grid.Row>
            <Grid.Column>
              <Transition.Group
                className="ui grid"
                animation="slide right"
                duration={200}>
                {this.state.showFilters && (
                  <Grid.Row>
                    <Grid.Column width={16}>

                        Filters{' '}
                        <HelpIcon text="Filters limit the set of runs that will be displayed in charts and tables on this page." />

                      <RunFiltersRedux
                        kind="filter"
                        buttonText="Add Filter"
                        keySuggestions={flatKeySuggestions(
                          this.props.data.keys
                        )}
                        runs={this.props.data.base}
                        filteredRuns={this.props.data.filtered}
                      />
                    </Grid.Column>
                  </Grid.Row>
                )}
              </Transition.Group>
            </Grid.Column>
          </Grid.Row>
          <Grid.Column width={16}>
            {this.props.haveViews && (
              <ViewModifier
                viewType="runs"
                data={this.props.data}
                pageQuery={this.props.query}
                updateViews={views =>
                  this.props.updateModel({
                    entityName: this.props.match.params.entity,
                    name: this.props.match.params.model,
                    id: this.props.projectID,
                    views: views,
                  })
                }
              />
            )}
          </Grid.Column>
          <Grid.Column width={16} style={{zIndex: 2}}>
            <Popup
              trigger={
                <Button
                  disabled={this.props.loading}
                  floated="right"
                  icon="columns"
                  content="Columns"
                />
              }
              content={
                <RunColumnsSelector columnNames={this.props.data.columnNames} />
              }
              on="click"
              position="bottom left"
            />
            {!this.props.haveViews && (
              <Button
                floated="right"
                content="Add Charts"
                disabled={this.props.loading}
                icon="area chart"
                onClick={() => this.props.addView('runs', 'New View', [])}
              />
            )}
            <Button
              floated="right"
              disabled={this.props.data.selectedRuns.length === 0}
              onClick={e => {
                // TODO(adrian): this should probably just be a separate component
                e.preventDefault();

                this.setState({
                  showConfirm: true,
                  confirmText:
                    'Are you sure you would like to hide these runs? You can reverse this later by removing the "hidden" label.',
                  confirmButton: `Hide ${
                    this.props.data.selectedRuns.length
                  } run(s)`,
                  handleConfirm: e => {
                    e.preventDefault();
                    this.props.modifyRuns({
                      ids: this.props.data.selectedRuns.map(run => run.id),
                      addTags: ['hidden'],
                    });
                    this.setState({
                      showConfirm: false,
                      handleConfirm: null,
                      handleCancel: null,
                    });
                  },
                  handleCancel: e => {
                    e.preventDefault();
                    this.setState({
                      showConfirm: false,
                      handleConfirm: null,
                      handleCancel: null,
                    });
                  },
                });
              }}>
              <Icon name="hide" />
              Hide {this.props.data.selectedRuns.length} run(s)
            </Button>
            <Dropdown
              icon={null}
              trigger={
                <Button>
                  <Icon
                    name={
                      this.props.data.selectedRuns.length === 0
                        ? 'square outline'
                        : this.props.data.selectedRuns.length ===
                          this.props.data.filtered.length
                          ? 'checkmark box'
                          : 'minus square outline'
                    }
                  />
                  Select
                </Button>
              }
              onClick={(e, {value}) => console.log('dropdown click', value)}>
              <Dropdown.Menu>
                <Dropdown.Item
                  onClick={() =>
                    this.props.setFilters('select', Selection.all())
                  }>
                  <Icon
                    style={{marginRight: 4}}
                    color="grey"
                    name="checkmark box"
                  />{' '}
                  All
                </Dropdown.Item>
                <Dropdown.Item
                  onClick={() =>
                    this.props.setFilters('select', Selection.none())
                  }>
                  <Icon
                    style={{marginRight: 4}}
                    color="grey"
                    name="square outline"
                  />{' '}
                  None
                </Dropdown.Item>
              </Dropdown.Menu>
            </Dropdown>
            {/*

              Select
              all
              none

 */}
          </Grid.Column>
        </Grid>
        <RunFeed
          admin={this.props.user && this.props.user.admin}
          loading={this.props.loading}
          runs={this.props.data.filtered}
          project={this.props.model}
          onSort={this.onSort}
          showFailed={this.state.showFailed}
          selectable={true}
          selectedRuns={this.props.data.selectedRunsById}
          columnNames={this.props.data.columnNames}
          limit={this.props.limit}
        />
      </Container>
    );
  }
}

const withMutations = compose(
  graphql(MODEL_UPSERT, {
    props: ({mutate}) => ({
      updateModel: variables =>
        mutate({
          variables: {...variables},
          updateQueries: {
            Model: (prev, {mutationResult}) => {
              const newModel = mutationResult.data.upsertModel.model;
              return update(prev, {model: {$set: newModel}});
            },
          },
        }),
    }),
  }),
  graphql(MODIFY_RUNS, {
    props: ({mutate}) => ({
      modifyRuns: variables => {
        mutate({
          variables: {...variables},
        });
      },
    }),
  })
);

function mapStateToProps(state, ownProps) {
  return {
    jobId: state.runs.currentJob,
    runFilters: state.runs.filters.filter,
    runSelections: state.runs.filters.select,
    user: state.global.user,
    sort: state.runs.sort,
    filterModel: state.runs.filterModel,
    reduxServerViews: state.views.server,
    reduxBrowserViews: state.views.browser,
    activeView: state.views.other.runs.activeView,
    haveViews:
      !_.isEqual(state.views.browser, state.views.server) ||
      state.views.browser.runs.tabs.length > 0,
  };
}

// export dumb component for testing purposes
export {Runs};

const mapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators(
    {
      setColumns,
      setFilters,
      setServerViews,
      setBrowserViews,
      setActiveView,
      resetViews,
      addView,
    },
    dispatch
  );
};

export default connect(mapStateToProps, mapDispatchToProps)(
  withMutations(withRunsQueryRedux(withRunsDataLoader(Runs)))
);
<|endoftext|>


<commit_before>var grow = grow || {};
window.grow = grow;

(function(grow){
  var toolConfig = {};

  grow.ui = grow.ui || {};

  grow.ui.showNotice = function(text) {
    var notice = document.createElement('div');
    notice.classList.add('grow_tool__notice');
    notice.appendChild(document.createTextNode(text));

    document.body.appendChild(notice);
    return notice;
  };

  grow.ui.toolConfig = function(tool, options) {
    toolConfig[tool] = options;
  };

  grow.ui.tools = grow.ui.tools || [];
  grow.ui.main = function(settings) {
    var el = document.createElement('div');
    var buttonsEl = document.createElement('div');
    buttonsEl.setAttribute('class', 'grow__buttons');

    buttonsEl.appendChild(createButton_('primary', null, null, {
      'click': function() {
        buttonsEl.classList.toggle('grow__expand');
      }
    }));

    buttonsEl.appendChild(createButton_('close', null, null, {
      'click': function() {
        el.parentNode.removeChild(el);
      }
    }));

    if (settings.injectEditUrl) {
      buttonsEl.appendChild(
        createButton_('edit', 'Edit', settings.injectEditUrl));
    }

    if (settings.injectTranslateUrl) {
      buttonsEl.appendChild(createButton_(
        'translate', 'Translate', settings.injectTranslateUrl));
    }

    for(i in grow.ui.tools) {
      tool = grow.ui.tools[i];

      if (tool['init']) {
        tool['init'](toolConfig[tool['kind']] || {});
      }

      if (tool['button']) {
        buttonsEl.appendChild(createButton_(
          tool['kind'], tool['name'], tool['button']['link'] || null,
          tool['button']['events'] || {}));
      }
    }

    // If there is nothing to do, do not show the menu at all.
    if (buttonsEl.children.length <= 2) {
      return;
    }

    el.setAttribute('id', 'grow-utils');
    el.appendChild(buttonsEl);
    document.body.appendChild(el);
  };

  var createButton_ = function(kind, label, url, events) {
    var containerEl = document.createElement('div');
    containerEl.classList.add('grow__button');

    var buttonEl = document.createElement('a');
    buttonEl.classList.add('grow__icon');
    buttonEl.classList.add('grow__icon_' + kind);

    if (url) {
      buttonEl.setAttribute('href', url);
      buttonEl.setAttribute('target', '_blank');
    } else {
      buttonEl.setAttribute('href', 'javascript:void(0)');
    }

    if (events) {
      for (var prop in events) {
        buttonEl.addEventListener(prop, events[prop]);
      }
    }

    containerEl.appendChild(buttonEl);

    if (label) {
      var labelEl = document.createElement('p');
      labelEl.appendChild(document.createTextNode(label));
      labelEl.classList.add('grow__label');
      containerEl.appendChild(labelEl);
    }

    return containerEl;
  };
})(grow);
<commit_msg>Making the notice text optional.<commit_after>var grow = grow || {};
window.grow = grow;

(function(grow){
  var toolConfig = {};

  grow.ui = grow.ui || {};

  grow.ui.showNotice = function(text) {
    var notice = document.createElement('div');
    notice.classList.add('grow_tool__notice');

    if (text) {
      notice.appendChild(document.createTextNode(text));
    }

    document.body.appendChild(notice);
    return notice;
  };

  grow.ui.toolConfig = function(tool, options) {
    toolConfig[tool] = options;
  };

  grow.ui.tools = grow.ui.tools || [];
  grow.ui.main = function(settings) {
    var el = document.createElement('div');
    var buttonsEl = document.createElement('div');
    buttonsEl.setAttribute('class', 'grow__buttons');

    buttonsEl.appendChild(createButton_('primary', null, null, {
      'click': function() {
        buttonsEl.classList.toggle('grow__expand');
      }
    }));

    buttonsEl.appendChild(createButton_('close', null, null, {
      'click': function() {
        el.parentNode.removeChild(el);
      }
    }));

    if (settings.injectEditUrl) {
      buttonsEl.appendChild(
        createButton_('edit', 'Edit', settings.injectEditUrl));
    }

    if (settings.injectTranslateUrl) {
      buttonsEl.appendChild(createButton_(
        'translate', 'Translate', settings.injectTranslateUrl));
    }

    for(i in grow.ui.tools) {
      tool = grow.ui.tools[i];

      if (tool['init']) {
        tool['init'](toolConfig[tool['kind']] || {});
      }

      if (tool['button']) {
        buttonsEl.appendChild(createButton_(
          tool['kind'], tool['name'], tool['button']['link'] || null,
          tool['button']['events'] || {}));
      }
    }

    // If there is nothing to do, do not show the menu at all.
    if (buttonsEl.children.length <= 2) {
      return;
    }

    el.setAttribute('id', 'grow-utils');
    el.appendChild(buttonsEl);
    document.body.appendChild(el);
  };

  var createButton_ = function(kind, label, url, events) {
    var containerEl = document.createElement('div');
    containerEl.classList.add('grow__button');

    var buttonEl = document.createElement('a');
    buttonEl.classList.add('grow__icon');
    buttonEl.classList.add('grow__icon_' + kind);

    if (url) {
      buttonEl.setAttribute('href', url);
      buttonEl.setAttribute('target', '_blank');
    } else {
      buttonEl.setAttribute('href', 'javascript:void(0)');
    }

    if (events) {
      for (var prop in events) {
        buttonEl.addEventListener(prop, events[prop]);
      }
    }

    containerEl.appendChild(buttonEl);

    if (label) {
      var labelEl = document.createElement('p');
      labelEl.appendChild(document.createTextNode(label));
      labelEl.classList.add('grow__label');
      containerEl.appendChild(labelEl);
    }

    return containerEl;
  };
})(grow);
<|endoftext|>


<commit_before>define(["Ti/_/declare", "Ti/_/UI/Widget", "Ti/_/dom", "Ti/_/event", "Ti/_/lang", "Ti/_/text!Ti/_/UI/WebViewBridge.js", "Ti/App", "Ti/API", "Ti/UI"],
	function(declare, Widget, dom, event, lang, bridge, App, API, UI) {

	var on = require.on;

	return declare("Ti.UI.WebView", Widget, {

		constructor: function() {
			App.addEventListener(this.widgetId + ":unload", lang.hitch(this, function() {
				this._loading(1);
			}));
			this.backgroundColor = "#fff";
		},

		_preventDefaultTouchEvent: false,

		destroy: function() {
			App.removeEventListener(this.widgetId + ":unload");
			this._destroy();
			Widget.prototype.destroy.apply(this, arguments);
		},

		_destroy: function() {
			if (this._iframe) {
				event.off(this._iframeHandles);
				dom.destroy(this._iframe);
			}
		},

		_createIFrame: function() {
			if (this._parent) {
				this._destroy();
				this._loading(1);

				var url = this.url || "",
					match = url.match(/(https?)\:\/\/([^\:\/]*)(:?\d*)(.*)/),
					loc = window.location,
					isSameDomain = !match || (match[0] + ":" === loc.protocol && match[1] + match[2] === window.location.host),
					iframe = this._iframe = dom.create("iframe", {
						frameborder: 0,
						marginwidth: 0,
						marginheight: 0,
						hspace: 0,
						vspace: 0,
						scrolling: this.showScrollbars ? "auto" : "no",
						src: url || require.toUrl("Ti/_/UI/blank.html"),
						style: {
							width: "100%",
							height: "100%"
						}
					}, this.domNode);

				this._iframeHandles = [
					on(iframe, "load", this, function(evt) {
						var i = Math.max(isSameDomain | 0, 0),
							cw = iframe.contentWindow,
							prop,
							url,
							html;

						if (i !== -1) {
							// we can always guarantee that the first load we'll know if it's the same domain
							isSameDomain = -1;
						} else {
							// for every load after the first, we need to try which will throw security errors
							for (prop in cw) {
								i++;
								break;
							}
						}

						if (i > 0) {
							url = cw.location.href;
							this.evalJS(bridge.replace("WEBVIEW_ID", this.widgetId + ":unload"));
							(html = this.properties.__values__.html) && this._setContent(html);
						} else {
							API.warn("Unable to inject WebView bridge into cross-domain URL, ignore browser security message");
						}

						this._loading();
						this.fireEvent("load", {
							url: url ? (this.properties.__values__.url = url) : this.url
						});
					}),
					on(iframe, "error", this, function() {
						this._loading();
						this.fireEvent("error", {
							message: "Page failed to load",
							url: this.url
						});
					})
				];

				return 1;
			}
		},

		_setParent: function(view) {
			Widget.prototype._setParent.apply(this, arguments);

			// we are being added to a parent, need to manually fire
			(this.url || this.html) && this._createIFrame();
		},

		_getWindow: function() {
			return this._iframe.contentWindow;
		},

		_getDoc: function() {
			return this._getWindow().document;
		},

		_getHistory: function() {
			return this._getWindow().history;
		},

		_loading: function(v) {
			this.loading || v && this.fireEvent("beforeload", {
				url: this.url
			});
			this.constants.loading = !!v;
		},

		canGoBack: function() {
			return this.url && !!this._getHistory().length;
		},

		canGoForward: function() {
			return this.url && !!this._getHistory().length;
		},

		evalJS: function(js) {
			var w = this._getWindow(),
				r = null;
			try {
				r = js && w && w.eval && w.eval(js);
			} catch (e) {}
			return r;
		},

		goBack: function() {
			if (this.canGoBack()) {
				var h = this._getHistory();
				if (h) {
					this._loading(1);
					h.go(-1);
				}
			}
		},

		goForward: function() {
			if (this.canGoForward()) {
				var h = this._getHistory();
				if (h) {
					this._loading(1);
					h.go(1);
				}
			}
		},

		setBasicAuthentication: function(username, password) {
			var url = this.url,
				protocolIndex = url.indexOf('//');
			url = url.substring(0, protocolIndex + 2) + username + ":" + password + "@" + url.substring(protocolIndex + 2, url.length);
			this.url = url;
			console.log(this.url);
		},

		reload: function() {
			var w = this._getWindow();
			this.url && w ? (w.location.href = this.url) : this._createIFrame();
		},

		stopLoading: function(hardStop) {
			try {
				this.loading && hardStop ? this._destroy() : this._getWindow().stop();
			} catch (e) {}
			this._loading();
		},

		_defaultWidth: UI.FILL,

		_defaultHeight: UI.FILL,

		_getContentSize: function() {
			return {
				width: this._iframe ? this._iframe.clientWidth : 0,
				height: this._iframe ? this._iframe.clientHeight : 0
			};
		},

		_setContent: function(value) {
			try {
				var doc = this._getDoc();
				doc.open();
				doc.write(value);
				doc.close();
			} catch (e) {}
			return value;
		},

		properties: {
			data: {
				set: function(value) {
					var data = value;
					switch (data && data.declaredClass) {
						case "Ti.Filesystem.File":
							data = data.read();
						case "Ti.Blob":
							data = data.toString();
						default:
							this.html = data;
					}
					return value;
				}
			},

			html: {
				get: function(value) {
					var doc = this._iframe && this._getDoc();
					return value === void 0 && doc ? doc.documentElement.innerHTML : value;
				},
				post: function(value) {
					var values = this.properties.__values__;
					values.data = void 0;
					values.url = void 0;
					this._createIFrame() && this._setContent(value);
				}
			},

			showScrollbars: {
				set: function(value) {
					this._iframe && dom.attr.set(this._iframe, "scrolling", value ? "auto" : "no");
					return value;
				},
				value: true
			},

			url: {
				post: function(value) {
					var values = this.properties.__values__;
					values.data = void 0;
					values.html = void 0;
					this._createIFrame();
				}
			}
		},

		constants: {
			loading: false
		}

	});

});<commit_msg>dont log user name and password in WebView.setBasicAuthentication call<commit_after>define(["Ti/_/declare", "Ti/_/UI/Widget", "Ti/_/dom", "Ti/_/event", "Ti/_/lang", "Ti/_/text!Ti/_/UI/WebViewBridge.js", "Ti/App", "Ti/API", "Ti/UI"],
	function(declare, Widget, dom, event, lang, bridge, App, API, UI) {

	var on = require.on;

	return declare("Ti.UI.WebView", Widget, {

		constructor: function() {
			App.addEventListener(this.widgetId + ":unload", lang.hitch(this, function() {
				this._loading(1);
			}));
			this.backgroundColor = "#fff";
		},

		_preventDefaultTouchEvent: false,

		destroy: function() {
			App.removeEventListener(this.widgetId + ":unload");
			this._destroy();
			Widget.prototype.destroy.apply(this, arguments);
		},

		_destroy: function() {
			if (this._iframe) {
				event.off(this._iframeHandles);
				dom.destroy(this._iframe);
			}
		},

		_createIFrame: function() {
			if (this._parent) {
				this._destroy();
				this._loading(1);

				var url = this.url || "",
					match = url.match(/(https?)\:\/\/([^\:\/]*)(:?\d*)(.*)/),
					loc = window.location,
					isSameDomain = !match || (match[0] + ":" === loc.protocol && match[1] + match[2] === window.location.host),
					iframe = this._iframe = dom.create("iframe", {
						frameborder: 0,
						marginwidth: 0,
						marginheight: 0,
						hspace: 0,
						vspace: 0,
						scrolling: this.showScrollbars ? "auto" : "no",
						src: url || require.toUrl("Ti/_/UI/blank.html"),
						style: {
							width: "100%",
							height: "100%"
						}
					}, this.domNode);

				this._iframeHandles = [
					on(iframe, "load", this, function(evt) {
						var i = Math.max(isSameDomain | 0, 0),
							cw = iframe.contentWindow,
							prop,
							url,
							html;

						if (i !== -1) {
							// we can always guarantee that the first load we'll know if it's the same domain
							isSameDomain = -1;
						} else {
							// for every load after the first, we need to try which will throw security errors
							for (prop in cw) {
								i++;
								break;
							}
						}

						if (i > 0) {
							url = cw.location.href;
							this.evalJS(bridge.replace("WEBVIEW_ID", this.widgetId + ":unload"));
							(html = this.properties.__values__.html) && this._setContent(html);
						} else {
							API.warn("Unable to inject WebView bridge into cross-domain URL, ignore browser security message");
						}

						this._loading();
						this.fireEvent("load", {
							url: url ? (this.properties.__values__.url = url) : this.url
						});
					}),
					on(iframe, "error", this, function() {
						this._loading();
						this.fireEvent("error", {
							message: "Page failed to load",
							url: this.url
						});
					})
				];

				return 1;
			}
		},

		_setParent: function(view) {
			Widget.prototype._setParent.apply(this, arguments);

			// we are being added to a parent, need to manually fire
			(this.url || this.html) && this._createIFrame();
		},

		_getWindow: function() {
			return this._iframe.contentWindow;
		},

		_getDoc: function() {
			return this._getWindow().document;
		},

		_getHistory: function() {
			return this._getWindow().history;
		},

		_loading: function(v) {
			this.loading || v && this.fireEvent("beforeload", {
				url: this.url
			});
			this.constants.loading = !!v;
		},

		canGoBack: function() {
			return this.url && !!this._getHistory().length;
		},

		canGoForward: function() {
			return this.url && !!this._getHistory().length;
		},

		evalJS: function(js) {
			var w = this._getWindow(),
				r = null;
			try {
				r = js && w && w.eval && w.eval(js);
			} catch (e) {}
			return r;
		},

		goBack: function() {
			if (this.canGoBack()) {
				var h = this._getHistory();
				if (h) {
					this._loading(1);
					h.go(-1);
				}
			}
		},

		goForward: function() {
			if (this.canGoForward()) {
				var h = this._getHistory();
				if (h) {
					this._loading(1);
					h.go(1);
				}
			}
		},

		setBasicAuthentication: function(username, password) {
			var url = this.url,
				protocolIndex = url.indexOf('//');
			url = url.substring(0, protocolIndex + 2) + username + ":" + password + "@" + url.substring(protocolIndex + 2, url.length);
			this.url = url;
		},

		reload: function() {
			var w = this._getWindow();
			this.url && w ? (w.location.href = this.url) : this._createIFrame();
		},

		stopLoading: function(hardStop) {
			try {
				this.loading && hardStop ? this._destroy() : this._getWindow().stop();
			} catch (e) {}
			this._loading();
		},

		_defaultWidth: UI.FILL,

		_defaultHeight: UI.FILL,

		_getContentSize: function() {
			return {
				width: this._iframe ? this._iframe.clientWidth : 0,
				height: this._iframe ? this._iframe.clientHeight : 0
			};
		},

		_setContent: function(value) {
			try {
				var doc = this._getDoc();
				doc.open();
				doc.write(value);
				doc.close();
			} catch (e) {}
			return value;
		},

		properties: {
			data: {
				set: function(value) {
					var data = value;
					switch (data && data.declaredClass) {
						case "Ti.Filesystem.File":
							data = data.read();
						case "Ti.Blob":
							data = data.toString();
						default:
							this.html = data;
					}
					return value;
				}
			},

			html: {
				get: function(value) {
					var doc = this._iframe && this._getDoc();
					return value === void 0 && doc ? doc.documentElement.innerHTML : value;
				},
				post: function(value) {
					var values = this.properties.__values__;
					values.data = void 0;
					values.url = void 0;
					this._createIFrame() && this._setContent(value);
				}
			},

			showScrollbars: {
				set: function(value) {
					this._iframe && dom.attr.set(this._iframe, "scrolling", value ? "auto" : "no");
					return value;
				},
				value: true
			},

			url: {
				post: function(value) {
					var values = this.properties.__values__;
					values.data = void 0;
					values.html = void 0;
					this._createIFrame();
				}
			}
		},

		constants: {
			loading: false
		}

	});

});<|endoftext|>


<commit_before><commit_msg>Preparing for message tests.<commit_after><|endoftext|>


<commit_before>"use strict";

//Load dependencies
var moment = require('moment-timezone');
var params = process.require("core/utilities/params.js");

/**
 * Add the days criterion in criteria
 * @param query
 * @param criteria
 */
module.exports.add = function (query, criteria) {
    var paramArray = params.parseQueryParam(query.day, 4);

    if (paramArray.length > 0) {
        var days = [];

        paramArray.forEach(function (params) {

            var day = params[0];
            var start = parseInt(params[1], 10);
            var end = parseInt(params[2], 10);
            var timezone = params[3];
            var zone = moment.tz.zone(timezone);
            if (zone != null && !isNaN(start) && !isNaN(end)) {

                var tmpObj = {};
                tmpObj["ad.play_time." + day + ".play"] = true;
                if (start != 0 || end != 0) {
                    var offset = Math.round(zone.parse(Date.UTC()) / 60);
                    tmpObj["ad.play_time." + day + ".start.hourUTC"] = {"$lte": start + offset};
                    tmpObj["ad.play_time." + day + ".end.hourUTC"] = {"$gte": end + offset};
                }
                days.push(tmpObj);

            }
        });

        if (days.length > 0) {
            if (!criteria["$and"]) {
                criteria["$and"] = days;
            }
            else {
                criteria["$and"] = criteria["$and"].concat(days);
            }
        }
    }
};<commit_msg>Add change on dayCriterion for character when end hour is higher than start hour.<commit_after>"use strict";

//Load dependencies
var moment = require('moment-timezone');
var params = process.require("core/utilities/params.js");

/**
 * Add the days criterion in criteria
 * @param query
 * @param criteria
 */
module.exports.add = function (query, criteria) {
    var paramArray = params.parseQueryParam(query.day, 4);

    if (paramArray.length > 0) {
        var days = [];

        paramArray.forEach(function (params) {

            var day = params[0];
            var start = parseInt(params[1], 10);
            var end = parseInt(params[2], 10);
            var timezone = params[3];
            var zone = moment.tz.zone(timezone);
            if (zone != null && !isNaN(start) && !isNaN(end)) {

                var tmpObj = {};
                tmpObj["ad.play_time." + day + ".play"] = true;
                if (start != 0 || end != 0) {
                    var offset = Math.round(zone.parse(Date.UTC()) / 60);
                    if(end>start){
                        tmpObj["ad.play_time." + day + ".start.hourUTC"] = {"$gte": start + offset};
                        tmpObj["ad.play_time." + day + ".end.hourUTC"] = {"$lte": end + offset,$gte:start+offset};
                    }
                    else {
                        tmpObj["ad.play_time." + day + ".start.hourUTC"] = {"$gte": start + offset};
                        tmpObj["ad.play_time." + day + ".end.hourUTC"] = {"$lte": end + offset};
                    }
                }
                days.push(tmpObj);

            }
        });

        if (days.length > 0) {
            if (!criteria["$and"]) {
                criteria["$and"] = days;
            }
            else {
                criteria["$and"] = criteria["$and"].concat(days);
            }
        }
    }
};<|endoftext|>


<commit_before>'use strict';
require('../../init');
let Client = require('../../../lib/client');
let client;
var success = false;
let util = require('util');

describe('Get-status', function () {
    it('Should work', function (done) {
        client = Client();
        client.on('open', onOpen);
        client.on('error', onError(done));
        client.on('message', onMessage(done));
        client.on('close', onClose(done));
    });
});

let callStack = [];
function onOpen() {
    // let procedure = client.services.spaceCenter.clearTarget();
    // callStack.push(procedure.decode);
    // client.send(procedure.call);
    let procedure = client.services.spaceCenter.getActiveVessel();
    callStack.push(procedure.decode);
    client.send(procedure.call);
};

function onError(done) {
    return function (err) {
        done(err);
    };
}
function onClose(done) {
    return function (event) {
        if (success) {
            done();
        }
        return done(new Error(util.format("Socket closed before done", event)));
    };
}
var counter = 0;
var control = null;
var vessel = null;
function onMessage(done) {
    return function (response) {
        counter++;
        expect(response.error).to.not.be.ok();
        expect(response.results.length).to.equal(1);
        response.results.forEach(function (result) {
            expect(result.error).to.not.be.ok();
            let decodeType = callStack.pop();
            if (decodeType) {
                let decodedResult = Client.decode(result.value, decodeType);
                expect(decodedResult).to.be.ok();
                if (counter === 1) {
                    vessel = decodedResult;
                    let procedure = client.services.spaceCenter.vesselGetControl(result.value);
                    callStack.push(procedure.decode);
                    client.send(procedure.call);
                }
                else if (counter === 2) {
                    control = decodedResult;
                    let procedure = client.services.spaceCenter.controlSetAbort(control.id, true);
                    callStack.push(procedure.decode);
                    client.send(procedure.call);
                } else {
                    success = true;
                    return done();
                }
            }
        });
    };
}

<commit_msg>manually building message.<commit_after>'use strict';
require('../../init');
let Client = require('../../../lib/client');
let client;
var success = false;
let util = require('util');
var proto = require('../../../lib/utilities/proto');

describe('Get-status', function () {
    it('Should work', function (done) {
        client = Client();
        client.on('open', onOpen);
        client.on('error', onError(done));
        client.on('message', onMessage(done));
        client.on('close', onClose(done));
    });
});

let callStack = [];
function onOpen() {
    // let procedure = client.services.spaceCenter.clearTarget();
    // callStack.push(procedure.decode);
    // client.send(procedure.call);
    let procedure = client.services.spaceCenter.getActiveVessel();
    callStack.push(procedure.decode);
    client.send(procedure.call);
};

function onError(done) {
    return function (err) {
        done(err);
    };
}
function onClose(done) {
    return function (event) {
        if (success) {
            done();
        }
        return done(new Error(util.format("Socket closed before done", event)));
    };
}
var counter = 0;
var control = null;
var vessel = null;
function onMessage(done) {
    return function (response) {
        counter++;
        expect(response.error).to.not.be.ok();
        expect(response.results.length).to.equal(1);
        response.results.forEach(function (result) {
            expect(result.error).to.not.be.ok();
            let decodeType = callStack.pop();
            if (decodeType) {
                let decodedResult = Client.decode(result.value, decodeType);
                expect(decodedResult).to.be.ok();
                if (counter === 1) {
                    vessel = decodedResult;
                    let arg = new proto.krpc.schema.Argument(0, result.value);
                    let call = new proto.krpc.schema.ProcedureCall('SpaceCenter', 'Vessel_get_Control', arg);
                    //let procedure = client.services.spaceCenter.vesselGetControl(result.value);
                    //callStack.push(procedure.decode);
                    client.send(call);
                }
                else if (counter === 2) {
                    control = decodedResult;
                    let procedure = client.services.spaceCenter.controlSetAbort(control.id, true);
                    callStack.push(procedure.decode);
                    client.send(procedure.call);
                } else {
                    success = true;
                    return done();
                }
            }
        });
    };
}

<|endoftext|>


<commit_before>'use strict';

module.exports = {
  shouldSendErrorIfNotFound: true,
};
<commit_msg>changes shouldSEndErrorIfNotFound back to false<commit_after>'use strict';

module.exports = {
  shouldSendErrorIfNotFound: false,
};
<|endoftext|>


<commit_before>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

cur_frm.add_fetch('employee','employee_name','employee_name');

cur_frm.cscript.onload = function(doc, dt, dn) {
	if(!doc.posting_date)
		set_multiple(dt,dn,{posting_date:get_today()});
	if(doc.__islocal) {
		cur_frm.set_value("status", "Open");
		cur_frm.cscript.calculate_total_days(doc, dt, dn);
	}
	return cur_frm.call({
		method:"hr.utils.get_leave_approver_list",
		callback: function(r) {
			cur_frm.set_df_property("leave_approver", "options", $.map(r.message,
				function(profile) {
					return {value: profile, label: wn.user_info(profile).fullname};
				}));
			cur_frm.cscript.get_leave_balance(cur_frm.doc);
		}
	});
}

cur_frm.cscript.refresh = function(doc, dt, dn) {
	if(doc.__islocal) {
		cur_frm.set_value("status", "Open")
	}
	cur_frm.set_intro("");
	if(doc.__islocal && !in_list(user_roles, "HR User")) {
		cur_frm.set_intro("Fill the form and save it")
	} else {
		if(doc.docstatus==0 && doc.status=="Open") {
			if(user==doc.leave_approver) {
				cur_frm.set_intro("You are the Leave Approver for this record. Please Update the 'Status' and Save");
				cur_frm.toggle_enable("status", true);
			} else {
				cur_frm.set_intro("This Leave Application is pending approval. Only the Leave Apporver can update status.")
				cur_frm.toggle_enable("status", false);
				if(!doc.__islocal) {
					if(cur_frm.frm_head.appframe.buttons.Submit)
						cur_frm.frm_head.appframe.buttons.Submit.remove();
				}
			}
		} else {
 			if(doc.status=="Approved") {
				cur_frm.set_intro("Leave application has been approved.");
				if(cur_frm.doc.docstatus==0) {
					cur_frm.set_intro("Please submit to update Leave Balance.");
				}
			} else if(doc.status=="Rejected") {
				cur_frm.set_intro("Leave application has been rejected.");
			}
		}
	}
}

cur_frm.cscript.employee = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.fiscal_year = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.leave_type = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.half_day = function(doc, dt, dn) {
	if(doc.from_date) {
		set_multiple(dt,dn,{to_date:doc.from_date});
		cur_frm.cscript.calculate_total_days(doc, dt, dn);
	}
}

cur_frm.cscript.from_date = function(doc, dt, dn) {
	if(cint(doc.half_day) == 1){
		set_multiple(dt,dn,{to_date:doc.from_date});
	}
	cur_frm.cscript.calculate_total_days(doc, dt, dn);
}

cur_frm.cscript.to_date = function(doc, dt, dn) {
	if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
		msgprint("To Date should be same as From Date for Half Day leave");
		set_multiple(dt,dn,{to_date:doc.from_date});
	}
	cur_frm.cscript.calculate_total_days(doc, dt, dn);
}

cur_frm.cscript.get_leave_balance = function(doc, dt, dn) {
	if(doc.docstatus==0 && doc.employee && doc.leave_type && doc.fiscal_year) {
		return cur_frm.call({
			method: "get_leave_balance",
			args: {
				employee: doc.employee,
				fiscal_year: doc.fiscal_year,
				leave_type: doc.leave_type
			}
		});
	}
}

cur_frm.cscript.calculate_total_days = function(doc, dt, dn) {
	if(doc.from_date && doc.to_date){
		if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
		else{
			// server call is done to include holidays in leave days calculations
			return get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
		}
	}
}

cur_frm.fields_dict.employee.get_query = function() {
	return {
		query: "hr.doctype.leave_application.leave_application.query_for_permitted_employees"
	};
}<commit_msg>[fix] [minor] retain leave approver after setting options<commit_after>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

cur_frm.add_fetch('employee','employee_name','employee_name');

cur_frm.cscript.onload = function(doc, dt, dn) {
	if(!doc.posting_date)
		set_multiple(dt,dn,{posting_date:get_today()});
	if(doc.__islocal) {
		cur_frm.set_value("status", "Open");
		cur_frm.cscript.calculate_total_days(doc, dt, dn);
	}

	var leave_approver = doc.leave_approver;
	return cur_frm.call({
		method:"hr.utils.get_leave_approver_list",
		callback: function(r) {
			cur_frm.set_df_property("leave_approver", "options", $.map(r.message,
				function(profile) {
					return {value: profile, label: wn.user_info(profile).fullname};
				}));
			if(leave_approver) cur_frm.set_value("leave_approver", leave_approver);
			cur_frm.cscript.get_leave_balance(cur_frm.doc);
		}
	});
}

cur_frm.cscript.refresh = function(doc, dt, dn) {
	if(doc.__islocal) {
		cur_frm.set_value("status", "Open")
	}
	cur_frm.set_intro("");
	if(doc.__islocal && !in_list(user_roles, "HR User")) {
		cur_frm.set_intro("Fill the form and save it")
	} else {
		if(doc.docstatus==0 && doc.status=="Open") {
			if(user==doc.leave_approver) {
				cur_frm.set_intro("You are the Leave Approver for this record. Please Update the 'Status' and Save");
				cur_frm.toggle_enable("status", true);
			} else {
				cur_frm.set_intro("This Leave Application is pending approval. Only the Leave Apporver can update status.")
				cur_frm.toggle_enable("status", false);
				if(!doc.__islocal) {
					if(cur_frm.frm_head.appframe.buttons.Submit)
						cur_frm.frm_head.appframe.buttons.Submit.remove();
				}
			}
		} else {
 			if(doc.status=="Approved") {
				cur_frm.set_intro("Leave application has been approved.");
				if(cur_frm.doc.docstatus==0) {
					cur_frm.set_intro("Please submit to update Leave Balance.");
				}
			} else if(doc.status=="Rejected") {
				cur_frm.set_intro("Leave application has been rejected.");
			}
		}
	}
}

cur_frm.cscript.employee = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.fiscal_year = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.leave_type = function (doc, dt, dn){
	cur_frm.cscript.get_leave_balance(doc, dt, dn);
}

cur_frm.cscript.half_day = function(doc, dt, dn) {
	if(doc.from_date) {
		set_multiple(dt,dn,{to_date:doc.from_date});
		cur_frm.cscript.calculate_total_days(doc, dt, dn);
	}
}

cur_frm.cscript.from_date = function(doc, dt, dn) {
	if(cint(doc.half_day) == 1){
		set_multiple(dt,dn,{to_date:doc.from_date});
	}
	cur_frm.cscript.calculate_total_days(doc, dt, dn);
}

cur_frm.cscript.to_date = function(doc, dt, dn) {
	if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
		msgprint("To Date should be same as From Date for Half Day leave");
		set_multiple(dt,dn,{to_date:doc.from_date});
	}
	cur_frm.cscript.calculate_total_days(doc, dt, dn);
}

cur_frm.cscript.get_leave_balance = function(doc, dt, dn) {
	if(doc.docstatus==0 && doc.employee && doc.leave_type && doc.fiscal_year) {
		return cur_frm.call({
			method: "get_leave_balance",
			args: {
				employee: doc.employee,
				fiscal_year: doc.fiscal_year,
				leave_type: doc.leave_type
			}
		});
	}
}

cur_frm.cscript.calculate_total_days = function(doc, dt, dn) {
	if(doc.from_date && doc.to_date){
		if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
		else{
			// server call is done to include holidays in leave days calculations
			return get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
		}
	}
}

cur_frm.fields_dict.employee.get_query = function() {
	return {
		query: "hr.doctype.leave_application.leave_application.query_for_permitted_employees"
	};
}<|endoftext|>


<commit_before>var request = require("request");
var passport = require('passport')
var githubStrategy = require('passport-github').Strategy;

var GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID;
var GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET;
var CONTEXT_URI = process.env.CONTEXT_URI;
var mongoDbConnection = require('./lib/connection.js');

module.exports = function(app) {

    var setSession = function(req, user) {
        req.session.username = user.username;
        req.session.encodedUsername = user.encodedUsername;
        req.session.githubUsername = user.githubUser.username;
        req.session.avatarUrl = user.githubUser._json.avatar_url;
    };

    var handleGithubCallback = function(req, res) {
        var githubUser = req.user.profile;
        req.session.githubAccessToken = req.user.accessToken;

        var isNewUser = function(user) {
            return !user;
        };
        var isUserRegisteredWithOneself = function(user) {
            return user && user.username;
        };
        var redirect = function(user, url) {
            res.redirect(CONTEXT_URI + url + "?username=" + user.username);
        };
        var insertGithubProfileInDb = function() {
            var options = {
                url: "https://api.github.com/user/emails?access_token=" + req.user.accessToken,
                headers: {
                    "User-Agent": "Quantified Dev Localhost"
                },
            };
            request(options, function(err, res, body) {
                if (!err) {
                    var userEmails = JSON.parse(body);
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    var githubUserRecord = {
                        githubUser: githubUser
                    }
                    mongoDbConnection(function(qdDb) {
                        qdDb.collection('users').insert(githubUserRecord, function(err, insertedRecords) {
                            if (err) {
                                res.status(500).send("Database error");
                            } else {
                                req.session.githubUsername = githubUser.username;
                                req.session.avatarUrl = githubUser._json.avatar_url;
                                redirect(githubUser, "/claimUsername");
                            }
                        });
                    });
                } else {
                    res.status(500).send("Could not fetch email addresses for user.");
                }
            });
        };

        var byGitHubUsername = {
            "githubUser.username": githubUser.username
        };
        mongoDbConnection(function(qdDb) {
            qdDb.collection('users').findOne(byGitHubUsername, function(err, user) {
                if (isNewUser(user)) {
                    insertGithubProfileInDb();
                } else if (isUserRegisteredWithOneself(user)) {
                    setSession(req, user);
                    if (req.session.redirectUrl) {
                        var redirectUrl = req.session.redirectUrl;
                        delete req.session.redirectUrl;
                        res.redirect(redirectUrl);
                    } else {
                        redirect(user, "/dashboard");
                    }
                } else {
                    req.session.githubUsername = user.githubUser.username;
                    req.session.avatarUrl = user.githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }
            })
        });
    };

    passport.serializeUser(function(user, done) {
        done(null, user);
    });

    passport.deserializeUser(function(obj, done) {
        done(null, obj);
    });

    passport.use(new githubStrategy({
        clientID: GITHUB_CLIENT_ID,
        clientSecret: GITHUB_CLIENT_SECRET,
        callbackURL: CONTEXT_URI + "/auth/github/callback"
    },
                                    function(accessToken, refreshToken, profile, done) {
                                        var githubProfile = {
                                            profile: profile,
                                            accessToken: accessToken
                                        };
                                        return done(null, githubProfile);
                                    }
                                   ));
    app.use(passport.initialize());
    app.use(passport.session());

    app.get('/auth/github', passport.authenticate('github', {
        scope: 'user:email'
    }));

    app.get('/auth/github/callback', passport.authenticate('github', {
        failureRedirect: CONTEXT_URI +'/signup'
    }), handleGithubCallback);
};
<commit_msg>added registeredOn date for users.<commit_after>var request = require("request");
var passport = require('passport')
var githubStrategy = require('passport-github').Strategy;

var GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID;
var GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET;
var CONTEXT_URI = process.env.CONTEXT_URI;
var mongoDbConnection = require('./lib/connection.js');

module.exports = function(app) {

    var setSession = function(req, user) {
        req.session.username = user.username;
        req.session.encodedUsername = user.encodedUsername;
        req.session.githubUsername = user.githubUser.username;
        req.session.avatarUrl = user.githubUser._json.avatar_url;
    };

    var handleGithubCallback = function(req, res) {
        var githubUser = req.user.profile;
        req.session.githubAccessToken = req.user.accessToken;

        var isNewUser = function(user) {
            return !user;
        };
        var isUserRegisteredWithOneself = function(user) {
            return user && user.username;
        };
        var redirect = function(user, url) {
            res.redirect(CONTEXT_URI + url + "?username=" + user.username);
        };
        var insertGithubProfileInDb = function() {
            var options = {
                url: "https://api.github.com/user/emails?access_token=" + req.user.accessToken,
                headers: {
                    "User-Agent": "Quantified Dev Localhost"
                },
            };
            request(options, function(err, res, body) {
                if (!err) {
                    var userEmails = JSON.parse(body);
                    for (var i in userEmails) {
                        githubUser.emails.push(userEmails[i]);
                    }
                    var githubUserRecord = {
                        githubUser: githubUser,
                        registeredOn: new Date()
                    }
                    mongoDbConnection(function(qdDb) {
                        qdDb.collection('users').insert(githubUserRecord, function(err, insertedRecords) {
                            if (err) {
                                res.status(500).send("Database error");
                            } else {
                                req.session.githubUsername = githubUser.username;
                                req.session.avatarUrl = githubUser._json.avatar_url;
                                redirect(githubUser, "/claimUsername");
                            }
                        });
                    });
                } else {
                    res.status(500).send("Could not fetch email addresses for user.");
                }
            });
        };

        var byGitHubUsername = {
            "githubUser.username": githubUser.username
        };
        mongoDbConnection(function(qdDb) {
            qdDb.collection('users').findOne(byGitHubUsername, function(err, user) {
                if (isNewUser(user)) {
                    insertGithubProfileInDb();
                } else if (isUserRegisteredWithOneself(user)) {
                    setSession(req, user);
                    if (req.session.redirectUrl) {
                        var redirectUrl = req.session.redirectUrl;
                        delete req.session.redirectUrl;
                        res.redirect(redirectUrl);
                    } else {
                        redirect(user, "/dashboard");
                    }
                } else {
                    req.session.githubUsername = user.githubUser.username;
                    req.session.avatarUrl = user.githubUser._json.avatar_url;
                    redirect(githubUser, "/claimUsername");
                }
            })
        });
    };

    passport.serializeUser(function(user, done) {
        done(null, user);
    });

    passport.deserializeUser(function(obj, done) {
        done(null, obj);
    });

    passport.use(new githubStrategy({
        clientID: GITHUB_CLIENT_ID,
        clientSecret: GITHUB_CLIENT_SECRET,
        callbackURL: CONTEXT_URI + "/auth/github/callback"
    },
                                    function(accessToken, refreshToken, profile, done) {
                                        var githubProfile = {
                                            profile: profile,
                                            accessToken: accessToken
                                        };
                                        return done(null, githubProfile);
                                    }
                                   ));
    app.use(passport.initialize());
    app.use(passport.session());

    app.get('/auth/github', passport.authenticate('github', {
        scope: 'user:email'
    }));

    app.get('/auth/github/callback', passport.authenticate('github', {
        failureRedirect: CONTEXT_URI +'/signup'
    }), handleGithubCallback);
};
<|endoftext|>


<commit_before>var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

var env = process.env.NODE_ENV === 'testing'
  ? require('../config/test.env')
  : config.build.env

var webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin(),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: process.env.NODE_ENV === 'testing'
        ? 'index.html'
        : config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency'
    }),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    // sw-precache service worker
    new SWPrecacheWebpackPlugin({
      cacheId: 'dingke-blog',
      filename: 'service_worker.js',
      minify: true,
      runtimeCaching: [
        {
          urlPattern: '/',
          handler: 'cacheFirst'
        },
        {
          urlPattern: '/',
          handler: 'cacheFirst'
        }
      ]
    })
  ]
})

if (config.build.productionGzip) {
  var CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
<commit_msg>use cacheFirst strategy when caching / and /articles<commit_after>var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

var env = process.env.NODE_ENV === 'testing'
  ? require('../config/test.env')
  : config.build.env

var webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  devtool: config.build.productionSourceMap ? '#source-map' : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin(),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: process.env.NODE_ENV === 'testing'
        ? 'index.html'
        : config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency'
    }),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    // sw-precache service worker
    new SWPrecacheWebpackPlugin({
      cacheId: 'dingke-blog',
      filename: 'service_worker.js',
      minify: true,
      runtimeCaching: [
        {
          urlPattern: '/',
          handler: 'cacheFirst'
        },
        {
          urlPattern: '/articles',
          handler: 'cacheFirst'
        }
      ]
    })
  ]
})

if (config.build.productionGzip) {
  var CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
<|endoftext|>


<commit_before>var should = require('should');
var request = require('supertest');
request = request('http://localhost:3000')

describe('cart.js', function () {
  describe('Invalid  Body', function (){
    it('should give a 400 with a missing key', function(done){
      request.post('/cart').
      send({"iteList":"jdhfsjbwkrsns,testing123"}).expect(400 ,done)
    });
    it('should give a 400 with no body', function(done){
      request.post('/cart').expect(400,done)
    });
    it('should give a 200 with a right request body', function(done){
      request.post('/cart').send({"itemList":"A12T-4GH7-QPL9-3N4M"}).expect(200,done)
    });
    it('should give a 200 with a lowercase product code', function(done){
        request.post('/cart').send({"itemList":"a12t-4gh7-QPL9-3N4M"}).expect(200,done)
    });
    it('should give a calculates a correct total with one product', function(done){
        request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2"}).expect('{"total":"6.41"}').expect(200,done)
      });
      it('should give a calculates a correct total with two products', function(done){
          request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2;a12t-4gh7-QPL9-3N4M"}).expect('{"total":"10.17"}').expect(200,done)
        });
  });
});
<commit_msg>adding more tests<commit_after>var should = require('should');
var request = require('supertest');
request = request('http://localhost:3000')

describe('cart.js', function () {
  describe('Invalid  Body', function (){
    it('should give a 400 with a missing key', function(done){
      request.post('/cart').
      send({"iteList":"jdhfsjbwkrsns,testing123"}).expect(400 ,done)
    });
    it('should give a 400 with no body', function(done){
      request.post('/cart').expect(400,done)
    });
    it('should give a 200 with a right request body', function(done){
      request.post('/cart').send({"itemList":"A12T-4GH7-QPL9-3N4M"}).expect(200,done)
    });
    it('should give a 200 with a lowercase product code', function(done){
        request.post('/cart').send({"itemList":"a12t-4gh7-QPL9-3N4M"}).expect(200,done)
    });
    it('should give a calculates a correct total with one product', function(done){
        request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2"}).expect('{"total":"6.41"}').expect(200,done)
      });
    it('should give a calculates a correct total with two products', function(done){
        request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2;a12t-4gh7-QPL9-3N4M"}).expect('{"total":"10.17"}').expect(200,done)
      });
    it('should give a 400 error with one faulty product out of two', function(done){
        request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2;jfasnnadfaj"}).expect(400,done)
    });
    it('should give a 400 error with one faulty product', function(done){
        request.post('/cart').send({"itemList":"jfasnnadfaj"}).expect(400,done)
    });
    it('should give a bad product code  with one faulty product out of two', function(done){
        request.post('/cart').send({"itemList":"65p1-udgm-XH2M-LQW2;jfasnnadfaj"}).expect('{"Reason":"Bad product Code"}').expect(400,done)
    });
    it('should give me a correct total  with a one uppercase and one lowercase code', function(done){
      request.post('/cart').send({"itemList":"A12T-4GH7-QPL9-3N4M;65p1-udgm-xh2m-lqw2"}).expect('{"total":"10.17"}').expect(200,done)
    });
  });
});
<|endoftext|>