<commit_before>$(document).ready(function(){
  // todos for this file
  // make it OO
  drawChartAjaxCall();
});

function draw(response) {
      // Chart size
  var w = window.innerWidth,
      h = 450,
      // Date variables
      days = [ 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday' ],
      monthNames = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
      abbreviatedMonthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ],
      // d3 variables
      maxDataPointsForDots = 500,
      transitionDuration = 1000,
      svg = null,
      yAxisGroup = null,
      xAxisGroup = null,
      dataCirclesGroup = null,
      dataLinesGroup = null;

  if(/live_update/.test(document.URL)){
    transitionDuration = 0;
  }

  var data = response,
  violations = 0;
  // add usefull properties to the data objects
  data.forEach(function(obj){
    obj.date = new Date(obj.created_at);
    obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 22;
    if(/live_update/.test(document.URL)){
      obj.violation = true;
    }
    if(obj.violation){ violations += 1; }
  });
  var margin = 40;
  var max = d3.max(data, function(d) { return Math.max( d.temp, d.outdoor_temp ) }) + 1;
  // checks whether or not there is an outdoor temp
  if ( d3.min(data, function(d) { return d.outdoor_temp }) ){
    var min = d3.min(data, function(d) { return Math.min( d.temp ) }) - 5;
  } else {
    var min = d3.min(data, function(d) { return Math.min( d.temp, d.outdoor_temp ) }) - 10;
  }
  var pointRadius = 4;
  var x = d3.time.scale().range([0, w - margin * 2]).domain([data[0].date, data[data.length - 1].date]);
  var y = d3.scale.linear().range([h - margin * 2, 0]).domain([min, max]);
  var xAxis = d3.svg.axis().scale(x).tickSize(h - margin * 2).tickPadding(0).ticks(data.length);
  var yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + margin * 2).tickPadding(0).ticks(5);
  var t = null,
  strokeWidth = w / data.length;

  svg = d3.select('#d3-chart').select('svg').select('g');
  if (svg.empty()) {
    svg = d3.select('#d3-chart')
      .append('svg:svg')
      .attr('width', w)
      .attr('height', h)
      .attr('class', 'viz')
      .append('svg:g')
      .attr('transform', 'translate(' + margin + ',' + margin + ')');
  }

  t = svg.transition().duration(transitionDuration);

  function addLineStlyingToXTicks(){
    var $lines = $(".xTick .tick line"),
        length = data.length,
        date,
        newText,
        $textEl;

    for(var i = 0; i < length; i++){
      if(data[i].isDay === false){
        $($lines[i]).attr(
          { 'stroke-width': strokeWidth, 'stroke': '#90ABB0' }
        );
        if(i === 0){
          $($lines[i]).attr({ 'stroke-width': strokeWidth * 1.9 });
        }
      }
      else {
        // add dates to bottom of graph
        if ( data[i].date.getHours() === 16 ) {
          date = data[i].date;
          newText = abbreviatedMonthNames[date.getMonth()] + " "
            + date.getDate() + ", " + (date.getYear() + 1900);
          $textEl = $($(".xTick .tick text")[i]);
          $textEl.text(newText);
          $textEl.show();
          $textEl.attr({"x": -15, "y": 380});
        }
      }
    }
  }

// x ticks and labels gets placed first
  // x ticks and labels
  if (!xAxisGroup) {
    xAxisGroup = svg.append('svg:g')
      .attr('class', 'xTick')
      .call(xAxis);
    addLineStlyingToXTicks();
  }
  else {
    t.select('.xTick').call(xAxis);
  }

// y ticks and labels gets placed second
  // y ticks and labels
  if (!yAxisGroup) {
    yAxisGroup = svg.append('svg:g')
      .attr('class', 'yTick')
      .call(yAxis);
  }
  else {
    t.select('.yTick').call(yAxis);
  }
  // fixes x value for text
  $(".yTick .tick text").attr("x", "-5")

// y ticks and labels gets placed third
  // Draw the lines
  if (!dataLinesGroup) {
    dataLinesGroup = svg.append('svg:g');
  }

  var dataLines = dataLinesGroup.selectAll('.data-line').data([data]);

  var line = d3.svg.line()
    // assign the X function to plot our line as we wish
    .x(function(d,i) {
      // verbose logging to show what's actually being done
      //console.log('Plotting X temp for date: ' + d.date + ' using index: ' + i + ' to be at: ' + x(d.date) + ' using our xScale.');
      // return the X coordinate where we want to plot this datapoint
      //return x(i);
      return x(d.date);
    })
    .y(function(d) {
      // verbose logging to show what's actually being done
      //console.log('Plotting Y temp for data temp: ' + d.temp + ' to be at: ' + y(d.temp) + " using our yScale.");
      // return the Y coordinate where we want to plot this datapoint
      //return y(d);
      return y(d.temp);
    })
    .interpolate("linear");

  var garea = d3.svg.area()
    .interpolate("linear")
    .x(function(d) {
      // verbose logging to show what's actually being done
      return x(d.date);
    })
    .y0(h - margin * 2)
    .y1(function(d) {
      // verbose logging to show what's actually being done
      return y(d.outdoor_temp);
    });

  dataLines
    .enter()
    .append('svg:path')
    .attr("class", "area");
    // .attr("d", garea(data));

  dataLines.enter().append('path')
    .attr('class', 'data-line')
    .style('opacity', 0.3)
    .attr("d", line(data))
    .transition()
    .delay(transitionDuration / 2)
    .duration(transitionDuration)
    .style('opacity', 1);
    // .attr('x1', function(d, i) { return (i > 0) ? xScale(data[i - 1].date) : xScale(d.date); })
    // .attr('y1', function(d, i) { return (i > 0) ? yScale(data[i - 1].temp) : yScale(d.temp); })
    // .attr('x2', function(d) { return xScale(d.date); })
    // .attr('y2', function(d) { return yScale(d.temp); });

  // dataLines.transition()
  //   .attr("d", line)
  //   .duration(transitionDuration)
  //   .style('opacity', 1)
  //   .attr("transform", function(d) {
  //     return "translate(" + x(d.date) + "," + y(d.temp) + ")";
  //   });

  dataLines.exit()
    .transition()
    .attr("d", line)
    .duration(transitionDuration)
    .attr("transform", function(d) {
     return "translate(" + x(d.date) + "," + y(0) + ")";
    })
    .style('opacity', 1e-6)
    .remove();

  d3.selectAll(".area").transition()
    .duration(transitionDuration)
    .attr("d", garea(data));

  // move the area to the back of the graph
  var fillArea = $(".area")
  $("#d3-chart svg > g").prepend(fillArea)

  // add number of violations to the legend
  $("#violations span").text($("#violations span")
    .text().replace(/\d+/, violations));

  if (violations) {
  // Draw the circles if there are any violations
    if (!dataCirclesGroup) {
      dataCirclesGroup = svg.append('svg:g');
    }

    var circles = dataCirclesGroup.selectAll('.data-point').data(data);

    circles.enter()
      .append('svg:circle')
      .attr('class', 'data-point')
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function() { return y(0) })
      .attr('r', function(d) {
        return d.violation ? pointRadius : 0;
      })
      .transition()
      .duration(transitionDuration)
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function(d) { return y(d.temp) });

    // circles
    //   .transition()
    //   .duration(transitionDuration)
    //   .attr('cx', function(d) { return x(d.date) })
    //   .attr('cy', function(d) { return y(d.temp) })
    //   .attr('r', function(d) {
    //     return d.violation ? pointRadius : null
    //   })
    //   .style('opacity', 1);

    circles
      .exit()
      .transition()
      .duration(transitionDuration)
      // Leave the cx transition off. Allowing the points to fall where they lie is best.
      //.attr('cx', function(d, i) { return xScale(i) })
      .attr('cy', function() { return y(0) })
      .style("opacity", 1e-6)
      .remove();
  }

  function legalMinimumFor(reading){
    if(reading.isDay === true){
      return '68';
    }else{
      return '55';
    }
  }

  function getCivilianTime(reading){
    if (reading.getHours() > 12){
      return (reading.getHours() - 12) + ":"
        + (reading.getMinutes() >= 10 ?
          reading.getMinutes() : "0" + reading.getMinutes())
        + " PM";
    }else{
      return reading.getHours() + ":"
        + (reading.getMinutes() >= 10 ?
          reading.getMinutes() : "0" + reading.getMinutes())
        + " AM";
    }
  }

  // only add tooltips if it is not a live demo
  if(!/live_update/.test(document.URL)){
    $('svg circle').tipsy({
      gravity: 's',
      html: true,
      topOffset: 2.8,
      leftOffset: 0.3,
      opacity: 1,
      title: function() {
        var d = this.__data__;
        var pDate = d.date;
        return pDate.getDate() + ' '
          + monthNames[pDate.getMonth()] + ' '
          + pDate.getFullYear() + '
'
          + days[ pDate.getDay() ] + ' at '
          + getCivilianTime(pDate) + '
'
          + 'Temperature in Violation
'
          + '
Temperature in Apt: ' + d.temp + '°'
          + '
Temperature Outside: ' + d.outdoor_temp + '°'
          + '
Legal minimum: ' + legalMinimumFor(d) + '°';
      }
    });
  }
}

