<commit_before>define(
  [
    'react',
    'dispatchers/AppDispatcher',
    'constants/InstanceConstants',
    'constants/ProjectInstanceConstants',
    'models/Instance',
    'models/InstanceState',
    'globals',
    'context',
    'url',
    'controllers/NotificationController',
    'actions/ProjectInstanceActions',
    'stores',

    // Modals
    'components/modals/ModalHelpers',
    'components/modals/instance/InstanceSuspendModal.react',
    'components/modals/instance/InstanceDeleteModal.react',
    'components/modals/instance/InstanceResumeModal.react',
    'components/modals/instance/InstanceStopModal.react',
    'components/modals/instance/InstanceStartModal.react',
    'components/modals/instance/InstanceRebootModal.react',
    'components/modals/instance/InstanceLaunchModal.react',
    'components/modals/instance/ExplainInstanceDeleteConditionsModal.react',
    'components/modals/project/ProjectInstanceLaunchModal.react',
    'components/modals/instance/InstanceReportModal.react',
    'components/modals/instance/InstanceImageModal.react'
  ],
  function (React, AppDispatcher, InstanceConstants, ProjectInstanceConstants, Instance, InstanceState, globals, context, URL, NotificationController, ProjectInstanceActions, stores, ModalHelpers, InstanceSuspendModal, InstanceDeleteModal, InstanceResumeModal, InstanceStopModal, InstanceStartModal, InstanceRebootModal, InstanceLaunchModal, ExplainInstanceDeleteConditionsModal, ProjectInstanceLaunchModal, InstanceReportModal, InstanceImageModal) {

    return {

      dispatch: function(actionType, payload, options){
        options = options || {};
        AppDispatcher.handleRouteAction({
          actionType: actionType,
          payload: payload,
          options: options
        });
      },

      // ------------------------
      // Standard CRUD Operations
      // ------------------------

      updateInstanceAttributes: function (instance, newAttributes) {
        var that = this;

        instance.set(newAttributes);
        that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

        instance.save({
          name: instance.get('name'),
          tags: instance.get('tags')
        }, {
          patch: true
        }).done(function () {
          //NotificationController.success(null, "Instance name and tags updated");
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        }).fail(function () {
          var message = "Error updating Instance " + instance.get('name') + ".";
          NotificationController.error(message);
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        });
      },

      addTagToInstance: function(tag, instance){
        var that = this;
        var instanceTags = instance.get('tags');
        instanceTags.push(tag.get('name'));

        instance.set({tags: instanceTags});
        that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

        instance.save({
          tags: instanceTags
        }, {
          patch: true
        }).done(function () {
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        }).fail(function () {
          NotificationController.error(null, "Error adding tag to Instance");
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        });
      },

      _terminate: function(payload, options){
        var instance = payload.instance;
        var project = payload.project;
        var that = this;

        that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});

        instance.destroy().done(function () {
          //NotificationController.success(null, 'Instance terminated');
          // poll until the instance is actually terminated
          //that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
          ProjectInstanceActions.removeInstanceFromProject(instance, project);

        }).fail(function (response) {
          NotificationController.error(null, 'Instance could not be terminated');
          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
        });
      },

      terminate: function(payload, options){
        var instance = payload.instance;
        var redirectUrl = payload.redirectUrl;
        var project = payload.project;
        var that = this;

        var attachedVolumes = stores.VolumeStore.getVolumesAttachedToInstance(instance);
        if(attachedVolumes.length > 0){
          var modal = ExplainInstanceDeleteConditionsModal({
            attachedVolumes: attachedVolumes,
            backdrop: 'static'
          });

          ModalHelpers.renderModal(modal, function(){});

        }else{
          var modal = InstanceDeleteModal({
            instance: payload.instance
          });

          ModalHelpers.renderModal(modal, function () {
            that._terminate(payload, options);
            if(redirectUrl) Backbone.history.navigate(redirectUrl, {trigger: true});
          });

        }
      },

      terminate_noModal: function(payload, options){
        this._terminate(payload, options);
      },

      // ----------------
      // Instance Actions
      // ----------------

      suspend: function (instance) {
        var that = this;

        var modal = InstanceSuspendModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "active - suspending"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.suspend({
           success: function (model) {
             //NotificationController.success(null, "Your instance is suspending...");

             var instanceState = new InstanceState({status_raw: "active - suspending"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be suspended");
           }
         });
        });
      },

      resume: function(instance){
        var that = this;

        var modal = InstanceResumeModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "suspended - resuming"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.resume({
           success: function (model) {
             //NotificationController.success(null, "Your instance is resuming...");

             var instanceState = new InstanceState({status_raw: "suspended - resuming"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be resumed");
           }
         });
        });

      },

      stop: function(instance){
        var that = this;

        var modal = InstanceStopModal();

        ModalHelpers.renderModal(modal, function () {

          var instanceState = new InstanceState({status_raw: "active - powering-off"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.stop({
           success: function (model) {
             //NotificationController.success(null, "Your instance is stopping...");

             var instanceState = new InstanceState({status_raw: "active - powering-off"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be stopped");
           }
         });
        })
      },

      start: function(instance){
        var that = this;

        var modal = InstanceStartModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "shutoff - powering-on"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.start({
           success: function (model) {
             //NotificationController.success(null, "Your instance is starting...");

             var instanceState = new InstanceState({status_raw: "shutoff - powering-on"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be started");
           }
         });
        })
      },

      reboot: function (instance) {
        var that = this;

        var modal = InstanceRebootModal();

        ModalHelpers.renderModal(modal, function () {
          // If user desires a hard reboot, need to pass an additional argument of reboot_type
          // action: "reboot"
          // reboot_type: "HARD"

          var instanceState = new InstanceState({status_raw: "active - rebooting"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.reboot({
           success: function (model) {
             var instanceState = new InstanceState({status_raw: "active - rebooting"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be rebooted");
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           }
         });
        });
      },

      launch: function(application){
        var that = this;

        var modal = InstanceLaunchModal({
          application: application
        });

        ModalHelpers.renderModal(modal, function (identity, machineId, sizeId, instanceName, project) {
          var instance = new Instance({
            identity: {
              id: identity.id,
              provider: identity.get('provider_id')
            },
            status: "build - scheduling"
          }, {parse: true});

          var params = {
            machine_alias: machineId,
            size_alias: sizeId,
            name: instanceName
          };

          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
          that.dispatch(ProjectInstanceConstants.ADD_PENDING_INSTANCE_TO_PROJECT, {
            instance: instance,
            project: project
          });

          instance.save(params, {
            success: function (model) {
              //NotificationController.success(null, 'Instance launching...');
              that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
              that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
              ProjectInstanceActions.addInstanceToProject(instance, project);
            },
            error: function (response) {
              NotificationController.error(null, 'Instance could not be launched');
              that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
            }
          });

          // Since this is triggered from the images page, navigate off
          // that page and back to the instance list so the user can see
          // their instance being created
          var redirectUrl = URL.projectResources(project, {relative: true});
          Backbone.history.navigate(redirectUrl, {trigger: true});
        })
      },

      requestImage: function(instance){
        var that = this;

        // instanceId, ipAddress
        var tags = stores.TagStore.getAll();

        var modal = InstanceImageModal({
          instance: instance,
          tags: tags
        });

        ModalHelpers.renderModal(modal, function (details) {
          var tagNames,
              requestData,
              providerId,
              identityId,
              requestUrl;

          tagNames = details.tags.map(function(tag){
            return tag.get('name');
          });

          requestData = {
            instance: instance.id,
            ip_address: instance.get("ip_address"),
            name: details.name,
            description: details.description,
            tags: tagNames,
            provider: details.providerId,
            software: details.software,
            exclude: details.filesToExclude,
            sys: details.systemFiles,
            vis: "public"
          };

          providerId = instance.getCreds().provider_id;
          identityId = instance.getCreds().identity_id;
          requestUrl = globals.API_ROOT + "/provider/" + providerId + "/identity/" + identityId + "/request_image" + globals.slash();

          $.ajax({
            url: requestUrl,
            type: 'POST',
            data: JSON.stringify(requestData),
            dataType: 'json',
            contentType: 'application/json',
            success: function (model) {
              NotificationController.info(null, "An image of your instance has been requested");
            },
            error: function (response, status, error) {
              NotificationController.error(null, "An image of your instance could not be requested");
            }
          });
        })
      },

      reportInstance: function(instance){
        var that = this;

        var modal = InstanceReportModal({
          instance: instance
        });

        ModalHelpers.renderModal(modal, function (reportInfo) {
          var profile = stores.ProfileStore.get(),
              username = profile.get('username'),
              reportUrl = globals.API_ROOT + "/email/support" + globals.slash(),
              problemText = "",
              reportData = {};

          if(reportInfo.problems){
            _.each(reportInfo.problems, function(problem){
              problemText = problemText + "  -" + problem + "\n";
            })
          }

          reportData = {
            username: username,
            message: "Instance IP: " + instance.get('ip_address') + "\n" +
                     "Instance ID: " + instance.id + "\n" +
                     "Provider ID: " + instance.get('identity').provider + "\n" +
                     "\n" +
                     "Problems" + "\n" +
                     problemText + "\n" +
                     "Details \n" +
                     reportInfo.details + "\n",
            subject: "Atmosphere Instance Report from " + username
          };

          $.ajax({
            url: reportUrl,
            type: 'POST',
            data: JSON.stringify(reportData),
            dataType: 'json',
            contentType: 'application/json',
            success: function (model) {
              NotificationController.info(null, "Your instance report has been sent to support.");
            },
            error: function (response, status, error) {
              NotificationController.error(null, "Your instance report could not be sent to support");
            }
          });
        })
      },

      createAndAddToProject: function(options){
        var project = options.project;
        var modal = React.createElement(ProjectInstanceLaunchModal);
        var that = this;

        ModalHelpers.renderModal(modal, function (identity, machineId, sizeId, instanceName) {
          var instance = new Instance({
            identity: {
              id: identity.id,
              provider: identity.get('provider_id')
            },
            status: "build - scheduling"
          }, {parse: true});

          var params = {
            machine_alias: machineId,
            size_alias: sizeId,
            name: instanceName
          };

          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
          that.dispatch(ProjectInstanceConstants.ADD_PENDING_INSTANCE_TO_PROJECT, {
            instance: instance,
            project: project
          });

          instance.save(params, {
            success: function (model) {
              //NotificationController.success(null, 'Instance launching...');
              that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
              that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
              ProjectInstanceActions.addInstanceToProject(instance, project);
            },
            error: function (response) {
              NotificationController.error(null, 'Instance could not be launched');
              that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
            }
          });
        })
      }

    };

  });
<commit_msg>bug fix, pass in object<commit_after>define(
  [
    'react',
    'dispatchers/AppDispatcher',
    'constants/InstanceConstants',
    'constants/ProjectInstanceConstants',
    'models/Instance',
    'models/InstanceState',
    'globals',
    'context',
    'url',
    'controllers/NotificationController',
    'actions/ProjectInstanceActions',
    'stores',

    // Modals
    'components/modals/ModalHelpers',
    'components/modals/instance/InstanceSuspendModal.react',
    'components/modals/instance/InstanceDeleteModal.react',
    'components/modals/instance/InstanceResumeModal.react',
    'components/modals/instance/InstanceStopModal.react',
    'components/modals/instance/InstanceStartModal.react',
    'components/modals/instance/InstanceRebootModal.react',
    'components/modals/instance/InstanceLaunchModal.react',
    'components/modals/instance/ExplainInstanceDeleteConditionsModal.react',
    'components/modals/project/ProjectInstanceLaunchModal.react',
    'components/modals/instance/InstanceReportModal.react',
    'components/modals/instance/InstanceImageModal.react'
  ],
  function (React, AppDispatcher, InstanceConstants, ProjectInstanceConstants, Instance, InstanceState, globals, context, URL, NotificationController, ProjectInstanceActions, stores, ModalHelpers, InstanceSuspendModal, InstanceDeleteModal, InstanceResumeModal, InstanceStopModal, InstanceStartModal, InstanceRebootModal, InstanceLaunchModal, ExplainInstanceDeleteConditionsModal, ProjectInstanceLaunchModal, InstanceReportModal, InstanceImageModal) {

    return {

      dispatch: function(actionType, payload, options){
        options = options || {};
        AppDispatcher.handleRouteAction({
          actionType: actionType,
          payload: payload,
          options: options
        });
      },

      // ------------------------
      // Standard CRUD Operations
      // ------------------------

      updateInstanceAttributes: function (instance, newAttributes) {
        var that = this;

        instance.set(newAttributes);
        that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

        instance.save({
          name: instance.get('name'),
          tags: instance.get('tags')
        }, {
          patch: true
        }).done(function () {
          //NotificationController.success(null, "Instance name and tags updated");
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        }).fail(function () {
          var message = "Error updating Instance " + instance.get('name') + ".";
          NotificationController.error(message);
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        });
      },

      addTagToInstance: function(tag, instance){
        var that = this;
        var instanceTags = instance.get('tags');
        instanceTags.push(tag.get('name'));

        instance.set({tags: instanceTags});
        that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

        instance.save({
          tags: instanceTags
        }, {
          patch: true
        }).done(function () {
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        }).fail(function () {
          NotificationController.error(null, "Error adding tag to Instance");
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
        });
      },

      _terminate: function(payload, options){
        var instance = payload.instance;
        var project = payload.project;
        var that = this;

        that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});

        instance.destroy().done(function () {
          //NotificationController.success(null, 'Instance terminated');
          // poll until the instance is actually terminated
          //that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
          ProjectInstanceActions.removeInstanceFromProject(instance, project);

        }).fail(function (response) {
          NotificationController.error(null, 'Instance could not be terminated');
          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
        });
      },

      terminate: function(payload, options){
        var instance = payload.instance;
        var redirectUrl = payload.redirectUrl;
        var project = payload.project;
        var that = this;

        var attachedVolumes = stores.VolumeStore.getVolumesAttachedToInstance(instance);
        if(attachedVolumes.length > 0){
          var modal = ExplainInstanceDeleteConditionsModal({
            attachedVolumes: attachedVolumes,
            backdrop: 'static'
          });

          ModalHelpers.renderModal(modal, function(){});

        }else{
          var modal = InstanceDeleteModal({
            instance: payload.instance
          });

          ModalHelpers.renderModal(modal, function () {
            that._terminate(payload, options);
            if(redirectUrl) Backbone.history.navigate(redirectUrl, {trigger: true});
          });

        }
      },

      terminate_noModal: function(payload, options){
        this._terminate(payload, options);
      },

      // ----------------
      // Instance Actions
      // ----------------

      suspend: function (instance) {
        var that = this;

        var modal = InstanceSuspendModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "active - suspending"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.suspend({
           success: function (model) {
             //NotificationController.success(null, "Your instance is suspending...");

             var instanceState = new InstanceState({status_raw: "active - suspending"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be suspended");
           }
         });
        });
      },

      resume: function(instance){
        var that = this;

        var modal = InstanceResumeModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "suspended - resuming"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.resume({
           success: function (model) {
             //NotificationController.success(null, "Your instance is resuming...");

             var instanceState = new InstanceState({status_raw: "suspended - resuming"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be resumed");
           }
         });
        });

      },

      stop: function(instance){
        var that = this;

        var modal = InstanceStopModal();

        ModalHelpers.renderModal(modal, function () {

          var instanceState = new InstanceState({status_raw: "active - powering-off"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.stop({
           success: function (model) {
             //NotificationController.success(null, "Your instance is stopping...");

             var instanceState = new InstanceState({status_raw: "active - powering-off"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be stopped");
           }
         });
        })
      },

      start: function(instance){
        var that = this;

        var modal = InstanceStartModal();

        ModalHelpers.renderModal(modal, function () {
          var instanceState = new InstanceState({status_raw: "shutoff - powering-on"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.start({
           success: function (model) {
             //NotificationController.success(null, "Your instance is starting...");

             var instanceState = new InstanceState({status_raw: "shutoff - powering-on"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be started");
           }
         });
        })
      },

      reboot: function (instance) {
        var that = this;

        var modal = InstanceRebootModal();

        ModalHelpers.renderModal(modal, function () {
          // If user desires a hard reboot, need to pass an additional argument of reboot_type
          // action: "reboot"
          // reboot_type: "HARD"

          var instanceState = new InstanceState({status_raw: "active - rebooting"});
          instance.set({state: instanceState});
          that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});

          instance.reboot({
           success: function (model) {
             var instanceState = new InstanceState({status_raw: "active - rebooting"});
             instance.set({state: instanceState});

             that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           },
           error: function (response) {
             NotificationController.error(null, "Your instance could not be rebooted");
             that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
           }
         });
        });
      },

      launch: function(application){
        var that = this;

        var modal = InstanceLaunchModal({
          application: application
        });

        ModalHelpers.renderModal(modal, function (identity, machineId, sizeId, instanceName, project) {
          var instance = new Instance({
            identity: {
              id: identity.id,
              provider: identity.get('provider_id')
            },
            status: "build - scheduling"
          }, {parse: true});

          var params = {
            machine_alias: machineId,
            size_alias: sizeId,
            name: instanceName
          };

          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
          that.dispatch(ProjectInstanceConstants.ADD_PENDING_INSTANCE_TO_PROJECT, {
            instance: instance,
            project: project
          });

          instance.save(params, {
            success: function (model) {
              //NotificationController.success(null, 'Instance launching...');
              that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
              that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
              ProjectInstanceActions.addInstanceToProject(instance, project);
            },
            error: function (response) {
              NotificationController.error(null, 'Instance could not be launched');
              that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
            }
          });

          // Since this is triggered from the images page, navigate off
          // that page and back to the instance list so the user can see
          // their instance being created
          var redirectUrl = URL.projectResources({project: project}, {relative: true});
          Backbone.history.navigate(redirectUrl, {trigger: true});
        })
      },

      requestImage: function(instance){
        var that = this;

        // instanceId, ipAddress
        var tags = stores.TagStore.getAll();

        var modal = InstanceImageModal({
          instance: instance,
          tags: tags
        });

        ModalHelpers.renderModal(modal, function (details) {
          var tagNames,
              requestData,
              providerId,
              identityId,
              requestUrl;

          tagNames = details.tags.map(function(tag){
            return tag.get('name');
          });

          requestData = {
            instance: instance.id,
            ip_address: instance.get("ip_address"),
            name: details.name,
            description: details.description,
            tags: tagNames,
            provider: details.providerId,
            software: details.software,
            exclude: details.filesToExclude,
            sys: details.systemFiles,
            vis: "public"
          };

          providerId = instance.getCreds().provider_id;
          identityId = instance.getCreds().identity_id;
          requestUrl = globals.API_ROOT + "/provider/" + providerId + "/identity/" + identityId + "/request_image" + globals.slash();

          $.ajax({
            url: requestUrl,
            type: 'POST',
            data: JSON.stringify(requestData),
            dataType: 'json',
            contentType: 'application/json',
            success: function (model) {
              NotificationController.info(null, "An image of your instance has been requested");
            },
            error: function (response, status, error) {
              NotificationController.error(null, "An image of your instance could not be requested");
            }
          });
        })
      },

      reportInstance: function(instance){
        var that = this;

        var modal = InstanceReportModal({
          instance: instance
        });

        ModalHelpers.renderModal(modal, function (reportInfo) {
          var profile = stores.ProfileStore.get(),
              username = profile.get('username'),
              reportUrl = globals.API_ROOT + "/email/support" + globals.slash(),
              problemText = "",
              reportData = {};

          if(reportInfo.problems){
            _.each(reportInfo.problems, function(problem){
              problemText = problemText + "  -" + problem + "\n";
            })
          }

          reportData = {
            username: username,
            message: "Instance IP: " + instance.get('ip_address') + "\n" +
                     "Instance ID: " + instance.id + "\n" +
                     "Provider ID: " + instance.get('identity').provider + "\n" +
                     "\n" +
                     "Problems" + "\n" +
                     problemText + "\n" +
                     "Details \n" +
                     reportInfo.details + "\n",
            subject: "Atmosphere Instance Report from " + username
          };

          $.ajax({
            url: reportUrl,
            type: 'POST',
            data: JSON.stringify(reportData),
            dataType: 'json',
            contentType: 'application/json',
            success: function (model) {
              NotificationController.info(null, "Your instance report has been sent to support.");
            },
            error: function (response, status, error) {
              NotificationController.error(null, "Your instance report could not be sent to support");
            }
          });
        })
      },

      createAndAddToProject: function(options){
        var project = options.project;
        var modal = React.createElement(ProjectInstanceLaunchModal);
        var that = this;

        ModalHelpers.renderModal(modal, function (identity, machineId, sizeId, instanceName) {
          var instance = new Instance({
            identity: {
              id: identity.id,
              provider: identity.get('provider_id')
            },
            status: "build - scheduling"
          }, {parse: true});

          var params = {
            machine_alias: machineId,
            size_alias: sizeId,
            name: instanceName
          };

          that.dispatch(InstanceConstants.ADD_INSTANCE, {instance: instance});
          that.dispatch(ProjectInstanceConstants.ADD_PENDING_INSTANCE_TO_PROJECT, {
            instance: instance,
            project: project
          });

          instance.save(params, {
            success: function (model) {
              //NotificationController.success(null, 'Instance launching...');
              that.dispatch(InstanceConstants.UPDATE_INSTANCE, {instance: instance});
              that.dispatch(InstanceConstants.POLL_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
              ProjectInstanceActions.addInstanceToProject(instance, project);
            },
            error: function (response) {
              NotificationController.error(null, 'Instance could not be launched');
              that.dispatch(InstanceConstants.REMOVE_INSTANCE, {instance: instance});
              that.dispatch(ProjectInstanceConstants.REMOVE_PENDING_INSTANCE_FROM_PROJECT, {
                instance: instance,
                project: project
              });
            }
          });
        })
      }

    };

  });
<|endoftext|>


<commit_before>/*globals $, d3, D3StackedBarChart, enrollment_chart_url */
(function() {
  "use strict";

  // private functions from
  // https://raw.github.com/mbostock/d3/master/src/layout/stack.js
  // for re-ordering data
  function d3_layout_stackReduceSum(d) {
    return d.reduce(d3_layout_stackSum, 0);
  }

  function d3_layout_stackSum(p, d) {
    return p + d[1];
  }

  // similar to python's any
  function any(arr){
    return arr.reduce(function(a, b){ return a || b; });
  }

  var Chart = D3StackedBarChart.extend({
    initData: function(new_data){
      // override to process data differently
      this.originalData = new_data;  // hold onto this
      var nested_dataset = d3.nest()
          .key(function(d) { return d.metric; })
          .entries(new_data);
      var stackOrder,
          stack = d3.layout.stack()
          .offset("zero")  // default
          .order(function(data) {
            var n = data.length,
                sums = data.map(d3_layout_stackReduceSum);
            stackOrder = d3.range(n).sort(function(a, b) { return sums[b] - sums[a]; });
            return stackOrder;
          })
          .values(function(d) { return d.values; })
          .x(function(d) { return d.year; })  // this doesn't seem to work
          .y(function(d) { return d.value; });
      var stacked_dataset = stack(nested_dataset);
      // actually sort the data too so colors are applied in sort order
      var return_data = [];
      for (var i = 0; i < stackOrder.length; i++){
        return_data.push(stacked_dataset[stackOrder[i]]);
      }
      // slower but terser alternative
      // return stackOrder.map(function(x){ return stacked_dataset[x]; });
      return return_data;
    },
    getXScale: function(){
      // override to pull year range from original data
      var self = this,
          data = this.originalData;
      var yearRange = d3.extent(data, function(d) { return d.year; });
      return d3.scale.ordinal()
          .domain(d3.range(yearRange[0], yearRange[1] + 1))
          .rangeRoundBands([0, self.options.plot_box.w], 0.1, 0.1);
    },
    getMaxY: function(data){
      // pull max from original raw data
      return d3.max(this.originalData, function(d) { return d.enrollment; });
    },
    getLayerFillStyle: function(){
      var self = this,
          n = self._data.length ;
      return function(d, i) { return self.options.color(i / n); };
    },
    getX: function(){
      // override to use `d.year` instead of `d.x`
      var self = this;
      return function(d) { return self.x_scale(d.year); };
    },
    getY: function(){
      // override to convert percent to value
      var self = this;
      return function(d) { return self.y_scale((d.y0 + d.y) * d.enrollment / 100.0); };
    },
    getH: function(){
      // override to convert percent to value
      var self = this;
      return function(d) { return self.height_scale(d.y * d.enrollment / 100.0); };
    },
    getBarWidth: function(){
      // override to get `len_x` a different way TODO can probably port this back into super
      // bar_width is an outer width
      return this.options.plot_box.w / this.x_scale.domain().length;
    },
    getBars: function(){
      // override to fix different data structure, array of objects instead of array of arrays
      var self = this;
      return this._layers.selectAll("rect.bar")
        .data(function(d) { return d.values; })
        .enter().append("rect")
          .attr("class", "bar")
          .attr("width", self.bar_width * 0.9)
          .attr("x", self.x)
          .attr("y", self.options.plot_box.h)
          .attr("height", 0)
          .transition()
            .delay(function(d, i) { return i * 10; })
            .attr("y", self.y)
            .attr("height", self.h);
    },

    legendActivateSeries: function(idx, targetElem){
      var self = this, filtered, targeted,
          $target = $(targetElem).parent(),
          $set = $target.parent().children(':not(.reset)'),
          reset = function(){
            self.rescale(self.getYDomain());  // TODO cache original outside this method
            self._layers.selectAll("rect.bar")
              .transition()
                .attr("y", self.y)
                .attr("height", self.h);
          },
          addResetCtl = function(){
            if ($target.parent().children('.reset').length) { return; }
            var $resetCtl = $('
× Reset
');
            $resetCtl.click(function(){
              $set.filter('.active').removeClass('active');
              self._layers.attr("display", null);  // XXX
              reset();
              $resetCtl.hide(500, function(){ $resetCtl.remove(); });
            });
            $resetCtl.find('a').click(function(e){ e.preventDefault(); });
            $target.parent().append($resetCtl);
          };

      // Interaction and UI
      // TODO allow multiple elements to be active
      var MODE; // DELETEME
      if ($target.hasClass('active')){
        $set.filter('.active').removeClass('active');
        MODE = "blur";
      } else {
        $set.filter('.active').removeClass('active');
        $target.addClass('active');
        addResetCtl();
        MODE = "focus";
      }

      // determine which layers to show
      // activeMask is the mask of what series are active: [true, false, false, ...]
      var activeMask = $set.map(function(i, x){ return $(x).hasClass('active'); }).toArray().reverse();
      if (!any(activeMask)){
        activeMask = activeMask.map(function(){ return true; });
      }

      // sort layers into two groups and toggle visiblity
      targeted = this._layers.filter(function(d, i){ return activeMask[i]; });
      targeted.attr("display", null);
      filtered = this._layers.filter(function(d, i){ return !activeMask[i]; });
      filtered.attr("display", "none");

      // redraw
      // TODO show multiple layers, this involves re-calculating everything
      // which is expensive
      if (MODE == "blur"){
        reset();
      } else {
        var max = d3.max(targeted.data()[0].values.map(function(a){ return a.value * a.enrollment / 100; }));
        self.rescale([0, max]);
        targeted.selectAll("rect.bar")
          .transition()
            .attr("y", function(d, i){
              // send thee to the bottom of the sea!
              return self.options.plot_box.h - self.h(d, i);
            })
            .attr("height", self.h);
      }
      if (self.yAxis){
        self.svg.select('.y.axis').transition().call(self.yAxis);
      }
    },

    getLegendSeriesTitle: function(d, i){
      return d.values[0].race.substr(2);
    }
  });

  var options = {
    'color': d3.interpolateRgb("#445", "#ccd"),
    // 'color': d3.scale.pow().exponent(0.75).range(["#445", "#ccd"]),
    'tooltip': function() { return this.__data__.y + " " + this.__data__.race; },
    'legendElem': $("#enrollment .legend")
  };

  new Chart($("#enrollment .chart"), enrollment_chart_url, options);
})();
<commit_msg>update: crank colors of race chart way up<commit_after>/*globals $, d3, D3StackedBarChart, enrollment_chart_url */
(function() {
  "use strict";

  // private functions from
  // https://raw.github.com/mbostock/d3/master/src/layout/stack.js
  // for re-ordering data
  function d3_layout_stackReduceSum(d) {
    return d.reduce(d3_layout_stackSum, 0);
  }

  function d3_layout_stackSum(p, d) {
    return p + d[1];
  }

  // similar to python's any
  function any(arr){
    return arr.reduce(function(a, b){ return a || b; });
  }

  var Chart = D3StackedBarChart.extend({
    initData: function(new_data){
      // override to process data differently
      this.originalData = new_data;  // hold onto this
      var nested_dataset = d3.nest()
          .key(function(d) { return d.metric; })
          .entries(new_data);
      var stackOrder,
          stack = d3.layout.stack()
          .offset("zero")  // default
          .order(function(data) {
            var n = data.length,
                sums = data.map(d3_layout_stackReduceSum);
            stackOrder = d3.range(n).sort(function(a, b) { return sums[b] - sums[a]; });
            return stackOrder;
          })
          .values(function(d) { return d.values; })
          .x(function(d) { return d.year; })  // this doesn't seem to work
          .y(function(d) { return d.value; });
      var stacked_dataset = stack(nested_dataset);
      // actually sort the data too so colors are applied in sort order
      var return_data = [];
      for (var i = 0; i < stackOrder.length; i++){
        return_data.push(stacked_dataset[stackOrder[i]]);
      }
      // slower but terser alternative
      // return stackOrder.map(function(x){ return stacked_dataset[x]; });
      return return_data;
    },
    getXScale: function(){
      // override to pull year range from original data
      var self = this,
          data = this.originalData;
      var yearRange = d3.extent(data, function(d) { return d.year; });
      return d3.scale.ordinal()
          .domain(d3.range(yearRange[0], yearRange[1] + 1))
          .rangeRoundBands([0, self.options.plot_box.w], 0.1, 0.1);
    },
    getMaxY: function(data){
      // pull max from original raw data
      return d3.max(this.originalData, function(d) { return d.enrollment; });
    },
    getLayerFillStyle: function(){
      var self = this,
          n = self._data.length ;
      return function(d, i) { return self.options.color(i / n); };
    },
    getX: function(){
      // override to use `d.year` instead of `d.x`
      var self = this;
      return function(d) { return self.x_scale(d.year); };
    },
    getY: function(){
      // override to convert percent to value
      var self = this;
      return function(d) { return self.y_scale((d.y0 + d.y) * d.enrollment / 100.0); };
    },
    getH: function(){
      // override to convert percent to value
      var self = this;
      return function(d) { return self.height_scale(d.y * d.enrollment / 100.0); };
    },
    getBarWidth: function(){
      // override to get `len_x` a different way TODO can probably port this back into super
      // bar_width is an outer width
      return this.options.plot_box.w / this.x_scale.domain().length;
    },
    getBars: function(){
      // override to fix different data structure, array of objects instead of array of arrays
      var self = this;
      return this._layers.selectAll("rect.bar")
        .data(function(d) { return d.values; })
        .enter().append("rect")
          .attr("class", "bar")
          .attr("width", self.bar_width * 0.9)
          .attr("x", self.x)
          .attr("y", self.options.plot_box.h)
          .attr("height", 0)
          .transition()
            .delay(function(d, i) { return i * 10; })
            .attr("y", self.y)
            .attr("height", self.h);
    },

    legendActivateSeries: function(idx, targetElem){
      var self = this, filtered, targeted,
          $target = $(targetElem).parent(),
          $set = $target.parent().children(':not(.reset)'),
          reset = function(){
            self.rescale(self.getYDomain());  // TODO cache original outside this method
            self._layers.selectAll("rect.bar")
              .transition()
                .attr("y", self.y)
                .attr("height", self.h);
          },
          addResetCtl = function(){
            if ($target.parent().children('.reset').length) { return; }
            var $resetCtl = $('
× Reset
');
            $resetCtl.click(function(){
              $set.filter('.active').removeClass('active');
              self._layers.attr("display", null);  // XXX
              reset();
              $resetCtl.hide(500, function(){ $resetCtl.remove(); });
            });
            $resetCtl.find('a').click(function(e){ e.preventDefault(); });
            $target.parent().append($resetCtl);
          };

      // Interaction and UI
      // TODO allow multiple elements to be active
      var MODE; // DELETEME
      if ($target.hasClass('active')){
        $set.filter('.active').removeClass('active');
        MODE = "blur";
      } else {
        $set.filter('.active').removeClass('active');
        $target.addClass('active');
        addResetCtl();
        MODE = "focus";
      }

      // determine which layers to show
      // activeMask is the mask of what series are active: [true, false, false, ...]
      var activeMask = $set.map(function(i, x){ return $(x).hasClass('active'); }).toArray().reverse();
      if (!any(activeMask)){
        activeMask = activeMask.map(function(){ return true; });
      }

      // sort layers into two groups and toggle visiblity
      targeted = this._layers.filter(function(d, i){ return activeMask[i]; });
      targeted.attr("display", null);
      filtered = this._layers.filter(function(d, i){ return !activeMask[i]; });
      filtered.attr("display", "none");

      // redraw
      // TODO show multiple layers, this involves re-calculating everything
      // which is expensive
      if (MODE == "blur"){
        reset();
      } else {
        var max = d3.max(targeted.data()[0].values.map(function(a){ return a.value * a.enrollment / 100; }));
        self.rescale([0, max]);
        targeted.selectAll("rect.bar")
          .transition()
            .attr("y", function(d, i){
              // send thee to the bottom of the sea!
              return self.options.plot_box.h - self.h(d, i);
            })
            .attr("height", self.h);
      }
      if (self.yAxis){
        self.svg.select('.y.axis').transition().call(self.yAxis);
      }
    },

    getLegendSeriesTitle: function(d, i){
      return d.values[0].race.substr(2);
    }
  });

  var options = {
    'color': d3.interpolateRgb("#001", "#eef"),  // does not actually reach maxima
    // 'color': d3.scale.pow().exponent(0.75).range(["#445", "#ccd"]),
    'tooltip': function() { return this.__data__.y + " " + this.__data__.race; },
    'legendElem': $("#enrollment .legend")
  };

  new Chart($("#enrollment .chart"), enrollment_chart_url, options);
})();
<|endoftext|>


<commit_before>const _ = require('underscore');
const moment = require('moment');
const CoreView = require('backbone/core-view');
const navigateThroughRouter = require('builder/helpers/navigate-through-router');
const pluralizeString = require('dashboard/helpers/pluralize');
const LikesView = require('dashboard/components/likes/like-view');
const EditableDescription = require('dashboard/components/editable-fields/editable-description');
const EditableTags = require('dashboard/components/editable-fields/editable-tags');
const SyncView = require('dashboard/views/dashboard/sync-dataset/sync-dataset-view.js');
const TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
const ChangePrivacyView = require('dashboard/views/dashboard/dialogs/change-privacy/change-privacy-view');
const Utils = require('builder/helpers/utils');
const template = require('./datasets-item.tpl');
const checkAndBuildOpts = require('builder/helpers/required-opts');

const REQUIRED_OPTS = [
  'configModel',
  'userModel',
  'routerModel',
  'modals'
];

/**
 * View representing an item in the list under datasets route.
 */
module.exports = CoreView.extend({
  tagName: 'li',
  className: 'DatasetsList-item DatasetsList-item--selectable',

  events: {
    'click .js-tag-link': navigateThroughRouter,
    'click .js-privacy': '_openPrivacyDialog',
    'click .js-sync': '_openSyncDialog',
    'click': '_selectDataset'
  },

  initialize: function (options) {
    checkAndBuildOpts(options, REQUIRED_OPTS, this);
    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    const vis = this.model;
    const table = vis.tableMetadata();
    const tags = vis.get('tags') || [];

    let url = vis.viewUrl(this._userModel);
    url = (this._routerModel.model.get('liked') && !vis.permission.hasAccess(this._userModel)) ? url.public() : url.edit();

    const templateData = {
      isRaster: vis.get('kind') === 'raster',
      geometryType: table.statsGeomColumnTypes().length > 0 ? table.statsGeomColumnTypes()[0] : '',
      title: vis.get('name'),
      datasetUrl: encodeURI(url),
      isOwner: vis.permission.isOwner(this._userModel),
      owner: vis.permission.owner.renderData(this._userModel),
      showPermissionIndicator: !vis.permission.hasWriteAccess(this._userModel),
      privacy: vis.get('privacy').toLowerCase(),
      likes: vis.get('likes') || 0,
      timeDiff: moment(vis.get('updated_at')).fromNow(),
      tags,
      tagsCount: tags.length,
      router: this._routerModel,
      maxTagsToShow: 3,
      rowCount: undefined,
      datasetSize: undefined,
      syncStatus: undefined,
      syncRanAt: undefined,
      fromExternalSource: ''
    };

    const rowCount = table.get('row_count');
    if (rowCount >= 0) {
      templateData.rowCount = rowCount < 10000 ? Utils.formatNumber(rowCount) : Utils.readizableNumber(rowCount);
      templateData.pluralizedRows = pluralizeString('Row', rowCount);
    }

    if (!_.isEmpty(vis.get('synchronization'))) {
      templateData.fromExternalSource = vis.get('synchronization').from_external_source;
    }

    const datasetSize = table.get('size');
    if (datasetSize >= 0) {
      templateData.datasetSize = Utils.readablizeBytes(datasetSize, true);
    }

    if (!_.isEmpty(vis.get('synchronization'))) {
      templateData.syncRanAt = moment(vis.get('synchronization').ran_at || new Date()).fromNow();
      templateData.syncStatus = vis.get('synchronization').state;
    }

    this.$el.html(template(templateData));

    this._renderDescription();
    this._renderTags();
    this._renderLikesIndicator();
    this._renderTooltips();

    // Item selected?
    this.$el[ vis.get('selected') ? 'addClass' : 'removeClass' ]('is--selected');

    return this;
  },

  _initBinds: function () {
    this.model.on('change', this.render, this);
  },

  _renderDescription: function () {
    const isOwner = this.model.permission.isOwner(this._userModel);
    const view = new EditableDescription({
      el: this.$('.js-item-description'),
      model: this.model,
      editable: isOwner && this._userModel.hasCreateDatasetsFeature()
    });
    this.addView(view.render());
  },

  _renderTags: function () {
    const isOwner = this.model.permission.isOwner(this._userModel);
    const view = new EditableTags({
      el: this.$('.js-item-tags'),
      model: this.model,
      routerModel: this._routerModel,
      editable: isOwner && this._userModel.hasCreateDatasetsFeature()
    });
    this.addView(view.render());
  },

  _renderLikesIndicator: function () {
    const view = new LikesView({
      model: this.model.like
    });
    this.$('.js-likes-indicator').replaceWith(view.render().el);
    this.addView(view);
  },

  _renderTooltips: function () {
    const synchronization = this.model.get('synchronization');

    if (!_.isEmpty(synchronization)) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.js-syncInfo')
        })
      );
    }

    if (!this.model.permission.isOwner(this._userModel)) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.UserAvatar')
        })
      );
    }

    if (!_.isEmpty(synchronization) && synchronization.from_external_source) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.js-public')
        })
      );
    }
  },

  _openPrivacyDialog: function (ev) {
    this.killEvent(ev);

    this._modals.create(modalModel => {
      return new ChangePrivacyView({
        visModel: this.model,
        userModel: this._userModel,
        configModel: this._configModel,
        modals: this._modals,
        modalModel
      });
    });
  },

  _openSyncDialog: function (ev) {
    this.killEvent(ev);

    this._modals.create(modalModel => {
      const view = new SyncView({
        enter_to_confirm: true,
        table: this.model.tableMetadata(),
        modalModel
      });

      // Force render of this item after changing sync settings
      const originalOK = view.ok;
      view.ok = () => {
        originalOK.apply(view, arguments);
        this.model.fetch(); // to force a re-render due to possible changed sync settings
      };

      return view;
    });
  },

  _selectDataset: function (ev) {
    // Let links use default behaviour
    if (ev.target.tagName !== 'A') {
      this.killEvent(ev);
      this.model.set('selected', !this.model.get('selected'));
    }
  }
});
<commit_msg>Show dash instead of 0 if updatedAt is in the last 24h<commit_after>const _ = require('underscore');
const moment = require('moment');
const CoreView = require('backbone/core-view');
const navigateThroughRouter = require('builder/helpers/navigate-through-router');
const pluralizeString = require('dashboard/helpers/pluralize');
const LikesView = require('dashboard/components/likes/like-view');
const EditableDescription = require('dashboard/components/editable-fields/editable-description');
const EditableTags = require('dashboard/components/editable-fields/editable-tags');
const SyncView = require('dashboard/views/dashboard/sync-dataset/sync-dataset-view.js');
const TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
const ChangePrivacyView = require('dashboard/views/dashboard/dialogs/change-privacy/change-privacy-view');
const Utils = require('builder/helpers/utils');
const template = require('./datasets-item.tpl');
const checkAndBuildOpts = require('builder/helpers/required-opts');

const REQUIRED_OPTS = [
  'configModel',
  'userModel',
  'routerModel',
  'modals'
];

/**
 * View representing an item in the list under datasets route.
 */
module.exports = CoreView.extend({
  tagName: 'li',
  className: 'DatasetsList-item DatasetsList-item--selectable',

  events: {
    'click .js-tag-link': navigateThroughRouter,
    'click .js-privacy': '_openPrivacyDialog',
    'click .js-sync': '_openSyncDialog',
    'click': '_selectDataset'
  },

  initialize: function (options) {
    checkAndBuildOpts(options, REQUIRED_OPTS, this);
    this._initBinds();
  },

  render: function () {
    this.clearSubViews();
    const vis = this.model;
    const table = vis.tableMetadata();
    const tags = vis.get('tags') || [];
    const updatedAt = moment(vis.get('updated_at'));

    let url = vis.viewUrl(this._userModel);
    url = (this._routerModel.model.get('liked') && !vis.permission.hasAccess(this._userModel)) ? url.public() : url.edit();

    const templateData = {
      isRaster: vis.get('kind') === 'raster',
      geometryType: table.statsGeomColumnTypes().length > 0 ? table.statsGeomColumnTypes()[0] : '',
      title: vis.get('name'),
      datasetUrl: encodeURI(url),
      isOwner: vis.permission.isOwner(this._userModel),
      owner: vis.permission.owner.renderData(this._userModel),
      showPermissionIndicator: !vis.permission.hasWriteAccess(this._userModel),
      privacy: vis.get('privacy').toLowerCase(),
      likes: vis.get('likes') || 0,
      timeDiff: updatedAt.fromNow(),
      tags,
      tagsCount: tags.length,
      router: this._routerModel,
      maxTagsToShow: 3,
      rowCount: undefined,
      datasetSize: undefined,
      syncStatus: undefined,
      syncRanAt: undefined,
      fromExternalSource: ''
    };

    const rowCount = table.get('row_count');
    if (rowCount >= 0) {
      templateData.rowCount = rowCount < 10000 ? Utils.formatNumber(rowCount) : Utils.readizableNumber(rowCount);
      templateData.pluralizedRows = pluralizeString('Row', rowCount);

      if (rowCount === 0) {
        const last24h = moment().subtract(1, 'day');

        if (updatedAt.isAfter(last24h)) {
          templateData.rowCount = '-';
        }
      }
    }

    if (!_.isEmpty(vis.get('synchronization'))) {
      templateData.fromExternalSource = vis.get('synchronization').from_external_source;
    }

    const datasetSize = table.get('size');
    if (datasetSize >= 0) {
      templateData.datasetSize = Utils.readablizeBytes(datasetSize, true);
    }

    if (!_.isEmpty(vis.get('synchronization'))) {
      templateData.syncRanAt = moment(vis.get('synchronization').ran_at || new Date()).fromNow();
      templateData.syncStatus = vis.get('synchronization').state;
    }

    this.$el.html(template(templateData));

    this._renderDescription();
    this._renderTags();
    this._renderLikesIndicator();
    this._renderTooltips();

    // Item selected?
    this.$el[ vis.get('selected') ? 'addClass' : 'removeClass' ]('is--selected');

    return this;
  },

  _initBinds: function () {
    this.model.on('change', this.render, this);
  },

  _renderDescription: function () {
    const isOwner = this.model.permission.isOwner(this._userModel);
    const view = new EditableDescription({
      el: this.$('.js-item-description'),
      model: this.model,
      editable: isOwner && this._userModel.hasCreateDatasetsFeature()
    });
    this.addView(view.render());
  },

  _renderTags: function () {
    const isOwner = this.model.permission.isOwner(this._userModel);
    const view = new EditableTags({
      el: this.$('.js-item-tags'),
      model: this.model,
      routerModel: this._routerModel,
      editable: isOwner && this._userModel.hasCreateDatasetsFeature()
    });
    this.addView(view.render());
  },

  _renderLikesIndicator: function () {
    const view = new LikesView({
      model: this.model.like
    });
    this.$('.js-likes-indicator').replaceWith(view.render().el);
    this.addView(view);
  },

  _renderTooltips: function () {
    const synchronization = this.model.get('synchronization');

    if (!_.isEmpty(synchronization)) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.js-syncInfo')
        })
      );
    }

    if (!this.model.permission.isOwner(this._userModel)) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.UserAvatar')
        })
      );
    }

    if (!_.isEmpty(synchronization) && synchronization.from_external_source) {
      this.addView(
        new TipsyTooltipView({
          el: this.$('.js-public')
        })
      );
    }
  },

  _openPrivacyDialog: function (ev) {
    this.killEvent(ev);

    this._modals.create(modalModel => {
      return new ChangePrivacyView({
        visModel: this.model,
        userModel: this._userModel,
        configModel: this._configModel,
        modals: this._modals,
        modalModel
      });
    });
  },

  _openSyncDialog: function (ev) {
    this.killEvent(ev);

    this._modals.create(modalModel => {
      const view = new SyncView({
        enter_to_confirm: true,
        table: this.model.tableMetadata(),
        modalModel
      });

      // Force render of this item after changing sync settings
      const originalOK = view.ok;
      view.ok = () => {
        originalOK.apply(view, arguments);
        this.model.fetch(); // to force a re-render due to possible changed sync settings
      };

      return view;
    });
  },

  _selectDataset: function (ev) {
    // Let links use default behaviour
    if (ev.target.tagName !== 'A') {
      this.killEvent(ev);
      this.model.set('selected', !this.model.get('selected'));
    }
  }
});
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import {withRouter} from 'react-router';
import {connect} from 'react-redux';
import ReactTooltip from 'react-tooltip';
import _ from 'lodash';
import DataSection from '../components/DataSection';
import ValuesSection from '../components/ValuesSection';
import * as kapacitorActionCreators from '../actions/view';
import * as queryActionCreators from '../../chronograf/actions/view';
import {bindActionCreators} from 'redux';
import selectStatement from 'src/chronograf/utils/influxql/select';
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
const RefreshingLineGraph = AutoRefresh(LineGraph);
import {getKapacitor, getKapacitorConfig} from 'shared/apis/index';
import Dropdown from 'shared/components/Dropdown';
import {ALERTS, DEFAULT_RULE_ID} from 'src/kapacitor/constants';
import {createRule, editRule} from 'src/kapacitor/apis';