function drawChartBasedOnScreenSize(chartData){
  if ( $('#live-update') !== undefined ) {
    $('.temp-num').html(chartData[chartData.length - 1].temp + '°')
  }

  if (window.innerWidth < 450) {
    var quarterReadings = chartData.slice(119, 167);
    $("#d3-chart").html("")
    draw(quarterReadings);
  }else if(window.innerWidth < 720){
    var halfReadings = chartData.slice(71, 167);
    $("#d3-chart").html("")
    draw(halfReadings);
  }else if(window.innerWidth < 1080){
    var threeQuarterReadings = chartData.slice(23, 167);
    $("#d3-chart").html("")
    draw(threeQuarterReadings);
  }else{
    $("#d3-chart").html("")
    draw(chartData);
  }
}

function drawChartAjaxCall(){
  if($("#d3-chart").length > 0){
    if(/collaborations/.test(document.URL)){
      var URL = /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
      // returns /user/11/collaborations/35
    } else if ( /live_update/.test(document.URL) ){
      var URL = /\/users\/\d+\/live_update/.exec(document.URL)[0];
      //returns /user/13/live_update
    } else {
      var URL = /\/users\/\d+/.exec(document.URL)[0];
    }
    $.ajax({
      url: URL,
      dataType: "JSON",
      success: function(response){
        if( response.length > 0 ){
          drawChartBasedOnScreenSize(response);
          var resizeTimer = 0;
          window.onresize = function(){
            if (resizeTimer){
              clearTimeout(resizeTimer);
            }
            resizeTimer = setTimeout(function(){
              drawChartBasedOnScreenSize(response);
            }, 50);
          };
        }
      },
      error: function(response){
        console.log("error");
        console.log(response);
      }
    });
  }
}<commit_msg>converts half of d3 charts into using named functions<commit_after>$(document).ready(function(){
  // todos for this file
  // make it OO
  drawChartAjaxCall();
});

function draw(response) {
      // Chart size
  var w = window.innerWidth,
      h = 450,
      // Date variables
      days = [ 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday' ],
      monthNames = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ],
      abbreviatedMonthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ],
      // d3 variables
      maxDataPointsForDots = 500,
      transitionDuration = 1000,
      svg = null,
      yAxisGroup = null,
      xAxisGroup = null,
      dataCirclesGroup = null,
      dataLinesGroup = null;

  if(/live_update/.test(document.URL)){
    transitionDuration = 0;
  }

  var data = response,
  violations = 0;
  // add usefull properties to the data objects
  data.forEach(function(obj){
    obj.date = new Date(obj.created_at);
    obj.isDay = obj.date.getHours() >= 6 && obj.date.getHours() <= 22;
    if(/live_update/.test(document.URL)){
      obj.violation = true;
    }
    if(obj.violation){ violations += 1; }
  });
  var margin = 40;
  var max = d3.max(data, function(d) { return Math.max( d.temp, d.outdoor_temp ) }) + 1;
  // checks whether or not there is an outdoor temp
  if ( d3.min(data, function(d) { return d.outdoor_temp }) ){
    var min = d3.min(data, function(d) { return Math.min( d.temp ) }) - 5;
  } else {
    var min = d3.min(data, function(d) { return Math.min( d.temp, d.outdoor_temp ) }) - 10;
  }
  var pointRadius = 4;
  var x = d3.time.scale().range([0, w - margin * 2]).domain([data[0].date, data[data.length - 1].date]);
  var y = d3.scale.linear().range([h - margin * 2, 0]).domain([min, max]);
  var xAxis = d3.svg.axis().scale(x).tickSize(h - margin * 2).tickPadding(0).ticks(data.length);
  var yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + margin * 2).tickPadding(0).ticks(5);
  var t = null,
  strokeWidth = w / data.length;

  var svg = d3.select('#d3-chart').select('svg').select('g');
  function createSvg(){
    if (svg.empty()) {
      svg = d3.select('#d3-chart')
        .append('svg:svg')
        .attr('width', w)
        .attr('height', h)
        .attr('class', 'viz')
        .append('svg:g')
        .attr('transform', 'translate(' + margin + ',' + margin + ')');
    }
  }

  createSvg();

  function setT(){
    t = svg.transition().duration(transitionDuration);
  }

  setT()

  function addLineStlyingToXTicks(){
    var $lines = $(".xTick .tick line"),
        length = data.length,
        date,
        newText,
        $textEl;

    for(var i = 0; i < length; i++){
      if(data[i].isDay === false){
        $($lines[i]).attr(
          { 'stroke-width': strokeWidth, 'stroke': '#90ABB0' }
        );
        if(i === 0){
          $($lines[i]).attr({ 'stroke-width': strokeWidth * 1.9 });
        }
      }
      else {
        // add dates to bottom of graph
        if ( data[i].date.getHours() === 16 ) {
          date = data[i].date;
          newText = abbreviatedMonthNames[date.getMonth()] + " "
            + date.getDate() + ", " + (date.getYear() + 1900);
          $textEl = $($(".xTick .tick text")[i]);
          $textEl.text(newText);
          $textEl.show();
          $textEl.attr({"x": -15, "y": 380});
        }
      }
    }
  }

// x ticks and labels gets placed first
  // x ticks and labels
  function setXAxisGroup(){
    if (!xAxisGroup) {
      xAxisGroup = svg.append('svg:g')
        .attr('class', 'xTick')
        .call(xAxis);
    }
    else {
      t.select('.xTick').call(xAxis);
    }
  }

  setXAxisGroup()
  addLineStlyingToXTicks();

// y ticks and labels gets placed second
  // y ticks and labels
  function setYAxisGroup() {
    if (!yAxisGroup) {
      yAxisGroup = svg.append('svg:g')
        .attr('class', 'yTick')
        .call(yAxis);
      // fixes x value for text
      $(".yTick .tick text").attr("x", "-5")
    }
    else {
      t.select('.yTick').call(yAxis);
    }
  }

  setYAxisGroup()

// y ticks and labels gets placed third
  // Draw the lines
  function setDataLinesGroup(){
    if (!dataLinesGroup) {
      dataLinesGroup = svg.append('svg:g');
    }
  }
  setDataLinesGroup()

  var dataLines = dataLinesGroup.selectAll('.data-line').data([data]);

  var line = d3.svg.line()
    // assign the X function to plot our line as we wish
    .x(function(d,i) {
      // verbose logging to show what's actually being done
      //console.log('Plotting X temp for date: ' + d.date + ' using index: ' + i + ' to be at: ' + x(d.date) + ' using our xScale.');
      // return the X coordinate where we want to plot this datapoint
      //return x(i);
      return x(d.date);
    })
    .y(function(d) {
      // verbose logging to show what's actually being done
      //console.log('Plotting Y temp for data temp: ' + d.temp + ' to be at: ' + y(d.temp) + " using our yScale.");
      // return the Y coordinate where we want to plot this datapoint
      //return y(d);
      return y(d.temp);
    })
    .interpolate("linear");

  var garea = d3.svg.area()
    .interpolate("linear")
    .x(function(d) {
      // verbose logging to show what's actually being done
      return x(d.date);
    })
    .y0(h - margin * 2)
    .y1(function(d) {
      // verbose logging to show what's actually being done
      return y(d.outdoor_temp);
    });

  dataLines
    .enter()
    .append('svg:path')
    .attr("class", "area");
    // .attr("d", garea(data));

  dataLines.enter().append('path')
    .attr('class', 'data-line')
    .style('opacity', 0.3)
    .attr("d", line(data))
    .transition()
    .delay(transitionDuration / 2)
    .duration(transitionDuration)
    .style('opacity', 1);
    // .attr('x1', function(d, i) { return (i > 0) ? xScale(data[i - 1].date) : xScale(d.date); })
    // .attr('y1', function(d, i) { return (i > 0) ? yScale(data[i - 1].temp) : yScale(d.temp); })
    // .attr('x2', function(d) { return xScale(d.date); })
    // .attr('y2', function(d) { return yScale(d.temp); });

  // dataLines.transition()
  //   .attr("d", line)
  //   .duration(transitionDuration)
  //   .style('opacity', 1)
  //   .attr("transform", function(d) {
  //     return "translate(" + x(d.date) + "," + y(d.temp) + ")";
  //   });

  dataLines.exit()
    .transition()
    .attr("d", line)
    .duration(transitionDuration)
    .attr("transform", function(d) {
     return "translate(" + x(d.date) + "," + y(0) + ")";
    })
    .style('opacity', 1e-6)
    .remove();

  d3.selectAll(".area").transition()
    .duration(transitionDuration)
    .attr("d", garea(data));

  // move the area to the back of the graph
  var fillArea = $(".area")
  $("#d3-chart svg > g").prepend(fillArea)

  // add number of violations to the legend
  $("#violations span").text($("#violations span")
    .text().replace(/\d+/, violations));

  if (violations) {
  // Draw the circles if there are any violations
    if (!dataCirclesGroup) {
      dataCirclesGroup = svg.append('svg:g');
    }

    var circles = dataCirclesGroup.selectAll('.data-point').data(data);

    circles.enter()
      .append('svg:circle')
      .attr('class', 'data-point')
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function() { return y(0) })
      .attr('r', function(d) {
        return d.violation ? pointRadius : 0;
      })
      .transition()
      .duration(transitionDuration)
      .style('opacity', 1)
      .attr('cx', function(d) { return x(d.date) })
      .attr('cy', function(d) { return y(d.temp) });

    // circles
    //   .transition()
    //   .duration(transitionDuration)
    //   .attr('cx', function(d) { return x(d.date) })
    //   .attr('cy', function(d) { return y(d.temp) })
    //   .attr('r', function(d) {
    //     return d.violation ? pointRadius : null
    //   })
    //   .style('opacity', 1);

    circles
      .exit()
      .transition()
      .duration(transitionDuration)
      // Leave the cx transition off. Allowing the points to fall where they lie is best.
      //.attr('cx', function(d, i) { return xScale(i) })
      .attr('cy', function() { return y(0) })
      .style("opacity", 1e-6)
      .remove();
  }

  function legalMinimumFor(reading){
    if(reading.isDay === true){
      return '68';
    }else{
      return '55';
    }
  }

  function getCivilianTime(reading){
    if (reading.getHours() > 12){
      return (reading.getHours() - 12) + ":"
        + (reading.getMinutes() >= 10 ?
          reading.getMinutes() : "0" + reading.getMinutes())
        + " PM";
    }else{
      return reading.getHours() + ":"
        + (reading.getMinutes() >= 10 ?
          reading.getMinutes() : "0" + reading.getMinutes())
        + " AM";
    }
  }

  // only add tooltips if it is not a live demo
  if(!/live_update/.test(document.URL)){
    $('svg circle').tipsy({
      gravity: 's',
      html: true,
      topOffset: 2.8,
      leftOffset: 0.3,
      opacity: 1,
      title: function() {
        var d = this.__data__;
        var pDate = d.date;
        return pDate.getDate() + ' '
          + monthNames[pDate.getMonth()] + ' '
          + pDate.getFullYear() + '
'
          + days[ pDate.getDay() ] + ' at '
          + getCivilianTime(pDate) + '
'
          + 'Temperature in Violation
'
          + '
Temperature in Apt: ' + d.temp + '°'
          + '
Temperature Outside: ' + d.outdoor_temp + '°'
          + '
Legal minimum: ' + legalMinimumFor(d) + '°';
      }
    });
  }
}

function drawChartBasedOnScreenSize(chartData){
  if ( $('#live-update') !== undefined ) {
    $('.temp-num').html(chartData[chartData.length - 1].temp + '°')
  }

  if (window.innerWidth < 450) {
    var quarterReadings = chartData.slice(119, 167);
    $("#d3-chart").html("")
    draw(quarterReadings);
  }else if(window.innerWidth < 720){
    var halfReadings = chartData.slice(71, 167);
    $("#d3-chart").html("")
    draw(halfReadings);
  }else if(window.innerWidth < 1080){
    var threeQuarterReadings = chartData.slice(23, 167);
    $("#d3-chart").html("")
    draw(threeQuarterReadings);
  }else{
    $("#d3-chart").html("")
    draw(chartData);
  }
}

function drawChartAjaxCall(){
  if($("#d3-chart").length > 0){
    if(/collaborations/.test(document.URL)){
      var URL = /\/users\/\d+\/collaborations\/\d+/.exec(document.URL)[0];
      // returns /user/11/collaborations/35
    } else if ( /live_update/.test(document.URL) ){
      var URL = /\/users\/\d+\/live_update/.exec(document.URL)[0];
      //returns /user/13/live_update
    } else {
      var URL = /\/users\/\d+/.exec(document.URL)[0];
    }
    $.ajax({
      url: URL,
      dataType: "JSON",
      success: function(response){
        if( response.length > 0 ){
          drawChartBasedOnScreenSize(response);
          var resizeTimer = 0;
          window.onresize = function(){
            if (resizeTimer){
              clearTimeout(resizeTimer);
            }
            resizeTimer = setTimeout(function(){
              drawChartBasedOnScreenSize(response);
            }, 50);
          };
        }
      },
      error: function(response){
        console.log("error");
        console.log(response);
      }
    });
  }
}<|endoftext|>


<commit_before>'use strict';
import React, { PropTypes } from 'react';
import c from 'classnames';
import { connect } from 'react-redux';
import {
  compose,
  getContext
} from 'recompose';
import { local } from 'redux-fractal';
import { createStore } from 'redux';
import { withRouter } from 'react-router';

import {
  CREATE_ROAD,
  CREATE_ROAD_SUCCESS,
  CREATE_ROAD_ERROR,
  createRoadEpic
} from '../redux/modules/roads';
import { environment } from '../config';

import T, {
  translate
} from '../components/t';
import { Modal, ModalHeader, ModalBody, ModalFooter } from './modal';

class AssetsCreateModal extends React.Component {
  constructor (props) {
    super(props);

    this.onSave = this.onSave.bind(this);
    this.onCloseClick = this.onCloseClick.bind(this);

    this.state = this.prepareState(props);
  }

  componentWillReceiveProps (nextProps) {
    if (!this.props.revealed && nextProps.revealed) {
      this.setState(this.prepareState(nextProps));
    }
  }

  prepareState (props) {
    return {
      vpromm: ''
    };
  }

  onValueChange (what, event) {
    this.setState({ [what]: event.target.value });
  }

  onCloseClick (e) {
    // Block while processing.
    if (this.props.roadPropsOp.processing) return;
    this.props.onCloseClick();
  }

  async onSave (e) {
    e.preventDefault();
    const vpromm = this.state.vpromm;

    // Validate Vprom

    try {
      const res = await this.props.createRoad(vpromm);
      if (res.error) throw new Error(res.error);
      this.props.onCloseClick({action: 'redirect', vpromm});
    } catch (error) {
      error.json().then(errMessage => {
        alert(translate(this.props.language, errMessage.message));
      })
    }
  }