export const KapacitorRulePage = React.createClass({
  propTypes: {
    source: PropTypes.shape({
      links: PropTypes.shape({
        proxy: PropTypes.string.isRequired,
        self: PropTypes.string.isRequired,
      }),
    }),
    addFlashMessage: PropTypes.func,
    rules: PropTypes.shape({}).isRequired,
    queryConfigs: PropTypes.shape({}).isRequired,
    kapacitorActions: PropTypes.shape({
      loadDefaultRule: PropTypes.func.isRequired,
      fetchRule: PropTypes.func.isRequired,
      chooseTrigger: PropTypes.func.isRequired,
      updateRuleValues: PropTypes.func.isRequired,
      updateMessage: PropTypes.func.isRequired,
      updateAlerts: PropTypes.func.isRequired,
      updateRuleName: PropTypes.func.isRequired,
    }).isRequired,
    queryActions: PropTypes.shape({}).isRequired,
    params: PropTypes.shape({
      ruleID: PropTypes.string,
    }).isRequired,
    router: PropTypes.shape({
      push: PropTypes.func.isRequired,
    }).isRequired,
  },

  getInitialState() {
    return {
      enabledAlerts: [],
      isEditingName: false,
    };
  },

  isEditing() {
    const {params} = this.props;
    return params.ruleID && params.ruleID !== 'new';
  },

  componentDidMount() {
    const {ruleID} = this.props.params;
    if (this.isEditing()) {
      this.props.kapacitorActions.fetchRule(this.props.source, ruleID);
    } else {
      this.props.kapacitorActions.loadDefaultRule();
    }

    getKapacitor(this.props.source).then((kapacitor) => {
      getKapacitorConfig(kapacitor).then(({data: {sections}}) => {
        const enabledAlerts = Object.keys(sections).filter((section) => {
          return _.get(sections, [section, 'elements', '0', 'options', 'enabled'], false) && ALERTS.includes(section);
        });
        this.setState({kapacitor, enabledAlerts});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem communicating with Kapacitor`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `We couldn't find a configured Kapacitor for this source`});
      });
    });
  },

  handleSave() {
    const {queryConfigs, rules, params, source} = this.props;
    if (this.isEditing()) { // If we are editing updated rule if not, create a new one
      const rule = rules[params.ruleID];
      const updatedRule = Object.assign({}, rule, {
        query: queryConfigs[rule.queryID],
      });
      editRule(updatedRule).then(() => {
        this.props.addFlashMessage({type: 'success', text: `Rule successfully updated!`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem updating the rule`});
      });
    } else {
      const rule = rules[DEFAULT_RULE_ID];
      const newRule = Object.assign({}, rule, {
        query: queryConfigs[rule.queryID],
      });
      delete newRule.queryID;
      createRule(this.state.kapacitor, newRule).then(() => {
        this.props.router.push(`/sources/${source.id}/alert-rules`);
        this.props.addFlashMessage({type: 'success', text: `Rule successfully created`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem creating the rule`});
      });
    }
  },

  handleChooseAlert(item) {
    this.props.kapacitorActions.updateAlerts(item.ruleID, [item.text]);
  },

  handleEditName(e, rule) {
    if (e.key === 'Enter') {
      const {updateRuleName} = this.props.kapacitorActions;
      const name = this.ruleName.value;
      updateRuleName(rule.id, name);
      this.toggleEditName();
    }

    if (e.key === 'Escape') {
      this.toggleEditName();
    }
  },

  handleEditNameBlur(rule) {
    const {updateRuleName} = this.props.kapacitorActions;
    const name = this.ruleName.value;
    updateRuleName(rule.id, name);
    this.toggleEditName();
  },

  toggleEditName() {
    this.setState({isEditingName: !this.state.isEditingName});
  },

  render() {
    const {rules, queryConfigs, params} = this.props;
    const rule = this.isEditing() ? rules[params.ruleID] : rules[DEFAULT_RULE_ID];
    const query = rule && queryConfigs[rule.queryID];

    if (!query) {
      return

;
    }

    return (

              {this.renderEditName(rule)}

              <button className="btn btn-success btn-sm" onClick={this.handleSave}>Save Rule</button>

                  {this.renderDataSection(query)}
                  {this.renderValuesSection(rule)}

                    {this.renderGraph(query, this.createUnderlayCallback(rule))}

                  {this.renderMessageSection(rule)}

    );
  },

  renderEditName(rule) {
    if (!this.state.isEditingName) {
      return (

          {rule.name}

      );
    }

    return (
      <input
        className="enterprise-header__editing"
        autoFocus={true}
        defaultValue={rule.name}
        ref={r => this.ruleName = r}
        onKeyDown={(e) => this.handleEditName(e, rule)}
        onBlur={() => this.handleEditNameBlur(rule)}
        placeholder="Name your rule"
      />
    );
  },

  renderGraph(query, underlayCallback) {
    const autoRefreshMs = 30000;
    const queryText = selectStatement({lower: 'now() - 15m'}, query);
    const queries = [{host: this.props.source.links.proxy, text: queryText}];
    const kapacitorLineColors = ["#4ED8A0"];

    if (!queryText) {
      return (

Select a Metric to preview on a graph

      );
    }
    return (
      <RefreshingLineGraph
        queries={queries}
        autoRefresh={autoRefreshMs}
        underlayCallback={underlayCallback}
        isGraphFilled={false}
        overrideLineColors={kapacitorLineColors}
      />
    );
  },

  renderDataSection(query) {
    return (

Select a Metric

          <DataSection source={this.props.source} query={query} actions={this.props.queryActions} />

    );
  },

  renderValuesSection(rule) {
    const {chooseTrigger, updateRuleValues} = this.props.kapacitorActions;
    return (

Values

          <ValuesSection rule={rule} query={this.props.queryConfigs[rule.queryID]} onChooseTrigger={chooseTrigger} onUpdateValues={updateRuleValues} />

    );
  },

  renderMessageSection(rule) {
    const alerts = this.state.enabledAlerts.map((text) => {
      return {text, ruleID: rule.id};
    });

    return (

Alert Message

          <textarea className="alert-message" ref={(r) => this.message = r} onChange={() => this.handleMessageChange(rule)} placeholder="Compose your alert message here"/>

Templates:

            {{ .ID }}
            {{ .Name }}
            {{ .TaskName }}
            <code data-tip="Concatenation of all group-by tags of the form [key=value,]+. If no groupBy is performed equal to literal "nil"">{{ .Group }}
            <code data-tip="Map of tags. Use {{ index .Tags "key" }} to get a specific tag value">{{ .Tags }}
            <code data-tip="Alert Level, one of: INFOWARNINGCRITICAL">{{ .Level }}
            <code data-tip="Map of fields. Use {{ index .Fields "key" }} to get a specific field value">{{ .Fields }}
            {{ .Time }}
            <ReactTooltip effect="solid" html={true} offset={{top: -4}} class="influx-tooltip kapacitor-tooltip" />

Send this Alert to:

            <Dropdown className="size-256" selected={rule.alerts[0] || 'Choose an Endpoint'} items={alerts} onChoose={this.handleChooseAlert} />

    );
  },

  handleMessageChange(rule) {
    this.props.kapacitorActions.updateMessage(rule.id, this.message.value);
  },

  createUnderlayCallback(rule) {
    return (canvas, area, dygraph) => {
      if (rule.trigger !== 'threshold') {
        return;
      }

      const theOnePercent = 0.01;
      let highlightStart = 0;
      let highlightEnd = 0;

      switch (rule.values.operator) {
        case 'equal to or greater':
        case 'greater than': {
          highlightStart = rule.values.value;
          highlightEnd = dygraph.yAxisRange()[1];
          break;
        }

        case 'equal to or less than':
        case 'less than': {
          highlightStart = dygraph.yAxisRange()[0];
          highlightEnd = rule.values.value;
          break;
        }

        case 'not equal to':
        case 'equal to': {
          const width = (theOnePercent) * (dygraph.yAxisRange()[1] - dygraph.yAxisRange()[0]);
          highlightStart = +rule.values.value - width;
          highlightEnd = +rule.values.value + width;
          break;
        }
      }

      const bottom = dygraph.toDomYCoord(highlightStart);
      const top = dygraph.toDomYCoord(highlightEnd);

      canvas.fillStyle = 'rgba(78,216,160,0.3)';
      canvas.fillRect(area.x, top, area.w, bottom - top);
    };
  },

});