  render () {
    const { processing } = this.props.roadPropsOp;

    return (
      <Modal
        id='assets-edit-modal'
        className='modal--medium'
        onCloseClick={this.onCloseClick}
        revealed={this.props.revealed} >

        <ModalHeader>

<T>Add new asset</T>

        </ModalHeader>
        <ModalBody>
          <form className={c('form', {disabled: processing})} disabled={processing} onSubmit={this.onSave}>

              <fieldset className='form__fieldset'>
                <legend className='form__legend'><T>Meta</T></legend>

                  VPRoMM ID
                  <input type='text' id='vpromm' name='vpromm' className='form__control' value={this.state.vpromm} onChange={this.onValueChange.bind(this, 'vpromm')} />

              </fieldset>

          </form>
        </ModalBody>
        <ModalFooter>
          <button className={c('mfa-xmark', {disabled: processing})} disabled={processing} type='button' onClick={this.onCloseClick}>Cancel</button>
          <button className={c('mfa-main mfa-tick', {disabled: processing})} disabled={processing} type='submit' onClick={this.onSave}>Save</button>
        </ModalFooter>
      </Modal>
    );
  }
}

if (environment !== 'production') {
  AssetsCreateModal.propTypes = {
    revealed: PropTypes.bool,
    roadPropsOp: PropTypes.object,
    onCloseClick: PropTypes.func,
    createRoad: PropTypes.func,
    language: PropTypes.string
  };
}

class AssetsCreate extends React.Component {
  constructor (props) {
    super(props);

    this.onCreateAssetClick = this.onCreateAssetClick.bind(this);
    this.onModalClose = this.onModalClose.bind(this);

    this.state = {
      createModalOpen: false
    };
  }

  onModalClose (data = {}) {
    this.setState({ createModalOpen: false });
    if (data.action === 'redirect') {
      // Why the setTimeout you ask?
      // For some reason redux-fractal doesn't play well with thunks.
      // It thinks that the action is being dispatched from a reducer and
      // throws an error. "Reducers may not dispatch actions."
      // This is meant to refresh the data after properties are saved.
      setTimeout(() => { this.props.router.push({pathname: `/${this.props.language}/assets/road/${data.vpromm}/`}); }, 0);
    }
  }

  onCreateAssetClick (e) {
    e.preventDefault();
    this.setState({ createModalOpen: true });
  }

  render () {
    return (

        <T>Add asset</T>

        <AssetsCreateModal
          revealed={this.state.createModalOpen}
          language={this.props.language}
          onCloseClick={this.onModalClose}
          createRoad={this.props.createRoad}
          roadPropsOp={this.props.roadPropsOp} />

    );
  }
}

if (environment !== 'production') {
  AssetsCreate.propTypes = {
    router: PropTypes.object,
    createRoad: React.PropTypes.func,
    language: React.PropTypes.string,
    roadPropsOp: React.PropTypes.object
  };
}

//
//
//

// Road operations state and reducer.
// Handles operations done to the properties.
const stateOpOnRoad = {
  processing: false,
  data: {}
};

const reducerOpOnRoad = (state = stateOpOnRoad, action) => {
  switch (action.type) {
    case CREATE_ROAD:
      return {...state, processing: true, error: false};
    case CREATE_ROAD_SUCCESS:
      return {...state, processing: false, error: false, data: action.data};
    case CREATE_ROAD_ERROR:
      return {...state, processing: false, error: true};
  }

  return state;
};

export default compose(
  withRouter,
  getContext({ language: React.PropTypes.string }),
  local({
    key: ({ vpromm }) => `create-road`,
    createStore: () => createStore(reducerOpOnRoad),
    mapStateToProps: (state) => ({
      roadPropsOp: state
    }),
    filterGlobalActions: ({ type }) => [
      CREATE_ROAD,
      CREATE_ROAD_SUCCESS,
      CREATE_ROAD_ERROR
    ].indexOf(type) > -1
  }),
  connect(
    (state, props) => ({}),
    (dispatch) => ({
      createRoad: (...args) => dispatch(createRoadEpic(...args))
    })
  )
)(AssetsCreate);
<commit_msg>lint again<commit_after>'use strict';
import React, { PropTypes } from 'react';
import c from 'classnames';
import { connect } from 'react-redux';
import {
  compose,
  getContext
} from 'recompose';
import { local } from 'redux-fractal';
import { createStore } from 'redux';
import { withRouter } from 'react-router';

import {
  CREATE_ROAD,
  CREATE_ROAD_SUCCESS,
  CREATE_ROAD_ERROR,
  createRoadEpic
} from '../redux/modules/roads';
import { environment } from '../config';

import T, {
  translate
} from '../components/t';
import { Modal, ModalHeader, ModalBody, ModalFooter } from './modal';

class AssetsCreateModal extends React.Component {
  constructor (props) {
    super(props);

    this.onSave = this.onSave.bind(this);
    this.onCloseClick = this.onCloseClick.bind(this);

    this.state = this.prepareState(props);
  }

  componentWillReceiveProps (nextProps) {
    if (!this.props.revealed && nextProps.revealed) {
      this.setState(this.prepareState(nextProps));
    }
  }

  prepareState (props) {
    return {
      vpromm: ''
    };
  }

  onValueChange (what, event) {
    this.setState({ [what]: event.target.value });
  }

  onCloseClick (e) {
    // Block while processing.
    if (this.props.roadPropsOp.processing) return;
    this.props.onCloseClick();
  }

  async onSave (e) {
    e.preventDefault();
    const vpromm = this.state.vpromm;

    // Validate Vprom

    try {
      const res = await this.props.createRoad(vpromm);
      if (res.error) throw new Error(res.error);
      this.props.onCloseClick({action: 'redirect', vpromm});
    } catch (error) {
      error.json().then(errMessage => {
        alert(translate(this.props.language, errMessage.message));
      });
    }
  }

  render () {
    const { processing } = this.props.roadPropsOp;

    return (
      <Modal
        id='assets-edit-modal'
        className='modal--medium'
        onCloseClick={this.onCloseClick}
        revealed={this.props.revealed} >

        <ModalHeader>

<T>Add new asset</T>

        </ModalHeader>
        <ModalBody>
          <form className={c('form', {disabled: processing})} disabled={processing} onSubmit={this.onSave}>

              <fieldset className='form__fieldset'>
                <legend className='form__legend'><T>Meta</T></legend>

                  VPRoMM ID
                  <input type='text' id='vpromm' name='vpromm' className='form__control' value={this.state.vpromm} onChange={this.onValueChange.bind(this, 'vpromm')} />

              </fieldset>

          </form>
        </ModalBody>
        <ModalFooter>
          <button className={c('mfa-xmark', {disabled: processing})} disabled={processing} type='button' onClick={this.onCloseClick}>Cancel</button>
          <button className={c('mfa-main mfa-tick', {disabled: processing})} disabled={processing} type='submit' onClick={this.onSave}>Save</button>
        </ModalFooter>
      </Modal>
    );
  }
}

if (environment !== 'production') {
  AssetsCreateModal.propTypes = {
    revealed: PropTypes.bool,
    roadPropsOp: PropTypes.object,
    onCloseClick: PropTypes.func,
    createRoad: PropTypes.func,
    language: PropTypes.string
  };
}

class AssetsCreate extends React.Component {
  constructor (props) {
    super(props);

    this.onCreateAssetClick = this.onCreateAssetClick.bind(this);
    this.onModalClose = this.onModalClose.bind(this);

    this.state = {
      createModalOpen: false
    };
  }

  onModalClose (data = {}) {
    this.setState({ createModalOpen: false });
    if (data.action === 'redirect') {
      // Why the setTimeout you ask?
      // For some reason redux-fractal doesn't play well with thunks.
      // It thinks that the action is being dispatched from a reducer and
      // throws an error. "Reducers may not dispatch actions."
      // This is meant to refresh the data after properties are saved.
      setTimeout(() => { this.props.router.push({pathname: `/${this.props.language}/assets/road/${data.vpromm}/`}); }, 0);
    }
  }

  onCreateAssetClick (e) {
    e.preventDefault();
    this.setState({ createModalOpen: true });
  }

  render () {
    return (

        <T>Add asset</T>

        <AssetsCreateModal
          revealed={this.state.createModalOpen}
          language={this.props.language}
          onCloseClick={this.onModalClose}
          createRoad={this.props.createRoad}
          roadPropsOp={this.props.roadPropsOp} />

    );
  }
}

if (environment !== 'production') {
  AssetsCreate.propTypes = {
    router: PropTypes.object,
    createRoad: React.PropTypes.func,
    language: React.PropTypes.string,
    roadPropsOp: React.PropTypes.object
  };
}

//
//
//

// Road operations state and reducer.
// Handles operations done to the properties.
const stateOpOnRoad = {
  processing: false,
  data: {}
};

const reducerOpOnRoad = (state = stateOpOnRoad, action) => {
  switch (action.type) {
    case CREATE_ROAD:
      return {...state, processing: true, error: false};
    case CREATE_ROAD_SUCCESS:
      return {...state, processing: false, error: false, data: action.data};
    case CREATE_ROAD_ERROR:
      return {...state, processing: false, error: true};
  }

  return state;
};

export default compose(
  withRouter,
  getContext({ language: React.PropTypes.string }),
  local({
    key: ({ vpromm }) => `create-road`,
    createStore: () => createStore(reducerOpOnRoad),
    mapStateToProps: (state) => ({
      roadPropsOp: state
    }),
    filterGlobalActions: ({ type }) => [
      CREATE_ROAD,
      CREATE_ROAD_SUCCESS,
      CREATE_ROAD_ERROR
    ].indexOf(type) > -1
  }),
  connect(
    (state, props) => ({}),
    (dispatch) => ({
      createRoad: (...args) => dispatch(createRoadEpic(...args))
    })
  )
)(AssetsCreate);
<|endoftext|>


<commit_before>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import Button from '@material-ui/core/Button';
import uuidv1 from 'uuid';
import { withStyles } from '@material-ui/core/styles';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import Switch from '@material-ui/core/Switch';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormGroup from '@material-ui/core/FormGroup';
import Grid from '@material-ui/core/Grid';
import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup';
import GenericDialog, { onEnterKeyHandler } from './GenericDialog';
import i18n from '../../services/i18n';
import { type Location, locationType } from '../../reducers/locations';
import { Pro } from '../../pro';
import ObjectStoreForm from './ObjectStoreForm';
import LocalForm from './LocalForm';

const styles = theme => ({
  root: {
    display: 'flex',
  },
  formControl: {
    margin: theme.spacing.unit * 3,
  },
  group: {
    margin: `${theme.spacing.unit}px 0`,
    display: 'flex',
    flexDirection: 'row'
  },
});

type Props = {
  classes: Object,
  open?: boolean,
  onClose: () => void,
  addLocation: (location: Location) => void,
  perspectives: Array<Object>,
  showSelectDirectoryDialog: () => void,
  resetState: () => void,
  selectedDirectoryPath?: string | null
};

type State = {
  errorTextPath?: boolean,
  errorTextName?: boolean,
  disableConfirmButton?: boolean,
  // open?: boolean,
  name?: string,
  path?: string,
  perspective?: string,
  isDefault?: boolean,
  isReadOnly?: boolean,
  watchForChanges?: boolean,
  persistIndex?: boolean,
  type: string
};

class CreateLocationDialog extends React.Component<Props, State> {
  state = {
    errorTextPath: false,
    errorTextName: false,
    disableConfirmButton: true,
    // open: false,
    name: '',
    path: '',
    perspective: '',
    isDefault: false,
    isReadOnly: false,
    watchForChanges: Pro,
    persistIndex: false,
    type: locationType.TYPE_LOCAL
  };

  /* componentWillReceiveProps = (nextProps: any) => {
    if (nextProps.open === true) {
      const dir = nextProps.selectedDirectoryPath;
      this.setState({
        name: dir ? extractDirectoryName(dir) : '',
        path: dir || '',
        perspective: '',
        isDefault: false,
        isReadOnly: false,
        watchForChanges: !!Pro,
        persistIndex: false
      });
    }
  }; */

  componentWillUnmount = () => {
    console.log('CreateLocationDialog componentWillUnmount');
  };

  handleInputChange = (event: Object) => {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    if (target.type === 'radio') { // type is changed (skip validation)
      this.setState({
        [name]: value
      });
    } else {
      this.handleChange(name, value);
    }
  };

  handleChange = (name, value) => {
    this.setState({
      [name]: value
    }, this.handleValidation);
  };

  handleValidation() {
    // const pathRegex = this.state.path.match('^((\.\./|[a-zA-Z0-9_/\-\\])*\.[a-zA-Z0-9]+)$');
    // const nameRegex = this.state.name.match('^[A-Z][-a-zA-Z]+$');
    if (this.state.type === locationType.TYPE_LOCAL) {
      let errorTextName = false;
      let errorTextPath = false;
      let disableConfirmButton = false;
      if (!this.state.name || this.state.name.length === 0) {
        errorTextName = true;
        disableConfirmButton = true;
      }

      if (!this.state.path || this.state.path.length === 0) {
        errorTextPath = true;
        disableConfirmButton = true;
      }

      this.setState({ errorTextName, errorTextPath, disableConfirmButton });
    } else if (this.state.type === locationType.TYPE_CLOUD) {
      let cloudErrorTextName = false;
      let cloudErrorTextPath = false;
      let cloudErrorAccessKey = false;
      let cloudErrorSecretAccessKey = false;
      let cloudErrorBucketName = false;
      let cloudErrorRegion = false;
      let disableConfirmButton = false;
      if (!this.state.storeName || this.state.storeName.length === 0) {
        cloudErrorTextName = true;
        disableConfirmButton = true;
      }

      if (!this.state.storePath || this.state.storePath.length === 0) {
        cloudErrorTextPath = true;
        disableConfirmButton = true;
      }

      if (!this.state.accessKeyId || this.state.accessKeyId.length === 0) {
        cloudErrorAccessKey = true;
        disableConfirmButton = true;
      }

      if (!this.state.secretAccessKey || this.state.secretAccessKey.length === 0) {
        cloudErrorSecretAccessKey = true;
        disableConfirmButton = true;
      }

      if (!this.state.bucketName || this.state.bucketName.length === 0) {
        cloudErrorBucketName = true;
        disableConfirmButton = true;
      }

      if (!this.state.region) {
        cloudErrorRegion = true;
        disableConfirmButton = true;
      }

      this.setState({ cloudErrorTextName, cloudErrorTextPath, cloudErrorAccessKey, cloudErrorSecretAccessKey, cloudErrorBucketName, disableConfirmButton, cloudErrorRegion });
    }
  }

  onConfirm = () => {
    if (!this.state.disableConfirmButton) {
      if (this.state.type === locationType.TYPE_LOCAL) {
        this.props.addLocation({
          uuid: uuidv1(),
          type: locationType.TYPE_LOCAL,
          name: this.state.name,
          paths: [this.state.path],
          perspective: this.state.perspective,
          isDefault: this.state.isDefault,
          isReadOnly: this.state.isReadOnly,
          persistIndex: this.state.persistIndex,
          watchForChanges: this.state.watchForChanges
        });
        /* this.setState({
          // open: false,
          errorTextPath: false,
          errorTextName: false,
          disableConfirmButton: true
        }); */
      } else if (this.state.type === locationType.TYPE_CLOUD) {
        this.props.addLocation({
          uuid: uuidv1(),
          type: locationType.TYPE_CLOUD,
          name: this.state.storeName,
          paths: [this.state.storePath],
          accessKeyId: this.state.accessKeyId,
          secretAccessKey: this.state.secretAccessKey,
          bucketName: this.state.bucketName,
          region: this.state.region.value,
          perspective: this.state.perspective,
          isDefault: this.state.isDefault,
          isReadOnly: this.state.isReadOnly,
          persistIndex: this.state.persistIndex,
          watchForChanges: this.state.watchForChanges
        });
        /* this.setState({
          open: false,
          errorTextPath: false,
          errorTextName: false,
          cloudErrorTextName: false,
          cloudErrorTextPath: false,
          cloudErrorAccessKey: false,
          cloudErrorSecretAccessKey: false,
          disableConfirmButton: true
        }); */
      }
      this.props.onClose();
      this.props.resetState('createLocationDialogKey');
    }
  };

  renderTitle = () => (
    <DialogTitle>{i18n.t('core:createLocationTitle')}</DialogTitle>
  );