function mapStateToProps(state) {
  return {
    rules: state.rules,
    queryConfigs: state.queryConfigs,
  };
}

function mapDispatchToProps(dispatch) {
  return {
    kapacitorActions: bindActionCreators(kapacitorActionCreators, dispatch),
    queryActions: bindActionCreators(queryActionCreators, dispatch),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(KapacitorRulePage));
<commit_msg>Display the rule message<commit_after>import React, {PropTypes} from 'react';
import {withRouter} from 'react-router';
import {connect} from 'react-redux';
import ReactTooltip from 'react-tooltip';
import _ from 'lodash';
import DataSection from '../components/DataSection';
import ValuesSection from '../components/ValuesSection';
import * as kapacitorActionCreators from '../actions/view';
import * as queryActionCreators from '../../chronograf/actions/view';
import {bindActionCreators} from 'redux';
import selectStatement from 'src/chronograf/utils/influxql/select';
import AutoRefresh from 'shared/components/AutoRefresh';
import LineGraph from 'shared/components/LineGraph';
const RefreshingLineGraph = AutoRefresh(LineGraph);
import {getKapacitor, getKapacitorConfig} from 'shared/apis/index';
import Dropdown from 'shared/components/Dropdown';
import {ALERTS, DEFAULT_RULE_ID} from 'src/kapacitor/constants';
import {createRule, editRule} from 'src/kapacitor/apis';

export const KapacitorRulePage = React.createClass({
  propTypes: {
    source: PropTypes.shape({
      links: PropTypes.shape({
        proxy: PropTypes.string.isRequired,
        self: PropTypes.string.isRequired,
      }),
    }),
    addFlashMessage: PropTypes.func,
    rules: PropTypes.shape({}).isRequired,
    queryConfigs: PropTypes.shape({}).isRequired,
    kapacitorActions: PropTypes.shape({
      loadDefaultRule: PropTypes.func.isRequired,
      fetchRule: PropTypes.func.isRequired,
      chooseTrigger: PropTypes.func.isRequired,
      updateRuleValues: PropTypes.func.isRequired,
      updateMessage: PropTypes.func.isRequired,
      updateAlerts: PropTypes.func.isRequired,
      updateRuleName: PropTypes.func.isRequired,
    }).isRequired,
    queryActions: PropTypes.shape({}).isRequired,
    params: PropTypes.shape({
      ruleID: PropTypes.string,
    }).isRequired,
    router: PropTypes.shape({
      push: PropTypes.func.isRequired,
    }).isRequired,
  },

  getInitialState() {
    return {
      enabledAlerts: [],
      isEditingName: false,
    };
  },

  isEditing() {
    const {params} = this.props;
    return params.ruleID && params.ruleID !== 'new';
  },

  componentDidMount() {
    const {ruleID} = this.props.params;
    if (this.isEditing()) {
      this.props.kapacitorActions.fetchRule(this.props.source, ruleID);
    } else {
      this.props.kapacitorActions.loadDefaultRule();
    }

    getKapacitor(this.props.source).then((kapacitor) => {
      getKapacitorConfig(kapacitor).then(({data: {sections}}) => {
        const enabledAlerts = Object.keys(sections).filter((section) => {
          return _.get(sections, [section, 'elements', '0', 'options', 'enabled'], false) && ALERTS.includes(section);
        });
        this.setState({kapacitor, enabledAlerts});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem communicating with Kapacitor`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `We couldn't find a configured Kapacitor for this source`});
      });
    });
  },

  handleSave() {
    const {queryConfigs, rules, params, source} = this.props;
    if (this.isEditing()) { // If we are editing updated rule if not, create a new one
      const rule = rules[params.ruleID];
      const updatedRule = Object.assign({}, rule, {
        query: queryConfigs[rule.queryID],
      });
      editRule(updatedRule).then(() => {
        this.props.addFlashMessage({type: 'success', text: `Rule successfully updated!`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem updating the rule`});
      });
    } else {
      const rule = rules[DEFAULT_RULE_ID];
      const newRule = Object.assign({}, rule, {
        query: queryConfigs[rule.queryID],
      });
      delete newRule.queryID;
      createRule(this.state.kapacitor, newRule).then(() => {
        this.props.router.push(`/sources/${source.id}/alert-rules`);
        this.props.addFlashMessage({type: 'success', text: `Rule successfully created`});
      }).catch(() => {
        this.props.addFlashMessage({type: 'error', text: `There was a problem creating the rule`});
      });
    }
  },

  handleChooseAlert(item) {
    this.props.kapacitorActions.updateAlerts(item.ruleID, [item.text]);
  },

  handleEditName(e, rule) {
    if (e.key === 'Enter') {
      const {updateRuleName} = this.props.kapacitorActions;
      const name = this.ruleName.value;
      updateRuleName(rule.id, name);
      this.toggleEditName();
    }

    if (e.key === 'Escape') {
      this.toggleEditName();
    }
  },

  handleEditNameBlur(rule) {
    const {updateRuleName} = this.props.kapacitorActions;
    const name = this.ruleName.value;
    updateRuleName(rule.id, name);
    this.toggleEditName();
  },

  toggleEditName() {
    this.setState({isEditingName: !this.state.isEditingName});
  },

  render() {
    const {rules, queryConfigs, params} = this.props;
    const rule = this.isEditing() ? rules[params.ruleID] : rules[DEFAULT_RULE_ID];
    const query = rule && queryConfigs[rule.queryID];

    if (!query) {
      return

;
    }

    return (

              {this.renderEditName(rule)}

              <button className="btn btn-success btn-sm" onClick={this.handleSave}>Save Rule</button>

                  {this.renderDataSection(query)}
                  {this.renderValuesSection(rule)}

                    {this.renderGraph(query, this.createUnderlayCallback(rule))}

                  {this.renderMessageSection(rule)}

    );
  },

  renderEditName(rule) {
    if (!this.state.isEditingName) {
      return (

          {rule.name}

      );
    }

    return (
      <input
        className="enterprise-header__editing"
        autoFocus={true}
        defaultValue={rule.name}
        ref={r => this.ruleName = r}
        onKeyDown={(e) => this.handleEditName(e, rule)}
        onBlur={() => this.handleEditNameBlur(rule)}
        placeholder="Name your rule"
      />
    );
  },

  renderGraph(query, underlayCallback) {
    const autoRefreshMs = 30000;
    const queryText = selectStatement({lower: 'now() - 15m'}, query);
    const queries = [{host: this.props.source.links.proxy, text: queryText}];
    const kapacitorLineColors = ["#4ED8A0"];

    if (!queryText) {
      return (

Select a Metric to preview on a graph

      );
    }
    return (
      <RefreshingLineGraph
        queries={queries}
        autoRefresh={autoRefreshMs}
        underlayCallback={underlayCallback}
        isGraphFilled={false}
        overrideLineColors={kapacitorLineColors}
      />
    );
  },

  renderDataSection(query) {
    return (

Select a Metric

          <DataSection source={this.props.source} query={query} actions={this.props.queryActions} />

    );
  },

  renderValuesSection(rule) {
    const {chooseTrigger, updateRuleValues} = this.props.kapacitorActions;
    return (

Values

          <ValuesSection rule={rule} query={this.props.queryConfigs[rule.queryID]} onChooseTrigger={chooseTrigger} onUpdateValues={updateRuleValues} />

    );
  },

  renderMessageSection(rule) {
    const alerts = this.state.enabledAlerts.map((text) => {
      return {text, ruleID: rule.id};
    });

    return (

Alert Message

          <textarea className="alert-message" ref={(r) => this.message = r} value={rule.message} onChange={() => this.handleMessageChange(rule)} placeholder="Compose your alert message here"/>

Templates:

            {{ .ID }}
            {{ .Name }}
            {{ .TaskName }}
            <code data-tip="Concatenation of all group-by tags of the form [key=value,]+. If no groupBy is performed equal to literal "nil"">{{ .Group }}
            <code data-tip="Map of tags. Use {{ index .Tags "key" }} to get a specific tag value">{{ .Tags }}
            <code data-tip="Alert Level, one of: INFOWARNINGCRITICAL">{{ .Level }}
            <code data-tip="Map of fields. Use {{ index .Fields "key" }} to get a specific field value">{{ .Fields }}
            {{ .Time }}
            <ReactTooltip effect="solid" html={true} offset={{top: -4}} class="influx-tooltip kapacitor-tooltip" />

Send this Alert to:

            <Dropdown className="size-256" selected={rule.alerts[0] || 'Choose an Endpoint'} items={alerts} onChoose={this.handleChooseAlert} />

    );
  },

  handleMessageChange(rule) {
    this.props.kapacitorActions.updateMessage(rule.id, this.message.value);
  },

  createUnderlayCallback(rule) {
    return (canvas, area, dygraph) => {
      if (rule.trigger !== 'threshold') {
        return;
      }

      const theOnePercent = 0.01;
      let highlightStart = 0;
      let highlightEnd = 0;

      switch (rule.values.operator) {
        case 'equal to or greater':
        case 'greater than': {
          highlightStart = rule.values.value;
          highlightEnd = dygraph.yAxisRange()[1];
          break;
        }

        case 'equal to or less than':
        case 'less than': {
          highlightStart = dygraph.yAxisRange()[0];
          highlightEnd = rule.values.value;
          break;
        }

        case 'not equal to':
        case 'equal to': {
          const width = (theOnePercent) * (dygraph.yAxisRange()[1] - dygraph.yAxisRange()[0]);
          highlightStart = +rule.values.value - width;
          highlightEnd = +rule.values.value + width;
          break;
        }
      }

      const bottom = dygraph.toDomYCoord(highlightStart);
      const top = dygraph.toDomYCoord(highlightEnd);

      canvas.fillStyle = 'rgba(78,216,160,0.3)';
      canvas.fillRect(area.x, top, area.w, bottom - top);
    };
  },

});

function mapStateToProps(state) {
  return {
    rules: state.rules,
    queryConfigs: state.queryConfigs,
  };
}

function mapDispatchToProps(dispatch) {
  return {
    kapacitorActions: bindActionCreators(kapacitorActionCreators, dispatch),
    queryActions: bindActionCreators(queryActionCreators, dispatch),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(KapacitorRulePage));
<|endoftext|>


<commit_before>'use strict';

// VARIABLES //

var invalid;
var test;

// MAIN //

// Create our test cases:
invalid = [];

test = {
	'code': [
		'/**',
		'* Beep boop.',
		'*',
		'* ~~~javascript',
		'* y = x;',
		'* ~~~',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'errors': [
		{
			'message': 'Fenced code should use ` as a marker',
			'type': null
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Beep boop.',
		'*',
		'* ~~~javascript',
		'* y = x;',
		'* ~~~',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'options': [ '`' ],
	'errors': [
		{
			'message': 'Fenced code should use ` as a marker',
			'type': null
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Beep _boop_.',
		'*',
		'* ```javascript',
		'* y = x;',
		'* ```',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'options': [ '~' ],
	'errors': [
		{
			'message': 'Fenced code should use ~ as a marker',
			'type': null
		}
	]
};
invalid.push( test );

// EXPORTS //

module.exports = invalid;
<commit_msg>Add invalid test using `consistent` option value<commit_after>'use strict';

// VARIABLES //

var invalid;
var test;

// MAIN //

// Create our test cases:
invalid = [];

test = {
	'code': [
		'/**',
		'* Beep boop.',
		'*',
		'* ~~~javascript',
		'* y = x;',
		'* ~~~',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'errors': [
		{
			'message': 'Fenced code should use ` as a marker',
			'type': null
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Beep boop.',
		'*',
		'* ~~~javascript',
		'* y = x;',
		'* ~~~',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'options': [ '`' ],
	'errors': [
		{
			'message': 'Fenced code should use ` as a marker',
			'type': null
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Beep _boop_.',
		'*',
		'* ```javascript',
		'* y = x;',
		'* ```',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'options': [ '~' ],
	'errors': [
		{
			'message': 'Fenced code should use ~ as a marker',
			'type': null
		}
	]
};
invalid.push( test );

test = {
	'code': [
		'/**',
		'* Beep _boop_.',
		'*',
		'* ~~~javascript',
		'* y = x;',
		'* ~~~',
		'*',
		'* ```javascript',
		'* y = x;',
		'* ```',
		'*/',
		'function beep() {',
		'    console.log( "boop" );',
		'}'
	].join( '\n' ),
	'options': [ 'consistent' ],
	'errors': [
		{
			'message': 'Fenced code should use ~ as a marker',
			'type': null
		}
	]
};
invalid.push( test );

// EXPORTS //

module.exports = invalid;
<|endoftext|>


<commit_before>describe('the stack spec', () => {
  it('shows the infrastructure works', () => {
    true.should.be.true();
  });

  const makeStack = () => {
    return {
      isEmpty: () => true,
      size: () => 0
    };
  };

  const stack = {
    isEmpty: () => true,
    size: () => 0
  };

  describe('a stack should', () => {
    it('start empty', () => {
      stack.isEmpty().should.be.true();
    });

    it('start with stack size 0', () => {
      stack.size().should.equal(0);
    });

    it('not be empty when pushed');

    it('leave stack size 1 when pushed');

    it('leave stack empty when pushed and popped');

    it('leave stack size 0 when pushed and popped');

    it('overflow');

    it('underflow');

    it('pop the same one pushed');

    it('pop the same two pushed');

    it('accept only positive capacity');
  });
}
);
<commit_msg>refactor toward next test<commit_after>describe('the stack spec', () => {
  it('shows the infrastructure works', () => {
    true.should.be.true();
  });

  const makeStack = () => {
    return {
      isEmpty: () => true,
      size: () => 0
    };
  };

  let stack = {
    isEmpty: () => true,
    size: () => 0
  };

  describe('a stack should', () => {
    it('start empty', () => {
      stack.isEmpty().should.be.true();
    });

    it('start with stack size 0', () => {
      stack.size().should.equal(0);
    });

    it('not be empty when pushed');

    it('leave stack size 1 when pushed');

    it('leave stack empty when pushed and popped');

    it('leave stack size 0 when pushed and popped');

    it('overflow');

    it('underflow');

    it('pop the same one pushed');

    it('pop the same two pushed');

    it('accept only positive capacity');
  });
}
);
<|endoftext|>


<commit_before>var FacebookStrategy = require('passport-facebook').Strategy;
var db = require('../db');
var localServices = require('../config/environment/thirdPartyServices');
// var client = require('./facebookAuthInfo.js');

module.exports = function(passport){

  // Facebook strategy is the primary way for a user to log in the service
  passport.use(new FacebookStrategy({

    // Uses configuration file to set Facebook auth parameters
  clientID: config.facebook.id,
  clientSecret: config.facebook.secret,
  callbackURL: config.facebook.callback

   }, function(token, refreshToken, profile, done){
    // console.log(profile.id);

    db.User.find({where: {'facebook_id' : profile.id}})
      .then(function(user){
        if(!user){

          // Creates a new user which extracts the Facbook ID and username
          // Facebook ID is referenced so that users are not able to sign up for more than one account
          // console.log('creating new user');
          db.User.create({
            username: profile.name.givenName,
            facebook_id: profile.id
          })
          .then(function(newUser){

            // console.log(newUser, '----------------------');
            // null value represents that there were no errors
            return done(null, newUser);
          });
        } else {

          // Current user exists and create currentUser object
          var currentUser = {
            username: user.username,
            table_id: user.id
          };

           // null value represents that there were no errors
          return done(null, currentUser);
        }
      });
    }
  ));
};<commit_msg>Fixed config file for authcontroller<commit_after>var FacebookStrategy = require('passport-facebook').Strategy;
var db = require('../db');
var config = require('../config/environment');

module.exports = function(passport){

  // Facebook strategy is the primary way for a user to log in the service
  passport.use(new FacebookStrategy({

    // Uses configuration file to set Facebook auth parameters
  clientID: config.facebook.id,
  clientSecret: config.facebook.secret,
  callbackURL: config.facebook.callback

   }, function(token, refreshToken, profile, done){
    // console.log(profile.id);

    db.User.find({where: {'facebook_id' : profile.id}})
      .then(function(user){
        if(!user){
          // Creates a new user which extracts the Facbook ID and username
          // Facebook ID is referenced so that users are not able to sign up for more than one account
          // console.log('creating new user');

          db.User.create({
            username: profile.name.givenName,
            facebook_id: profile.id
          })
          .then(function(newUser){
            // console.log(newUser, '----------------------');
            // null value represents that there were no errors
            return done(null, newUser);
          });
        } else {

          // Current user exists and create currentUser object

          var currentUser = {
            username: user.username,
            table_id: user.id
          };
           // null value represents that there were no errors
          return done(null, currentUser);
        }
      });
    }
  ));
};<|endoftext|>


<commit_before>var socketio = require('socket.io');

function configureSocketIo(server, repo) {
    var io = socketio.listen(server);

    // If this is a raspberry pi viewer.
    var viewerMode = process.argv[2] ? process.argv[2].toLowerCase() : 'none';
    if(viewerMode === 'omx' || viewerMode == '-omx') {
        console.log('omxplayer viewer enabled');
        var omxViewer = require('./omx-viewer')();
    }

    io.on('connection', function(socket) {
        console.log('connection made');
        socket.on('disconnect', function() {
            console.log('user disconnected');
        });
        socket.on('select video', function(args) {
            console.log('select video');
            console.log(args);
            //socket.broadcast.emit('select video');
            var videoDetails = repo.loadVideoDetails(args.videoId);
            socket.broadcast.emit('video selected', videoDetails);
            if(omxViewer) {
                omxViewer.videoSelected(videoDetails);
                socket.broadcast.emit('video playing');
            }
            console.log('video selected');
        });
        socket.on('play video', function(args) {
            console.log('play video');
            socket.broadcast.emit('play video');
            if(omxViewer) {
                omxViewer.play(args);
                socket.broadcast.emit('video playing');
            }
        });
        socket.on('video playing', function(args) {
            console.log('video playing');
            socket.broadcast.emit('video playing');
        });
        socket.on('pause video', function(args) {
            console.log('pause video');
            socket.broadcast.emit('pause video');
            if(omxViewer) {
                omxViewer.pause(args);
                socket.broadcast.emit('video paused');
            }
        });
        socket.on('video paused', function(args) {
            console.log('video paused');
            socket.broadcast.emit('video paused');
        });
        socket.on('stop video', function(args) {
            console.log('stop video');
            socket.broadcast.emit('stop video');
            if(omxViewer) {
                omxViewer.stop(args);
                socket.broadcast.emit('video stopped');
            }
        });
        socket.on('video stopped', function(args) {
            console.log('video stopped');
            socket.broadcast.emit('video stopped');
        });
        socket.on('seek video', function(args) {
            console.log('seek video');
            console.log(args);
            socket.broadcast.emit('seek video', args);
            if(omxViewer) {
                omxViewer.seek(args);
                socket.broadcast.emit('video seeked');
            }
        });
        socket.on('video seeked', function(args) {
            console.log('video seeked');
            socket.broadcast.emit('video seeked');
        });
        socket.on('jump video', function(args) {
            console.log('jump video');
            console.log(args);
            socket.broadcast.emit('jump video', args);
            if(omxViewer) {
                omxViewer.jump(args);
                socket.broadcast.emit('video jumped');
            }
        });
        socket.on('video jumped', function(args) {
            console.log('video jumped');
            socket.broadcast.emit('video jumped');
        });
    });
}

module.exports = configureSocketIo;<commit_msg>Fix object is not a function error in omxviewer<commit_after>var socketio = require('socket.io');

function configureSocketIo(server, repo) {
    var io = socketio.listen(server);

    // If this is a raspberry pi viewer.
    var viewerMode = process.argv[2] ? process.argv[2].toLowerCase() : 'none';
    if(viewerMode === 'omx' || viewerMode == '-omx') {
        console.log('omxplayer viewer enabled');
        var omxViewer = require('./omx-viewer');
    }

    io.on('connection', function(socket) {
        console.log('connection made');
        socket.on('disconnect', function() {
            console.log('user disconnected');
        });
        socket.on('select video', function(args) {
            console.log('select video');
            console.log(args);
            //socket.broadcast.emit('select video');
            var videoDetails = repo.loadVideoDetails(args.videoId);
            socket.broadcast.emit('video selected', videoDetails);
            if(omxViewer) {
                omxViewer.videoSelected(videoDetails);
                socket.broadcast.emit('video playing');
            }
            console.log('video selected');
        });
        socket.on('play video', function(args) {
            console.log('play video');
            socket.broadcast.emit('play video');
            if(omxViewer) {
                omxViewer.play(args);
                socket.broadcast.emit('video playing');
            }
        });
        socket.on('video playing', function(args) {
            console.log('video playing');
            socket.broadcast.emit('video playing');
        });
        socket.on('pause video', function(args) {
            console.log('pause video');
            socket.broadcast.emit('pause video');
            if(omxViewer) {
                omxViewer.pause(args);
                socket.broadcast.emit('video paused');
            }
        });
        socket.on('video paused', function(args) {
            console.log('video paused');
            socket.broadcast.emit('video paused');
        });
        socket.on('stop video', function(args) {
            console.log('stop video');
            socket.broadcast.emit('stop video');
            if(omxViewer) {
                omxViewer.stop(args);
                socket.broadcast.emit('video stopped');
            }
        });
        socket.on('video stopped', function(args) {
            console.log('video stopped');
            socket.broadcast.emit('video stopped');
        });
        socket.on('seek video', function(args) {
            console.log('seek video');
            console.log(args);
            socket.broadcast.emit('seek video', args);
            if(omxViewer) {
                omxViewer.seek(args);
                socket.broadcast.emit('video seeked');
            }
        });
        socket.on('video seeked', function(args) {
            console.log('video seeked');
            socket.broadcast.emit('video seeked');
        });
        socket.on('jump video', function(args) {
            console.log('jump video');
            console.log(args);
            socket.broadcast.emit('jump video', args);
            if(omxViewer) {
                omxViewer.jump(args);
                socket.broadcast.emit('video jumped');
            }
        });
        socket.on('video jumped', function(args) {
            console.log('video jumped');
            socket.broadcast.emit('video jumped');
        });
    });
}

module.exports = configureSocketIo;<|endoftext|>