  renderContent = () => {
    // const { classes } = this.props;
    let content;
    if (this.state.type === locationType.TYPE_CLOUD) {
      content = (<ObjectStoreForm handleInputChange={this.handleInputChange} handleChange={this.handleChange} state={this.state} />);
    } else {
      content = (<LocalForm showSelectDirectoryDialog={this.props.showSelectDirectoryDialog} handleInputChange={this.handleInputChange} handleChange={this.handleChange} state={this.state} />);
    }
    return (
      <DialogContent>
        <Grid container spacing={24}>
          <Grid item xs={2} style={{ lineHeight: 3, textAlign: 'right' }}>
          Type
          </Grid>
          <Grid item xs={10}>
            <RadioGroup
              component="label"
              aria-label="Type"
              name="type"
              value={this.state.type}
              onChange={this.handleInputChange}
              row
            >
              <FormControlLabel value={locationType.TYPE_LOCAL} control={<Radio />} label="Local" />
              <FormControlLabel value={locationType.TYPE_CLOUD} control={<Radio />} label="Cloud (S3 AWS)" />
            </RadioGroup>
          </Grid>
        </Grid>
        {content}
        <FormGroup>
          <FormControlLabel
            control={
              <Switch
                data-tid="locationIsDefault"
                name="isDefault"
                checked={this.state.isDefault}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:startupLocation')}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changeReadOnlyMode"
                name="isReadOnly"
                checked={this.state.isReadOnly}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:readonlyModeSwitch') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changePersistIndex"
                name="persistIndex"
                checked={this.state.persistIndex}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:persistIndexSwitch') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changeWatchForChanges"
                name="watchForChanges"
                checked={this.state.watchForChanges}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:watchForChangesInLocation') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
        </FormGroup>
      </DialogContent>
    );
  };

  /*
        <FormControl
          fullWidth={true}
        >
          <InputLabel htmlFor="perspective">{i18n.t('core:createLocationDefaultPerspective')}</InputLabel>
          <Select
            native
            autoWidth
            label={i18n.t('core:createLocationDefaultPerspective')}
            name="perspective"
            value={this.state.perspective}
            onChange={this.handleInputChange}
            input={<Input id="perspective" />}
          >
            {this.props.perspectives.map((persp) => (<option key={persp.id} value={persp.id}>{persp.name}</option>))}
          </Select>
        </FormControl>
*/

  renderActions = () => (
    <DialogActions>
      <Button onClick={this.props.onClose} >
        {i18n.t('core:cancel')}
      </Button>
      <Button
        disabled={this.state.disableConfirmButton}
        onClick={this.onConfirm}
        data-tid="confirmLocationCreation"
        color="primary"
      >
        {i18n.t('core:ok')}
      </Button>
    </DialogActions>
  );

  render() {
    return (
      <GenericDialog
        open={this.props.open}
        onClose={this.props.onClose}
        onEnterKey={(event) => onEnterKeyHandler(event, this.onConfirm)}
        renderTitle={this.renderTitle}
        renderContent={this.renderContent}
        renderActions={this.renderActions}
      />
    );
  }
}

export default withStyles(styles)(CreateLocationDialog);
<commit_msg>validation fixes<commit_after>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import Button from '@material-ui/core/Button';
import uuidv1 from 'uuid';
import { withStyles } from '@material-ui/core/styles';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import Switch from '@material-ui/core/Switch';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormGroup from '@material-ui/core/FormGroup';
import Grid from '@material-ui/core/Grid';
import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup';
import GenericDialog, { onEnterKeyHandler } from './GenericDialog';
import i18n from '../../services/i18n';
import { type Location, locationType } from '../../reducers/locations';
import { Pro } from '../../pro';
import ObjectStoreForm from './ObjectStoreForm';
import LocalForm from './LocalForm';

const styles = theme => ({
  root: {
    display: 'flex',
  },
  formControl: {
    margin: theme.spacing.unit * 3,
  },
  group: {
    margin: `${theme.spacing.unit}px 0`,
    display: 'flex',
    flexDirection: 'row'
  },
});

type Props = {
  classes: Object,
  open?: boolean,
  onClose: () => void,
  addLocation: (location: Location) => void,
  perspectives: Array<Object>,
  showSelectDirectoryDialog: () => void,
  resetState: () => void,
  selectedDirectoryPath?: string | null
};

type State = {
  errorTextPath?: boolean,
  errorTextName?: boolean,
  disableConfirmButton?: boolean,
  // open?: boolean,
  name?: string,
  path?: string,
  perspective?: string,
  isDefault?: boolean,
  isReadOnly?: boolean,
  watchForChanges?: boolean,
  persistIndex?: boolean,
  type: string
};

class CreateLocationDialog extends React.Component<Props, State> {
  state = {
    errorTextPath: false,
    errorTextName: false,
    disableConfirmButton: true,
    // open: false,
    name: '',
    path: '',
    perspective: '',
    isDefault: false,
    isReadOnly: false,
    watchForChanges: Pro,
    persistIndex: false,
    type: locationType.TYPE_LOCAL
  };

  /* componentWillReceiveProps = (nextProps: any) => {
    if (nextProps.open === true) {
      const dir = nextProps.selectedDirectoryPath;
      this.setState({
        name: dir ? extractDirectoryName(dir) : '',
        path: dir || '',
        perspective: '',
        isDefault: false,
        isReadOnly: false,
        watchForChanges: !!Pro,
        persistIndex: false
      });
    }
  }; */

  componentWillUnmount = () => {
    console.log('CreateLocationDialog componentWillUnmount');
  };

  handleInputChange = (event: Object) => {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    if (target.type === 'radio') { // type is changed (skip validation)
      this.setState({
        [name]: value
      });
    } else {
      this.handleChange(name, value);
    }
  };

  handleChange = (name, value) => {
    this.setState({
      [name]: value
    }, () => {
      this.handleValidation(name);
    });
  };

  /* handleFieldValidation(field) {
    if (!this.state[field] || this.state[field].length === 0) {
      const errorName = 'error' + field;
      this.setState({ [errorName]: true, disableConfirmButton: true });
    }
  } */

  handleValidation(field) {
    // const pathRegex = this.state.path.match('^((\.\./|[a-zA-Z0-9_/\-\\])*\.[a-zA-Z0-9]+)$');
    // const nameRegex = this.state.name.match('^[A-Z][-a-zA-Z]+$');
    if (this.state.type === locationType.TYPE_LOCAL) {
      let errorTextName = false;
      let errorTextPath = false;
      let disableConfirmButton = false;
      if (!this.state.name || this.state.name.length === 0) {
        errorTextName = true;
        disableConfirmButton = true;
      } else if (field === 'name' && !this.state.errorTextName && !this.state.errorTextPath && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.path || this.state.path.length === 0) {
        errorTextPath = true;
        disableConfirmButton = true;
      }

      return new Promise(resolve => this.setState({ errorTextName, errorTextPath, disableConfirmButton }, resolve(!disableConfirmButton)));
    } else if (this.state.type === locationType.TYPE_CLOUD) {
      let cloudErrorTextName = false;
      let cloudErrorTextPath = false;
      let cloudErrorAccessKey = false;
      let cloudErrorSecretAccessKey = false;
      let cloudErrorBucketName = false;
      let cloudErrorRegion = false;
      let disableConfirmButton = false;
      if (!this.state.storeName || this.state.storeName.length === 0) {
        cloudErrorTextName = true;
        disableConfirmButton = true;
      } else if (field === 'storeName'
        && !this.state.cloudErrorTextName
        && !this.state.cloudErrorTextPath
        && !this.state.cloudErrorAccessKey
        && !this.state.cloudErrorSecretAccessKey
        && !this.state.cloudErrorBucketName
        && !this.state.cloudErrorRegion
        && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.storePath || this.state.storePath.length === 0) {
        cloudErrorTextPath = true;
        disableConfirmButton = true;
      } else if (field === 'storePath'
        && !this.state.cloudErrorTextName
        && !this.state.cloudErrorTextPath
        && !this.state.cloudErrorAccessKey
        && !this.state.cloudErrorSecretAccessKey
        && !this.state.cloudErrorBucketName
        && !this.state.cloudErrorRegion
        && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.accessKeyId || this.state.accessKeyId.length === 0) {
        cloudErrorAccessKey = true;
        disableConfirmButton = true;
      } else if (field === 'accessKeyId'
        && !this.state.cloudErrorTextName
        && !this.state.cloudErrorTextPath
        && !this.state.cloudErrorAccessKey
        && !this.state.cloudErrorSecretAccessKey
        && !this.state.cloudErrorBucketName
        && !this.state.cloudErrorRegion
        && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.secretAccessKey || this.state.secretAccessKey.length === 0) {
        cloudErrorSecretAccessKey = true;
        disableConfirmButton = true;
      } else if (field === 'secretAccessKey'
        && !this.state.cloudErrorTextName
        && !this.state.cloudErrorTextPath
        && !this.state.cloudErrorAccessKey
        && !this.state.cloudErrorSecretAccessKey
        && !this.state.cloudErrorBucketName
        && !this.state.cloudErrorRegion
        && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.bucketName || this.state.bucketName.length === 0) {
        cloudErrorBucketName = true;
        disableConfirmButton = true;
      } else if (field === 'bucketName'
        && !this.state.cloudErrorTextName
        && !this.state.cloudErrorTextPath
        && !this.state.cloudErrorAccessKey
        && !this.state.cloudErrorSecretAccessKey
        && !this.state.cloudErrorBucketName
        && !this.state.cloudErrorRegion
        && this.state.disableConfirmButton) { // initial skip validation for other fields
        return new Promise(((resolve) => {
          resolve(true);
        }));
      }

      if (!this.state.region) {
        cloudErrorRegion = true;
        disableConfirmButton = true;
      }

      return new Promise(resolve => this.setState({
        cloudErrorTextName,
        cloudErrorTextPath,
        cloudErrorAccessKey,
        cloudErrorSecretAccessKey,
        cloudErrorBucketName,
        disableConfirmButton,
        cloudErrorRegion }, resolve(!disableConfirmButton)));
    }
    return new Promise(((resolve) => {
      resolve(true);
    }));
  }

  onConfirm = () => {
    this.handleValidation().then((success) => {
      if (success) {
        if (this.state.type === locationType.TYPE_LOCAL) {
          this.props.addLocation({
            uuid: uuidv1(),
            type: locationType.TYPE_LOCAL,
            name: this.state.name,
            paths: [this.state.path],
            perspective: this.state.perspective,
            isDefault: this.state.isDefault,
            isReadOnly: this.state.isReadOnly,
            persistIndex: this.state.persistIndex,
            watchForChanges: this.state.watchForChanges
          });
        } else if (this.state.type === locationType.TYPE_CLOUD) {
          this.props.addLocation({
            uuid: uuidv1(),
            type: locationType.TYPE_CLOUD,
            name: this.state.storeName,
            paths: [this.state.storePath],
            accessKeyId: this.state.accessKeyId,
            secretAccessKey: this.state.secretAccessKey,
            bucketName: this.state.bucketName,
            region: this.state.region.value,
            perspective: this.state.perspective,
            isDefault: this.state.isDefault,
            isReadOnly: this.state.isReadOnly,
            persistIndex: this.state.persistIndex,
            watchForChanges: this.state.watchForChanges
          });
        }
        this.props.onClose();
        this.props.resetState('createLocationDialogKey');
      }
      return haveErrors;
    }).catch((error) => {
      console.debug('Failed validation', error);
    });
  };

  renderTitle = () => (
    <DialogTitle>{i18n.t('core:createLocationTitle')}</DialogTitle>
  );

  renderContent = () => {
    // const { classes } = this.props;
    let content;
    if (this.state.type === locationType.TYPE_CLOUD) {
      content = (<ObjectStoreForm handleInputChange={this.handleInputChange} handleChange={this.handleChange} state={this.state} />);
    } else {
      content = (<LocalForm showSelectDirectoryDialog={this.props.showSelectDirectoryDialog} handleInputChange={this.handleInputChange} handleChange={this.handleChange} state={this.state} />);
    }
    return (
      <DialogContent>
        <Grid container spacing={24}>
          <Grid item xs={2} style={{ lineHeight: 3, textAlign: 'right' }}>
          Type
          </Grid>
          <Grid item xs={10}>
            <RadioGroup
              component="label"
              aria-label="Type"
              name="type"
              value={this.state.type}
              onChange={this.handleInputChange}
              row
            >
              <FormControlLabel value={locationType.TYPE_LOCAL} control={<Radio />} label="Local" />
              <FormControlLabel value={locationType.TYPE_CLOUD} control={<Radio />} label="Cloud (S3 AWS)" />
            </RadioGroup>
          </Grid>
        </Grid>
        {content}
        <FormGroup>
          <FormControlLabel
            control={
              <Switch
                data-tid="locationIsDefault"
                name="isDefault"
                checked={this.state.isDefault}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:startupLocation')}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changeReadOnlyMode"
                name="isReadOnly"
                checked={this.state.isReadOnly}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:readonlyModeSwitch') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changePersistIndex"
                name="persistIndex"
                checked={this.state.persistIndex}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:persistIndexSwitch') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
          <FormControlLabel
            control={
              <Switch
                disabled={!Pro}
                data-tid="changeWatchForChanges"
                name="watchForChanges"
                checked={this.state.watchForChanges}
                onChange={this.handleInputChange}
              />
            }
            label={i18n.t('core:watchForChangesInLocation') + (Pro ? '' : ' - ' + i18n.t('core:proFeature'))}
          />
        </FormGroup>
      </DialogContent>
    );
  };

  /*
        <FormControl
          fullWidth={true}
        >
          <InputLabel htmlFor="perspective">{i18n.t('core:createLocationDefaultPerspective')}</InputLabel>
          <Select
            native
            autoWidth
            label={i18n.t('core:createLocationDefaultPerspective')}
            name="perspective"
            value={this.state.perspective}
            onChange={this.handleInputChange}
            input={<Input id="perspective" />}
          >
            {this.props.perspectives.map((persp) => (<option key={persp.id} value={persp.id}>{persp.name}</option>))}
          </Select>
        </FormControl>
*/

  renderActions = () => (
    <DialogActions>
      <Button onClick={this.props.onClose} >
        {i18n.t('core:cancel')}
      </Button>
      <Button
        disabled={this.state.disableConfirmButton}
        onClick={this.onConfirm}
        data-tid="confirmLocationCreation"
        color="primary"
      >
        {i18n.t('core:ok')}
      </Button>
    </DialogActions>
  );

  render() {
    return (
      <GenericDialog
        open={this.props.open}
        onClose={this.props.onClose}
        onEnterKey={(event) => onEnterKeyHandler(event, this.onConfirm)}
        renderTitle={this.renderTitle}
        renderContent={this.renderContent}
        renderActions={this.renderActions}
      />
    );
  }
}

export default withStyles(styles)(CreateLocationDialog);
<|endoftext|>


<commit_before>import keys from 'describe-type/source/@/keys.js';
import slice from 'describe-type/source/@/slice.js';
import array from 'describe-type/source/is/array.js';
import object from 'describe-type/source/is/object.js';
import callable from 'describe-type/source/is/callable.js';

export default (strategy) => {
	let notation = '';
	return function assign(target) {
		const args = slice(arguments);
		const output = Object(target || {});
		for (let ix = 1; ix < args.length; ix += 1) {
			const from = args[ix];
			const keyList = keys(Object(from));
			for (let iy = 0; iy < keyList.length; iy += 1) {
				const key = keyList[iy];
				const outputValue = output[key];
				const sourceValue = from[key];
				if (array(outputValue) || array(sourceValue)) {
					const f = array(sourceValue) ? slice(sourceValue) : [];
					const o = array(outputValue) ? slice(outputValue) : [];
					output[key] = strategy(f, o, `${notation}.${key}`, keyList);
				} else if (callable(outputValue) || callable(sourceValue)) {
					output[key] = strategy(sourceValue, outputValue, `${notation}.${key}`, keyList);
				} else if (object(outputValue) || object(sourceValue)) {
					const cn = notation;
					notation = (cn ? `${cn}.` : '') + key;
					output[key] = assign(outputValue, sourceValue);
					notation = cn;
				} else {
					output[key] = strategy(sourceValue, outputValue, `${notation}.${key}`, keyList);
				}
			}
		}
		return output;
	};
};
<commit_msg>perf: assign<commit_after>import keys from 'describe-type/source/@/keys.js';
import slice from 'describe-type/source/@/slice.js';
import array from 'describe-type/source/is/array.js';
import object from 'describe-type/source/is/object.js';
import callable from 'describe-type/source/is/callable.js';

export default (strategy) => {
	let notation = '';
	return function assign(target) {
		const args = slice(arguments);
		const output = target == null ? {} : target;
		for (let ix = 1; ix < args.length; ix += 1) {
			const from = args[ix];
			const keyList = keys(from);
			for (let iy = 0; iy < keyList.length; iy += 1) {
				const key = keyList[iy];
				const outputValue = output[key];
				const sourceValue = from[key];
				if (array(outputValue) || array(sourceValue)) {
					const f = array(sourceValue) ? slice(sourceValue) : [];
					const o = array(outputValue) ? slice(outputValue) : [];
					output[key] = strategy(f, o, `${notation}.${key}`, keyList);
				} else if (callable(outputValue) || callable(sourceValue)) {
					output[key] = strategy(sourceValue, outputValue, `${notation}.${key}`, keyList);
				} else if (object(outputValue) || object(sourceValue)) {
					const cn = notation;
					notation = (cn ? `${cn}.` : '') + key;
					output[key] = assign(outputValue, sourceValue);
					notation = cn;
				} else {
					output[key] = strategy(sourceValue, outputValue, `${notation}.${key}`, keyList);
				}
			}
		}
		return output;
	};
};
<|endoftext|>


<commit_before>/* globals onmessage: true, postMessage: true */
/**
 * Count the status of build and boot reports.
 * Return a message with an array of 2 elements: the total count, an array of 3
 * elements (in this order: passed, failed, other).
 *
 * @param {Object} message: The received message containing the response from
 * the API.
**/
onmessage = function(message) {
    'use strict';
    var counted,
        failed,
        other,
        passed,
        results,
        total;

    function _count(result) {
        switch (result.status) {
            case 'FAIL':
                failed = failed + 1;
                break;
            case 'PASS':
                passed = passed + 1;
                break;
            default:
                other = other + 1;
                break;
        }
    }

    counted = null;

    if (message.data) {
        failed = 0;
        other = 0;
        passed = 0;
        total = 0;
        results = message.data.result;

        if (results.length > 0) {
            results.forEach(_count);
            total = passed + failed + other;
            counted = [total, [passed, failed, other]];
        }
    }

    postMessage(counted);
};
<commit_msg>Fix total count calculation<commit_after>/* globals onmessage: true, postMessage: true */
/**
 * Count the status of build and boot reports.
 * Return a message with an array of 2 elements: the total count, an array of 3
 * elements (in this order: passed, failed, other).
 *
 * @param {Object} message: The received message containing the response from
 * the API.
**/
onmessage = function(message) {
    'use strict';
    var counted,
        failed,
        other,
        passed,
        results,
        total;

    function _count(result) {
        switch (result.status) {
            case 'FAIL':
                failed = failed + 1;
                break;
            case 'PASS':
                passed = passed + 1;
                break;
            default:
                other = other + 1;
                break;
        }
        total = total + 1;
    }

    counted = null;

    if (message.data) {
        failed = 0;
        other = 0;
        passed = 0;
        total = 0;
        results = message.data.result;

        if (results.length > 0) {
            results.forEach(_count);
            counted = [total, [passed, failed, other]];
        }
    }

    postMessage(counted);
};
<|endoftext|>


<commit_before>import Ember from 'ember';
import modal from '../utils/modal';
import app_state from '../utils/app_state';
import i18n from '../utils/i18n';
import persistence from '../utils/persistence';
import CoughDrop from '../app';

export default modal.ModalController.extend({
  opening: function() {
    var supervisees = [];
    if(app_state.get('sessionUser.supervisees')) {
      app_state.get('sessionUser.supervisees').forEach(function(supervisee) {
        var res = Ember.Object.create(supervisee);
        res.set('disabled', !supervisee.edit_permission);
        supervisees.push(res);
      });
    }
    this.set('loading', false);
    this.set('error', false);
    this.set('model.supervisees', supervisees);
    if(supervisees.length === 0) {
      this.set('current_selected_id', 'self');
    }
  },
  user_board: function() {
    var for_user_id = this.get('currently_selected_id');
    this.set('self_currently_selected', for_user_id == 'self');
    if(this.get('model.supervisees')) {
      this.get('model.supervisees').forEach(function(sup) {
        if(for_user_id == sup.id) {
          sup.set('currently_selected', true);
        } else {
          sup.set('currently_selected', false);
        }
      });
    }
  }.observes('currently_selected_id', 'model.supervisees'),
  actions: {
    select: function(for_user_id) {
      this.set('currently_selected_id', for_user_id);
    },
    add: function() {
      var board = this.get('model.board');
      var user_id = this.get('currently_selected_id');
      var _this = this;

      _this.set('loading', true);

      var find_user = CoughDrop.store.findRecord('user', user_id);

      var update_user = find_user.then(function(user) {
        var boards = user.get('preferences.sidebar_boards');
        if(!boards || boards.length === 0) {
          boards = window.user_preferences.any_user.default_sidebar_boards;
        }
        boards.unshift({
          name: board.name,
          key: board.key,
          home_lock: !!board.home_lock,
          image: board.image
        });

        user.set('preferences.sidebar_boards', boards);
        return user.save();
      });

      update_user.then(function(user) {
        _this.set('loading', false);
        if(persistence.get('online')) {
          Ember.run.later(function() {
            persistence.sync('self').then(null, function() { });
          }, 1000);
        }
        modal.close('add-to-sidebar');
        modal.success(i18n.t('added_to_sidebar', "Added to the user's sidebar!"));
      }, function() {
        _this.set('loading', false);
        _this.set('error', true);
      });
    }
  }
});
<commit_msg>adding to sidebar should work even without supervisees<commit_after>import Ember from 'ember';
import modal from '../utils/modal';
import app_state from '../utils/app_state';
import i18n from '../utils/i18n';
import persistence from '../utils/persistence';
import CoughDrop from '../app';

export default modal.ModalController.extend({
  opening: function() {
    var supervisees = [];
    if(app_state.get('sessionUser.supervisees')) {
      app_state.get('sessionUser.supervisees').forEach(function(supervisee) {
        var res = Ember.Object.create(supervisee);
        res.set('disabled', !supervisee.edit_permission);
        supervisees.push(res);
      });
    }
    this.set('loading', false);
    this.set('error', false);
    this.set('model.supervisees', supervisees);
    if(supervisees.length === 0) {
      this.set('currently_selected_id', 'self');
    }
  },
  user_board: function() {
    var for_user_id = this.get('currently_selected_id');
    this.set('self_currently_selected', for_user_id == 'self');
    if(this.get('model.supervisees')) {
      this.get('model.supervisees').forEach(function(sup) {
        if(for_user_id == sup.id) {
          sup.set('currently_selected', true);
        } else {
          sup.set('currently_selected', false);
        }
      });
    }
  }.observes('currently_selected_id', 'model.supervisees'),
  actions: {
    select: function(for_user_id) {
      this.set('currently_selected_id', for_user_id);
    },
    add: function() {
      var board = this.get('model.board');
      var user_id = this.get('currently_selected_id');
      var _this = this;

      _this.set('loading', true);

      var find_user = CoughDrop.store.findRecord('user', user_id);

      var update_user = find_user.then(function(user) {
        var boards = user.get('preferences.sidebar_boards');
        if(!boards || boards.length === 0) {
          boards = window.user_preferences.any_user.default_sidebar_boards;
        }
        boards.unshift({
          name: board.name,
          key: board.key,
          home_lock: !!board.home_lock,
          image: board.image
        });

        user.set('preferences.sidebar_boards', boards);
        return user.save();
      });

      update_user.then(function(user) {
        _this.set('loading', false);
        if(persistence.get('online')) {
          Ember.run.later(function() {
            persistence.sync('self').then(null, function() { });
          }, 1000);
        }
        modal.close('add-to-sidebar');
        modal.success(i18n.t('added_to_sidebar', "Added to the user's sidebar!"));
      }, function() {
        _this.set('loading', false);
        _this.set('error', true);
      });
    }
  }
});
<|endoftext|>