<commit_before>define(
// require.js dependency injection
[
  './module'
],

// require.js module scope
function(module) {
  'use strict';

  module.controller(

    // controller name
    'MainCtrl',

    // dependencies injection
    ['ProgressConfig', 'MenuConfig', '$scope',

  // controller definition
  function(progressConfig, menu, $scope) {

    $scope.appLoaded = 'ok';

    //--- @begin: loading progressbar config
    progressConfig.eventListeners();
    progressConfig.color('#428bca');
    //--- @end: loading progressbar config

    //--- @begin: menu items
    menu.addMenuItem('Home', '');
    menu.addMenuItem('Boorkmarks', 'bookmarks');
    menu.addMenuItem('About', 'about');
    //--- @end: menu items

  }]);

});<commit_msg>angular-ee swt : menu label review<commit_after>define(
// require.js dependency injection
[
  './module'
],

// require.js module scope
function(module) {
  'use strict';

  module.controller(

    // controller name
    'MainCtrl',

    // dependencies injection
    ['ProgressConfig', 'MenuConfig', '$scope',

  // controller definition
  function(progressConfig, menu, $scope) {

    $scope.appLoaded = 'ok';

    //--- @begin: loading progressbar config
    progressConfig.eventListeners();
    progressConfig.color('#428bca');
    //--- @end: loading progressbar config

    //--- @begin: menu items
    menu.addMenuItem('Home', '');
    menu.addMenuItem('Bookmarks', 'bookmarks');
    menu.addMenuItem('About', 'about');
    //--- @end: menu items

  }]);

});<|endoftext|>


<commit_before>import * as React from "react"
import { Link } from "gatsby"

// styles
const pageStyles = {
  color: "#232129",
  padding: "96px",
  fontFamily: "-apple-system, Roboto, sans-serif, serif",
}
const headingStyles = {
  marginTop: 0,
  marginBottom: 64,
  maxWidth: 320,
}

const paragraphStyles = {
  marginBottom: 48,
}
const codeStyles = {
  color: "#8A6534",
  padding: 4,
  backgroundColor: "#FFF4DB",
  fontSize: "1.25rem",
  borderRadius: 4,
}

// markup
const IndexPage = () => {
  return (

      <title>Not found</title>

Page not found

        Sorry{" "}

          😔
        {" "}
        we couldn’t find what you were looking for.

        {process.env.NODE_ENV === "development" ? (
          <>

              Try creating a page in src/pages/.

          </>
        ) : null}

        <Link to="/">Go home</Link>.

  )
}

export default IndexPage
<commit_msg>Silly fix to make page component clearer (#28694)<commit_after>import * as React from "react"
import { Link } from "gatsby"

// styles
const pageStyles = {
  color: "#232129",
  padding: "96px",
  fontFamily: "-apple-system, Roboto, sans-serif, serif",
}
const headingStyles = {
  marginTop: 0,
  marginBottom: 64,
  maxWidth: 320,
}

const paragraphStyles = {
  marginBottom: 48,
}
const codeStyles = {
  color: "#8A6534",
  padding: 4,
  backgroundColor: "#FFF4DB",
  fontSize: "1.25rem",
  borderRadius: 4,
}

// markup
const NotFoundPage = () => {
  return (

      <title>Not found</title>

Page not found

        Sorry{" "}

          😔
        {" "}
        we couldn’t find what you were looking for.

        {process.env.NODE_ENV === "development" ? (
          <>

            Try creating a page in src/pages/.

          </>
        ) : null}

        <Link to="/">Go home</Link>.

  )
}

export default NotFoundPage
<|endoftext|>


<commit_before>var GRAFT_URLS = {
    // JS
    "http://persistent.info/web-experiments/static-resource-grafting/site/script.js":
        "http://localhost:8000/grafted/script.js",
    "http://persistent.info/web-experiments/static-resource-grafting/site/styles.css":
        "http://localhost:8000/grafted/styles.css"
};

chrome.webRequest.onBeforeRequest.addListener(
    function(info) {
        var graftedUrl = GRAFT_URLS[info.url];
        if (graftedUrl) {
            return {redirectUrl: graftedUrl};
        }
    },
    {
        urls: Object.keys(GRAFT_URLS)
    },
    ["blocking"]);

chrome.webRequest.onHeadersReceived.addListener(
    function(details) {
        var strippedCsp = false;
        for (var i = 0; i < details.responseHeaders.length; i++) {
            var header = details.responseHeaders[i];
            if (header.name.toLowerCase() === "content-security-policy") {
                header.value = '';
                strippedCsp = true;
                break;
            }
        }

        if (strippedCsp) {
            return {responseHeaders: details.responseHeaders};
        }
    },
    {
        types: ["main_frame"],
        urls: [
            "http://persistent.info/web-experiments/static-resource-grafting/*"
        ]
    },
    ["blocking", "responseHeaders"]);

<commit_msg>Small grafting extension style cleanups.<commit_after>var GRAFT_URLS = {
    "http://persistent.info/web-experiments/static-resource-grafting/site/script.js":
        "http://localhost:8000/grafted/script.js",
    "http://persistent.info/web-experiments/static-resource-grafting/site/styles.css":
        "http://localhost:8000/grafted/styles.css"
};

chrome.webRequest.onBeforeRequest.addListener(
    function(info) {
        var graftedUrl = GRAFT_URLS[info.url];
        if (graftedUrl) {
            return {redirectUrl: graftedUrl};
        }
    },
    {urls: Object.keys(GRAFT_URLS)},
    ["blocking"]);

chrome.webRequest.onHeadersReceived.addListener(
    function(details) {
        var strippedCsp = false;
        for (var i = 0; i < details.responseHeaders.length; i++) {
            var header = details.responseHeaders[i];
            if (header.name.toLowerCase() === "content-security-policy") {
                header.value = "";
                strippedCsp = true;
                break;
            }
        }

        if (strippedCsp) {
            return {responseHeaders: details.responseHeaders};
        }
    },
    {
        types: ["main_frame"],
        urls: ["http://persistent.info/web-experiments/static-resource-grafting/*"]
    },
    ["blocking", "responseHeaders"]);

<|endoftext|>


<commit_before>Mailpile.bulk_actions_update_ui = function() {
  if (Mailpile.messages_cache.length === 1) {
    var message = '1 ' + $('#bulk-actions-message').data('bulk_selected');
    $('#bulk-actions-message').html(message);
    Mailpile.show_bulk_actions($('.bulk-actions').find('li.hide'));
  }
  else if (Mailpile.messages_cache.length < 1) {
    var message = $('#bulk-actions-message').data('bulk_selected_none');
    $('#bulk-actions-message').html(message);
    Mailpile.hide_bulk_actions($('.bulk-actions').find('li.hide'));
	}
	else {
	  $('#bulk-actions-selected-count').html(Mailpile.messages_cache.length);
  }
};

Mailpile.bulk_action_read = function() {
  Mailpile.API.tag_post({ del: 'new', mid: Mailpile.messages_cache }, function(result) {
    $.each(Mailpile.messages_cache, function(key, mid) {
      $('#pile-message-' + mid).removeClass('in_new');
    });
  });
};

Mailpile.bulk_action_unread = function() {
  Mailpile.API.tag_post({ add: 'new', mid: Mailpile.messages_cache }, function(result) {
    $.each(Mailpile.messages_cache, function(key, mid) {
      $('#pile-message-' + mid).addClass('in_new');
    });
  });
};

Mailpile.bulk_action_select_target = function() {
  var target = this.search_target;
  var mid = $('#pile-results tr').eq(target).data('mid');
  Mailpile.bulk_cache_add('messages_cache', mid);
  $('#pile-message-' + mid).addClass('result-on').find('input[type=checkbox]').prop('checked',true);
  this.bulk_actions_update_ui();
  return true;
};

Mailpile.bulk_action_deselect_target = function() {
  var target = this.search_target;
  var mid = $('#pile-results tr').eq(target).data('mid');
  Mailpile.bulk_cache_remove('messages_cache', mid);
  $('#pile-message-' + mid).removeClass('result-on').find('input[type=checkbox]').prop('checked', false);
  this.bulk_actions_update_ui();
  return true;
};

Mailpile.bulk_action_toggle_target = function() {
  var target = this.search_target;
  if (target === 'none') {
    var mid = $('#pile-results tr').eq(0).data('mid');
    Mailpile.pile_action_select($('#pile-message-' + mid));
  } else {
    var mid = $('#pile-results tr').eq(target).data('mid');
    if ($('#pile-message-' + mid).find('input[type=checkbox]').is(':checked')) {
      Mailpile.bulk_action_deselect_target();
    } else {
      Mailpile.bulk_action_select_target();
    }
  }
  return true;
};

Mailpile.bulk_action_select_all = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    Mailpile.pile_action_select($(this).parent().parent());
  });
  $("#pile-select-all-action").attr('checked','checked');
};

Mailpile.bulk_action_select_none = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    Mailpile.pile_action_unselect($(this).parent().parent());
  });
  $("#pile-select-all-action").removeAttr('checked');
};

Mailpile.bulk_action_select_invert = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    if ($(this).is(":checked")) {
      Mailpile.pile_action_unselect($(this).parent().parent());
    } else {
      Mailpile.pile_action_select($(this).parent().parent());
    }
  });
  if (this['messages_cache'].length == checkboxes.length) {
    $("#pile-select-all-action").attr('checked','checked');
  } else if (this['messages_cache'].length == 0) {
    $("#pile-select-all-action").removeAttr('checked');
  }
};

Mailpile.bulk_action_select_between = function() {
  alert('FIXME: Will select messages between two points');
};

Mailpile.bulk_action_selection_up = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  if (this['messages_cache'].length == 0) {
    Mailpile.pile_action_select($(checkboxes[checkboxes.length-1]).parent().parent());
    return;
  }
  $.each(checkboxes, function() {
    if ($(this).parent().parent().next().children().children("input").is(":checked")) {
      Mailpile.pile_action_select($(this).parent().parent());
    } else {
      Mailpile.pile_action_unselect($(this).parent().parent());
    }
  });
};

Mailpile.bulk_action_selection_down = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  if (this['messages_cache'].length == 0) {
    Mailpile.pile_action_select($(checkboxes[0]).parent().parent());
    return;
  }
  $(checkboxes.get().reverse()).each(function() {
    if ($(this).parent().parent().prev().children().children("input").is(":checked")) {
      Mailpile.pile_action_select($(this).parent().parent());
    } else {
      Mailpile.pile_action_unselect($(this).parent().parent());
    }
  });
};

Mailpile.open_selected_thread = function() {
  if (this['messages_cache'].length == 1) {
    $("#pile-results input[type=checkbox]:checked").each(function() {
      window.location.href = $(this).parent().parent()
                                    .children(".subject")
                                    .children("a").attr("href");
    });
  }
};<commit_msg>Oops, forgot about unselecting space hotkey<commit_after>Mailpile.bulk_actions_update_ui = function() {
  if (Mailpile.messages_cache.length === 1) {
    var message = '1 ' + $('#bulk-actions-message').data('bulk_selected');
    $('#bulk-actions-message').html(message);
    Mailpile.show_bulk_actions($('.bulk-actions').find('li.hide'));
  }
  else if (Mailpile.messages_cache.length < 1) {
    var message = $('#bulk-actions-message').data('bulk_selected_none');
    $('#bulk-actions-message').html(message);
    Mailpile.hide_bulk_actions($('.bulk-actions').find('li.hide'));
	}
	else {
	  $('#bulk-actions-selected-count').html(Mailpile.messages_cache.length);
  }
};

Mailpile.bulk_action_read = function() {
  Mailpile.API.tag_post({ del: 'new', mid: Mailpile.messages_cache }, function(result) {
    $.each(Mailpile.messages_cache, function(key, mid) {
      $('#pile-message-' + mid).removeClass('in_new');
    });
  });
};

Mailpile.bulk_action_unread = function() {
  Mailpile.API.tag_post({ add: 'new', mid: Mailpile.messages_cache }, function(result) {
    $.each(Mailpile.messages_cache, function(key, mid) {
      $('#pile-message-' + mid).addClass('in_new');
    });
  });
};

Mailpile.bulk_action_select_target = function() {
  var target = this.search_target;
  var mid = $('#pile-results tr').eq(target).data('mid');
  Mailpile.bulk_cache_add('messages_cache', mid);
  $('#pile-message-' + mid).addClass('result-on').find('input[type=checkbox]').prop('checked',true);
  this.bulk_actions_update_ui();
  return true;
};

Mailpile.bulk_action_deselect_target = function() {
  var target = this.search_target;
  var mid = $('#pile-results tr').eq(target).data('mid');
  Mailpile.bulk_cache_remove('messages_cache', mid);
  $('#pile-message-' + mid).removeClass('result-on').find('input[type=checkbox]').prop('checked', false);
  this.bulk_actions_update_ui();
  return true;
};

Mailpile.bulk_action_toggle_target = function() {
  var target = this.search_target;
  // No Target
  if (target === 'none') {
    var mid = $('#pile-results tr').eq(0).data('mid');
    if ($('#pile-message-' + mid).find('input[type=checkbox]').is(':checked')) {
      Mailpile.pile_action_unselect($('#pile-message-' + mid));
    } else {
      Mailpile.pile_action_select($('#pile-message-' + mid));
    }
  }
  // Has Target
  else {
    var mid = $('#pile-results tr').eq(target).data('mid');
    if ($('#pile-message-' + mid).find('input[type=checkbox]').is(':checked')) {
      Mailpile.bulk_action_deselect_target();
    } else {
      Mailpile.bulk_action_select_target();
    }
  }
  return true;
};

Mailpile.bulk_action_select_all = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    Mailpile.pile_action_select($(this).parent().parent());
  });
  $("#pile-select-all-action").attr('checked','checked');
};

Mailpile.bulk_action_select_none = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    Mailpile.pile_action_unselect($(this).parent().parent());
  });
  $("#pile-select-all-action").removeAttr('checked');
};

Mailpile.bulk_action_select_invert = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  $.each(checkboxes, function() {
    if ($(this).is(":checked")) {
      Mailpile.pile_action_unselect($(this).parent().parent());
    } else {
      Mailpile.pile_action_select($(this).parent().parent());
    }
  });
  if (this['messages_cache'].length == checkboxes.length) {
    $("#pile-select-all-action").attr('checked','checked');
  } else if (this['messages_cache'].length == 0) {
    $("#pile-select-all-action").removeAttr('checked');
  }
};

Mailpile.bulk_action_select_between = function() {
  alert('FIXME: Will select messages between two points');
};

Mailpile.bulk_action_selection_up = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  if (this['messages_cache'].length == 0) {
    Mailpile.pile_action_select($(checkboxes[checkboxes.length-1]).parent().parent());
    return;
  }
  $.each(checkboxes, function() {
    if ($(this).parent().parent().next().children().children("input").is(":checked")) {
      Mailpile.pile_action_select($(this).parent().parent());
    } else {
      Mailpile.pile_action_unselect($(this).parent().parent());
    }
  });
};

Mailpile.bulk_action_selection_down = function() {
  var checkboxes = $('#pile-results input[type=checkbox]');
  if (this['messages_cache'].length == 0) {
    Mailpile.pile_action_select($(checkboxes[0]).parent().parent());
    return;
  }
  $(checkboxes.get().reverse()).each(function() {
    if ($(this).parent().parent().prev().children().children("input").is(":checked")) {
      Mailpile.pile_action_select($(this).parent().parent());
    } else {
      Mailpile.pile_action_unselect($(this).parent().parent());
    }
  });
};

Mailpile.open_selected_thread = function() {
  if (this['messages_cache'].length == 1) {
    $("#pile-results input[type=checkbox]:checked").each(function() {
      window.location.href = $(this).parent().parent()
                                    .children(".subject")
                                    .children("a").attr("href");
    });
  }
};<|endoftext|>


<commit_before>describe('bashnotebook', function(){

  var controller;
  var httpBackend;
  var $compile;
  var nbService;

  beforeEach(module('oide'));
  beforeEach(module('oide.editor'));
  beforeEach(module('oide.filesystemservice'));
  beforeEach(module('oide.templates'));
  beforeEach(module('oide.filetreedirective'));

  beforeEach(inject(function($controller, $rootScope, $log, $document, $httpBackend, _$compile_, $modal, NotebookService){
    scope = $rootScope.$new();
    $compile = _$compile_;
    httpBackend = $httpBackend;
    nbService = NotebookService;
    httpBackend.whenGET('/filebrowser/filetree/a/dir').respond(function(){
      return [200, dirs];
    });
    controller = $controller;
    controller = $controller('NotebookCtrl', {
      $scope: scope,
      $document: $document,
      $log: $log,
      NotebookService: NotebookService,
      $modal: $modal
    });
    scope.ctrl = controller;
    scope.$apply();
  }));

  describe('Notebook Controller', function(){
    it('should initialize the directive properly', function(){
      var element = angular.element('

');
      el = $compile(element)(scope);
      scope.$digest();
      expect(scope.ctrl.cellsObj).toBeDefined();
      expect(scope.ctrl.nbFile).toBeDefined();
      expect(scope.ctrl.nbFile.filepath).toBe('-');
      expect(scope.ctrl.nbFile.filename).toBe('Untitled');
      expect(scope.ctrl.unsaved).not.toBeTruthy();
    });
  });

});
<commit_msg>stop and start kernel tests<commit_after>describe('bashnotebook', function(){

  var controller;
  var httpBackend;
  var $compile;
  var nbService;

  beforeEach(module('oide'));
  beforeEach(module('oide.editor'));
  beforeEach(module('oide.filesystemservice'));
  beforeEach(module('oide.templates'));
  beforeEach(module('oide.filetreedirective'));

  beforeEach(inject(function($controller, $rootScope, $log, $document, $httpBackend, _$compile_, $modal, NotebookService){
    scope = $rootScope.$new();
    $compile = _$compile_;
    httpBackend = $httpBackend;
    nbService = NotebookService;
    httpBackend.whenGET('/filebrowser/filetree/a/dir').respond(function(){
      return [200, dirs];
    });
    controller = $controller;
    controller = $controller('NotebookCtrl', {
      $scope: scope,
      $document: $document,
      $log: $log,
      NotebookService: NotebookService,
      $modal: $modal
    });
    scope.ctrl = controller;
    scope.$apply();
  }));

  describe('Notebook Controller', function(){
    it('should initialize the directive properly', function(){
      var element = angular.element('

');
      el = $compile(element)(scope);
      scope.$digest();
      expect(scope.ctrl.cellsObj).toBeDefined();
      expect(scope.ctrl.nbFile).toBeDefined();
      expect(scope.ctrl.nbFile.filepath).toBe('-');
      expect(scope.ctrl.nbFile.filename).toBe('Untitled');
      expect(scope.ctrl.unsaved).not.toBeTruthy();
    });

    it('should start a kernel', function(){
      var element = angular.element('

');
      el = $compile(element)(scope);
      scope.$digest();
      // create spy on notebook service method
      spyOn(nbService, 'startKernel');
      scope.ctrl.startKernel();
      expect(nbService.startKernel).toHaveBeenCalled();
    });

    it('should stop a kernel', function(){
      var element = angular.element('

');
      el = $compile(element)(scope);
      scope.$digest();
      // create spy on stop kernel
      spyOn(nbService, 'stopKernel');
      scope.ctrl.stopKernel();
      expect(nbService.stopKernel).toHaveBeenCalled();
    });

  });

});
<|endoftext|>


<commit_before>/* notes from dinner discussion today (are these worth keeping?  where
 * should i move them?  -mf):

there should be a way to keep changes locally without posting them
right away.  something like a button that toggles between "edit" and
"display", and if there are local changes, the background colour
changes to "not saved", and two further buttons "submit changes" and
"discard changes" appear next to the "edit/display" button.  "submit"
and "discard" buttons also appear on super-structures; if the user has
edited a number of paragraphs, she can post a new version of the
entire document with one click.

there must be a way for the server to receive a batch of post requests
that are processed in one database "transaction" (not to be confused
with rest api transactions that need to be handled by client and
server cooperatively and are a total mess).

if the server receives a paragraph update (or several ones), it
performs the update to the containing document triggered by the
essence edge from paragraph to document, and possibly further updates.
all objects updated implicitly by the paragraph update are collected
into a dict that maps old versions (that are still up to date for all
the client knows) to new ones (that the client should know about).
this dict is sent to the client in the http response to the paragraph
update.

this does not address the problem that the server wants to tell the
client about changes by other users in real-time.  but that's an
unrelated problem: if a user changes a paragraph, she wants to go on
working on the changed version right away; if other users change
stuff, she wants to be notified as soon as possible, but (1) delays
are acceptable, and (2) she doesn't want the notifications to
interfere with her work.

*/

(function($, obviel) {

    // for editing

    // FIXME: Put in seperate module
    // Adds fields to make a view settings object editable.
    ad.Editable = function(child) {
        var result = {
            edit: function(ev) {
                    this.el.render(this.obj, "edit");
                },
        };
        $.extend(result, child);
        return result;
    };

    obviel.view({
        iface: 'adhocracy.interfaces.IParagraph',
        name: 'edit',
        obvt: '

<button data-on="click|preview">Preview
',
        before: function() {
            this.obj.form = toForms(this.obj);
        },
        preview: function() {
            // FIXME: How do we get the real value?
            value = document.getElementById('obviel-field-auto0-text').value;
            this.obj.data['adhocracy#interfaces#IText'].text = value;
            this.el.render(this.obj);
        }
    });

    // end editing

    // Pool:
    obviel.view({
        iface: 'adhocracy.interfaces.IPool',
        obvtUrl: 'templates/IPool.obvt',
    });

    // Versionables
    var interfaces = ["IProposalContainer", "IParagraphContainer"];
    for (i in interfaces) {
        name = interfaces[i];
        console.log(('adhocracy.interfaces.' + name));
        obviel.view({
            iface: ('adhocracy.interfaces.' + name),
            before: function() {
                this.obj._versions_path = this.obj.meta.path + "/_versions";
            },
            obvt: '

',
        });
    };

    // small views for named items
    var interfaces = ["IProposalContainer", "IParagraphContainer"];
    for (i in interfaces) {
        name = interfaces[i];
        obviel.view({
            iface: 'adhocracy.interfaces.' + name,
            name: 'small',
            obvtUrl: 'templates/IName.small.obvt'
        });
    };

    obviel.view(ad.Editable({
        iface: 'adhocracy.interfaces.IProposal',
        obvtUrl: 'templates/IProposal.obvt',
    }));

    obviel.view(ad.Editable({
        iface: 'adhocracy.interfaces.IParagraph',
        obvtUrl: 'templates/IParagraph.obvt',
    }));

    obviel.view({
        iface: 'adhocracy.interfaces.INodeVersions',
        obvtUrl: "templates/INodeVersions.obvt"
    });

    obviel.view({
        iface: "formlist",
        obvt: '

'
    });

    obviel.view({
        iface: 'debug_links',
        obvtUrl: 'templates/debug_links.obvt'
    });

}) (jQuery, obviel);
<commit_msg>frontend: hint at a solution to soenke's open issue with forms<commit_after>/* notes from dinner discussion today (are these worth keeping?  where
 * should i move them?  -mf):

there should be a way to keep changes locally without posting them
right away.  something like a button that toggles between "edit" and
"display", and if there are local changes, the background colour
changes to "not saved", and two further buttons "submit changes" and
"discard changes" appear next to the "edit/display" button.  "submit"
and "discard" buttons also appear on super-structures; if the user has
edited a number of paragraphs, she can post a new version of the
entire document with one click.

there must be a way for the server to receive a batch of post requests
that are processed in one database "transaction" (not to be confused
with rest api transactions that need to be handled by client and
server cooperatively and are a total mess).

if the server receives a paragraph update (or several ones), it
performs the update to the containing document triggered by the
essence edge from paragraph to document, and possibly further updates.
all objects updated implicitly by the paragraph update are collected
into a dict that maps old versions (that are still up to date for all
the client knows) to new ones (that the client should know about).
this dict is sent to the client in the http response to the paragraph
update.

this does not address the problem that the server wants to tell the
client about changes by other users in real-time.  but that's an
unrelated problem: if a user changes a paragraph, she wants to go on
working on the changed version right away; if other users change
stuff, she wants to be notified as soon as possible, but (1) delays
are acceptable, and (2) she doesn't want the notifications to
interfere with her work.

*/

(function($, obviel) {

    // for editing

    // FIXME: Put in seperate module
    // Adds fields to make a view settings object editable.
    ad.Editable = function(child) {
        var result = {
            edit: function(ev) {
                    this.el.render(this.obj, "edit");
                },
        };
        $.extend(result, child);
        return result;
    };

    obviel.view({
        iface: 'adhocracy.interfaces.IParagraph',
        name: 'edit',
        obvt: '

<button data-on="click|preview">Preview
',
        before: function() {
            this.obj.form = toForms(this.obj);
        },
        preview: function() {
            // FIXME: How do we get the real value?
            value = document.getElementById('obviel-field-auto0-text').value;

            console.log("FIXME");
            console.log(this);
            console.log(this.el[0]);

            // XXX: el[0] must contain another xml tag, say, "
" or
            // "
" or "<textarea>" that contains only the contents
            // we are looking for.  then we can dig into this.el
            // properly and pluck it.

            // .getElementByClass()?
            // ...?

            this.obj.data['adhocracy#interfaces#IText'].text = value;
            this.el.render(this.obj);
        }
    });

    // end editing

    // Pool:
    obviel.view({
        iface: 'adhocracy.interfaces.IPool',
        obvtUrl: 'templates/IPool.obvt',
    });

    // Versionables
    var interfaces = ["IProposalContainer", "IParagraphContainer"];
    for (i in interfaces) {
        name = interfaces[i];
        console.log(('adhocracy.interfaces.' + name));
        obviel.view({
            iface: ('adhocracy.interfaces.' + name),
            before: function() {
                this.obj._versions_path = this.obj.meta.path + "/_versions";
            },
            obvt: '

',
        });
    };

    // small views for named items
    var interfaces = ["IProposalContainer", "IParagraphContainer"];
    for (i in interfaces) {
        name = interfaces[i];
        obviel.view({
            iface: 'adhocracy.interfaces.' + name,
            name: 'small',
            obvtUrl: 'templates/IName.small.obvt'
        });
    };

    obviel.view(ad.Editable({
        iface: 'adhocracy.interfaces.IProposal',
        obvtUrl: 'templates/IProposal.obvt',
    }));

    obviel.view(ad.Editable({
        iface: 'adhocracy.interfaces.IParagraph',
        obvtUrl: 'templates/IParagraph.obvt',
    }));

    obviel.view({
        iface: 'adhocracy.interfaces.INodeVersions',
        obvtUrl: "templates/INodeVersions.obvt"
    });

    obviel.view({
        iface: "formlist",
        obvt: '

'
    });

    obviel.view({
        iface: 'debug_links',
        obvtUrl: 'templates/debug_links.obvt'
    });

}) (jQuery, obviel);
<|endoftext|>


<commit_before>'use strict';

/**
 * GraphQL.js service
 *
 * @description: A set of functions similar to controller's actions to avoid code duplication.
 */

const _ = require('lodash');
const pluralize = require('pluralize');
const Aggregator = require('./Aggregator');
const Loaders = require('./Loaders');
const Query = require('./Query.js');
const Mutation = require('./Mutation.js');
const Types = require('./Types.js');
const Schema = require('./Schema.js');

module.exports = {
  /**
   * Construct the GraphQL query & definition and apply the right resolvers.
   *
   * @return Object
   */

  shadowCRUD: function(models, plugin) {
    // Retrieve generic service from the Content Manager plugin.
    const resolvers =
      strapi.plugins['content-manager'].services['contentmanager'];

    const initialState = {
      definition: '',
      query: {},
      mutation: {},
      resolver: { Query: {}, Mutation: {} },
    };

    if (_.isEmpty(models)) {
      return initialState;
    }

    return models.reduce((acc, name) => {
      const model = plugin
        ? strapi.plugins[plugin].models[name]
        : strapi.models[name];

      // Setup initial state with default attribute that should be displayed
      // but these attributes are not properly defined in the models.
      const initialState = {
        [model.primaryKey]: 'ID!',
      };

      const globalId = model.globalId;
      const _schema = _.cloneDeep(
        _.get(strapi.plugins, 'graphql.config._schema.graphql', {}),
      );

      if (!acc.resolver[globalId]) {
        acc.resolver[globalId] = {};
      }

      // Add timestamps attributes.
      if (_.get(model, 'options.timestamps') === true) {
        Object.assign(initialState, {
          createdAt: 'DateTime!',
          updatedAt: 'DateTime!',
        });

        Object.assign(acc.resolver[globalId], {
          createdAt: (obj) => {
            // eslint-disable-line no-unused-vars
            return obj.createdAt || obj.created_at;
          },
          updatedAt: (obj) => {
            // eslint-disable-line no-unused-vars
            return obj.updatedAt || obj.updated_at;
          },
        });
      }

      // Retrieve user customisation.
      const { type = {}, resolver = {} } = _schema;

      // Convert our layer Model to the GraphQL DL.
      const attributes = Object.keys(model.attributes)
        .filter(attribute => model.attributes[attribute].private !== true)
        .reduce((acc, attribute) => {
          // Convert our type to the GraphQL type.
          acc[attribute] = Types.convertType({
            definition: model.attributes[attribute],
            modelName: globalId,
            attributeName: attribute,
          });

          return acc;
        }, initialState);

      // Detect enum and generate it for the schema definition
      const enums = Object.keys(model.attributes)
        .filter(attribute => model.attributes[attribute].type === 'enumeration')
        .map(attribute => {
          const definition = model.attributes[attribute];

          return `enum ${Types.convertEnumType(
            definition,
            globalId,
            attribute,
          )} { ${definition.enum.join(' \n ')} }`;
        })
        .join(' ');

      acc.definition += enums;

      // Add parameters to optimize association query.
      (model.associations || [])
        .filter(association => association.type === 'collection')
        .forEach(association => {
          attributes[
            `${
              association.alias
            }(sort: String, limit: Int, start: Int, where: JSON)`
          ] = attributes[association.alias];

          delete attributes[association.alias];
        });

      acc.definition += `${Schema.getDescription(
        type[globalId],
        model,
      )}type ${globalId} {${Schema.formatGQL(
        attributes,
        type[globalId],
        model,
      )}}\n\n`;

      // Add definition to the schema but this type won't be "queriable" or "mutable".
      if (
        type[model.globalId] === false ||
        _.get(type, `${model.globalId}.enabled`) === false
      ) {
        return acc;
      }

      // Build resolvers.
      const queries = {
        singular:
          _.get(resolver, `Query.${pluralize.singular(name)}`) !== false
            ? Query.composeQueryResolver(_schema, plugin, name, true)
            : null,
        plural:
          _.get(resolver, `Query.${pluralize.plural(name)}`) !== false
            ? Query.composeQueryResolver(_schema, plugin, name, false)
            : null,
      };

      Object.keys(queries).forEach(type => {
        // The query cannot be built.
        if (_.isError(queries[type])) {
          strapi.log.error(queries[type]);
          strapi.stop();
        }

        // Only create query if the function is available.
        if (_.isFunction(queries[type])) {
          if (type === 'singular') {
            Object.assign(acc.query, {
              [`${pluralize.singular(name)}(id: ID!)`]: model.globalId,
            });
          } else {
            Object.assign(acc.query, {
              [`${pluralize.plural(
                name,
              )}(sort: String, limit: Int, start: Int, where: JSON)`]: `[${
                model.globalId
              }]`,
            });
          }

          _.merge(acc.resolver.Query, {
            [type === 'singular'
              ? pluralize.singular(name)
              : pluralize.plural(name)]: queries[type],
          });
        }
      });

      // TODO:
      // - Implement batch methods (need to update the content-manager as well).
      // - Implement nested transactional methods (create/update).
      const mutations = {
        create:
          _.get(resolver, `Mutation.create${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'create')
            : null,
        update:
          _.get(resolver, `Mutation.update${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'update')
            : null,
        delete:
          _.get(resolver, `Mutation.delete${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'delete')
            : null,
      };

      // Add model Input definition.
      acc.definition += Types.generateInputModel(model, name);

      Object.keys(mutations).forEach(type => {
        if (_.isFunction(mutations[type])) {
          let mutationDefinition;
          let mutationName = `${type}${_.capitalize(name)}`;

          // Generate the Input for this specific action.
          acc.definition += Types.generateInputPayloadArguments(
            model,
            name,
            type,
          );

          switch (type) {
            case 'create':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };

              break;
            case 'update':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };

              break;
            case 'delete':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };
              break;
            default:
            // Nothing.
          }

          // Assign mutation definition to global definition.
          Object.assign(acc.mutation, mutationDefinition);

          // Assign resolver to this mutation and merge it with the others.
          _.merge(acc.resolver.Mutation, {
            [`${mutationName}`]: mutations[type],
          });
        }
      });

      // TODO:
      // - Add support for Graphql Aggregation in Bookshelf ORM
      if (model.orm === 'mongoose') {
        // Generation the aggregation for the given model
        const modelAggregator = Aggregator.formatModelConnectionsGQL(
          attributes,
          model,
          name,
          queries.plural,
        );
        if (modelAggregator) {
          acc.definition += modelAggregator.type;
          if (!acc.resolver[modelAggregator.globalId]) {
            acc.resolver[modelAggregator.globalId] = {};
          }

          _.merge(acc.resolver, modelAggregator.resolver);
          _.merge(acc.query, modelAggregator.query);
        }
      }

      // Build associations queries.
      (model.associations || []).forEach(association => {
        switch (association.nature) {
          case 'oneToManyMorph':
            return _.merge(acc.resolver[globalId], {
              [association.alias]: async obj => {
                const withRelated = await resolvers.fetch(
                  {
                    id: obj[model.primaryKey],
                    model: name,
                  },
                  plugin,
                  [association.alias],
                  false,
                );

                const entry =
                  withRelated && withRelated.toJSON
                    ? withRelated.toJSON()
                    : withRelated;

                // Set the _type only when the value is defined
                if (entry[association.alias]) {
                  entry[association.alias]._type = _.upperFirst(
                    association.model,
                  );
                }

                return entry[association.alias];
              },
            });
          case 'manyMorphToOne':
          case 'manyMorphToMany':
          case 'manyToManyMorph':
            return _.merge(acc.resolver[globalId], {
              [association.alias]: async (obj) => {
                // eslint-disable-line no-unused-vars
                const [withRelated, withoutRelated] = await Promise.all([
                  resolvers.fetch(
                    {
                      id: obj[model.primaryKey],
                      model: name,
                    },
                    plugin,
                    [association.alias],
                    false,
                  ),
                  resolvers.fetch(
                    {
                      id: obj[model.primaryKey],
                      model: name,
                    },
                    plugin,
                    [],
                  ),
                ]);

                const entry =
                  withRelated && withRelated.toJSON
                    ? withRelated.toJSON()
                    : withRelated;

                // TODO:
                // - Handle sort, limit and start (lodash or inside the query)
                entry[association.alias].map((entry, index) => {
                  const type =
                    _.get(
                      withoutRelated,
                      `${association.alias}.${index}.kind`,
                    ) ||
                    _.upperFirst(
                      _.camelCase(
                        _.get(
                          withoutRelated,
                          `${association.alias}.${index}.${
                            association.alias
                          }_type`,
                        ),
                      ),
                    ) ||
                    _.upperFirst(_.camelCase(association[association.type]));

                  entry._type = type;

                  return entry;
                });

                return entry[association.alias];
              },
            });
          default:
        }

        _.merge(acc.resolver[globalId], {
          [association.alias]: async (obj, options) => {
            // eslint-disable-line no-unused-vars
            // Construct parameters object to retrieve the correct related entries.
            const params = {
              model: association.model || association.collection,
            };

            const queryOpts = {
              source: association.plugin,
            };

            // Get refering model.
            const ref = association.plugin
              ? strapi.plugins[association.plugin].models[params.model]
              : strapi.models[params.model];

            if (association.type === 'model') {
              params[ref.primaryKey] = _.get(obj, [association.alias, ref.primaryKey], obj[association.alias]);
            } else {
              // Apply optional arguments to make more precise nested request.
              const convertedParams = strapi.utils.models.convertParams(
                name,
                Query.convertToParams(Query.amountLimiting(options)),
              );

              const where = strapi.utils.models.convertParams(
                name,
                options.where || {},
              );

              // Limit, order, etc.
              Object.assign(queryOpts, convertedParams, { where: where.where });

              // Skip.
              queryOpts.skip = convertedParams.start;

              switch (association.nature) {
                case "manyToMany": {
                  const arrayOfIds = (obj[association.alias] || []).map(
                    related => {
                      return related[ref.primaryKey] || related;
                    }
                  );

                  Object.assign(queryOpts, {
                    ...queryOpts,
                    query: {
                      [ref.primaryKey]: arrayOfIds
                    }
                  });

                  break;
                }
                default:
                  Object.assign(queryOpts, {
                    ...queryOpts,
                    query: {
                      [association.via]: obj[ref.primaryKey]
                    }
                  });
              }
            }

            if (queryOpts.hasOwnProperty('query') &&
              queryOpts.query.hasOwnProperty('id') &&
              queryOpts.query.id.hasOwnProperty('value') &&
              Array.isArray(queryOpts.query.id.value)
            ) {
              queryOpts.query.id.symbol = 'IN';
            }

            return association.model ?
              Loaders.loaders[association.collection || association.model].load({ params, options: queryOpts, single: true }):
              Loaders.loaders[association.collection || association.model].load({ options: queryOpts, association });
          },
        });
      });

      return acc;
    }, initialState);
  }
};
<commit_msg>Fix loader name<commit_after>'use strict';

/**
 * GraphQL.js service
 *
 * @description: A set of functions similar to controller's actions to avoid code duplication.
 */

const _ = require('lodash');
const pluralize = require('pluralize');
const Aggregator = require('./Aggregator');
const Loaders = require('./Loaders');
const Query = require('./Query.js');
const Mutation = require('./Mutation.js');
const Types = require('./Types.js');
const Schema = require('./Schema.js');

module.exports = {
  /**
   * Construct the GraphQL query & definition and apply the right resolvers.
   *
   * @return Object
   */

  shadowCRUD: function(models, plugin) {
    // Retrieve generic service from the Content Manager plugin.
    const resolvers =
      strapi.plugins['content-manager'].services['contentmanager'];

    const initialState = {
      definition: '',
      query: {},
      mutation: {},
      resolver: { Query: {}, Mutation: {} },
    };

    if (_.isEmpty(models)) {
      return initialState;
    }

    return models.reduce((acc, name) => {
      const model = plugin
        ? strapi.plugins[plugin].models[name]
        : strapi.models[name];

      // Setup initial state with default attribute that should be displayed
      // but these attributes are not properly defined in the models.
      const initialState = {
        [model.primaryKey]: 'ID!',
      };

      const globalId = model.globalId;
      const _schema = _.cloneDeep(
        _.get(strapi.plugins, 'graphql.config._schema.graphql', {}),
      );

      if (!acc.resolver[globalId]) {
        acc.resolver[globalId] = {};
      }

      // Add timestamps attributes.
      if (_.get(model, 'options.timestamps') === true) {
        Object.assign(initialState, {
          createdAt: 'DateTime!',
          updatedAt: 'DateTime!',
        });

        Object.assign(acc.resolver[globalId], {
          createdAt: (obj) => {
            // eslint-disable-line no-unused-vars
            return obj.createdAt || obj.created_at;
          },
          updatedAt: (obj) => {
            // eslint-disable-line no-unused-vars
            return obj.updatedAt || obj.updated_at;
          },
        });
      }

      // Retrieve user customisation.
      const { type = {}, resolver = {} } = _schema;

      // Convert our layer Model to the GraphQL DL.
      const attributes = Object.keys(model.attributes)
        .filter(attribute => model.attributes[attribute].private !== true)
        .reduce((acc, attribute) => {
          // Convert our type to the GraphQL type.
          acc[attribute] = Types.convertType({
            definition: model.attributes[attribute],
            modelName: globalId,
            attributeName: attribute,
          });

          return acc;
        }, initialState);

      // Detect enum and generate it for the schema definition
      const enums = Object.keys(model.attributes)
        .filter(attribute => model.attributes[attribute].type === 'enumeration')
        .map(attribute => {
          const definition = model.attributes[attribute];

          return `enum ${Types.convertEnumType(
            definition,
            globalId,
            attribute,
          )} { ${definition.enum.join(' \n ')} }`;
        })
        .join(' ');

      acc.definition += enums;

      // Add parameters to optimize association query.
      (model.associations || [])
        .filter(association => association.type === 'collection')
        .forEach(association => {
          attributes[
            `${
              association.alias
            }(sort: String, limit: Int, start: Int, where: JSON)`
          ] = attributes[association.alias];

          delete attributes[association.alias];
        });

      acc.definition += `${Schema.getDescription(
        type[globalId],
        model,
      )}type ${globalId} {${Schema.formatGQL(
        attributes,
        type[globalId],
        model,
      )}}\n\n`;

      // Add definition to the schema but this type won't be "queriable" or "mutable".
      if (
        type[model.globalId] === false ||
        _.get(type, `${model.globalId}.enabled`) === false
      ) {
        return acc;
      }

      // Build resolvers.
      const queries = {
        singular:
          _.get(resolver, `Query.${pluralize.singular(name)}`) !== false
            ? Query.composeQueryResolver(_schema, plugin, name, true)
            : null,
        plural:
          _.get(resolver, `Query.${pluralize.plural(name)}`) !== false
            ? Query.composeQueryResolver(_schema, plugin, name, false)
            : null,
      };

      Object.keys(queries).forEach(type => {
        // The query cannot be built.
        if (_.isError(queries[type])) {
          strapi.log.error(queries[type]);
          strapi.stop();
        }

        // Only create query if the function is available.
        if (_.isFunction(queries[type])) {
          if (type === 'singular') {
            Object.assign(acc.query, {
              [`${pluralize.singular(name)}(id: ID!)`]: model.globalId,
            });
          } else {
            Object.assign(acc.query, {
              [`${pluralize.plural(
                name,
              )}(sort: String, limit: Int, start: Int, where: JSON)`]: `[${
                model.globalId
              }]`,
            });
          }

          _.merge(acc.resolver.Query, {
            [type === 'singular'
              ? pluralize.singular(name)
              : pluralize.plural(name)]: queries[type],
          });
        }
      });

      // TODO:
      // - Implement batch methods (need to update the content-manager as well).
      // - Implement nested transactional methods (create/update).
      const mutations = {
        create:
          _.get(resolver, `Mutation.create${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'create')
            : null,
        update:
          _.get(resolver, `Mutation.update${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'update')
            : null,
        delete:
          _.get(resolver, `Mutation.delete${_.capitalize(name)}`) !== false
            ? Mutation.composeMutationResolver(_schema, plugin, name, 'delete')
            : null,
      };

      // Add model Input definition.
      acc.definition += Types.generateInputModel(model, name);

      Object.keys(mutations).forEach(type => {
        if (_.isFunction(mutations[type])) {
          let mutationDefinition;
          let mutationName = `${type}${_.capitalize(name)}`;

          // Generate the Input for this specific action.
          acc.definition += Types.generateInputPayloadArguments(
            model,
            name,
            type,
          );

          switch (type) {
            case 'create':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };

              break;
            case 'update':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };

              break;
            case 'delete':
              mutationDefinition = {
                [`${mutationName}(input: ${mutationName}Input)`]: `${mutationName}Payload`,
              };
              break;
            default:
            // Nothing.
          }

          // Assign mutation definition to global definition.
          Object.assign(acc.mutation, mutationDefinition);

          // Assign resolver to this mutation and merge it with the others.
          _.merge(acc.resolver.Mutation, {
            [`${mutationName}`]: mutations[type],
          });
        }
      });

      // TODO:
      // - Add support for Graphql Aggregation in Bookshelf ORM
      if (model.orm === 'mongoose') {
        // Generation the aggregation for the given model
        const modelAggregator = Aggregator.formatModelConnectionsGQL(
          attributes,
          model,
          name,
          queries.plural,
        );
        if (modelAggregator) {
          acc.definition += modelAggregator.type;
          if (!acc.resolver[modelAggregator.globalId]) {
            acc.resolver[modelAggregator.globalId] = {};
          }

          _.merge(acc.resolver, modelAggregator.resolver);
          _.merge(acc.query, modelAggregator.query);
        }
      }

      // Build associations queries.
      (model.associations || []).forEach(association => {
        switch (association.nature) {
          case 'oneToManyMorph':
            return _.merge(acc.resolver[globalId], {
              [association.alias]: async obj => {
                const withRelated = await resolvers.fetch(
                  {
                    id: obj[model.primaryKey],
                    model: name,
                  },
                  plugin,
                  [association.alias],
                  false,
                );

                const entry =
                  withRelated && withRelated.toJSON
                    ? withRelated.toJSON()
                    : withRelated;

                // Set the _type only when the value is defined
                if (entry[association.alias]) {
                  entry[association.alias]._type = _.upperFirst(
                    association.model,
                  );
                }

                return entry[association.alias];
              },
            });
          case 'manyMorphToOne':
          case 'manyMorphToMany':
          case 'manyToManyMorph':
            return _.merge(acc.resolver[globalId], {
              [association.alias]: async (obj) => {
                // eslint-disable-line no-unused-vars
                const [withRelated, withoutRelated] = await Promise.all([
                  resolvers.fetch(
                    {
                      id: obj[model.primaryKey],
                      model: name,
                    },
                    plugin,
                    [association.alias],
                    false,
                  ),
                  resolvers.fetch(
                    {
                      id: obj[model.primaryKey],
                      model: name,
                    },
                    plugin,
                    [],
                  ),
                ]);

                const entry =
                  withRelated && withRelated.toJSON
                    ? withRelated.toJSON()
                    : withRelated;

                // TODO:
                // - Handle sort, limit and start (lodash or inside the query)
                entry[association.alias].map((entry, index) => {
                  const type =
                    _.get(
                      withoutRelated,
                      `${association.alias}.${index}.kind`,
                    ) ||
                    _.upperFirst(
                      _.camelCase(
                        _.get(
                          withoutRelated,
                          `${association.alias}.${index}.${
                            association.alias
                          }_type`,
                        ),
                      ),
                    ) ||
                    _.upperFirst(_.camelCase(association[association.type]));

                  entry._type = type;

                  return entry;
                });

                return entry[association.alias];
              },
            });
          default:
        }

        _.merge(acc.resolver[globalId], {
          [association.alias]: async (obj, options) => {
            // eslint-disable-line no-unused-vars
            // Construct parameters object to retrieve the correct related entries.
            const params = {
              model: association.model || association.collection,
            };

            const queryOpts = {
              source: association.plugin,
            };

            // Get refering model.
            const ref = association.plugin
              ? strapi.plugins[association.plugin].models[params.model]
              : strapi.models[params.model];

            if (association.type === 'model') {
              params[ref.primaryKey] = _.get(obj, [association.alias, ref.primaryKey], obj[association.alias]);
            } else {
              // Apply optional arguments to make more precise nested request.
              const convertedParams = strapi.utils.models.convertParams(
                name,
                Query.convertToParams(Query.amountLimiting(options)),
              );

              const where = strapi.utils.models.convertParams(
                name,
                options.where || {},
              );

              // Limit, order, etc.
              Object.assign(queryOpts, convertedParams, { where: where.where });

              // Skip.
              queryOpts.skip = convertedParams.start;

              switch (association.nature) {
                case "manyToMany": {
                  const arrayOfIds = (obj[association.alias] || []).map(
                    related => {
                      return related[ref.primaryKey] || related;
                    }
                  );

                  Object.assign(queryOpts, {
                    ...queryOpts,
                    query: {
                      [ref.primaryKey]: arrayOfIds
                    }
                  });

                  break;
                }
                default:
                  Object.assign(queryOpts, {
                    ...queryOpts,
                    query: {
                      [association.via]: obj[ref.primaryKey]
                    }
                  });
              }
            }

            if (queryOpts.hasOwnProperty('query') &&
              queryOpts.query.hasOwnProperty('id') &&
              queryOpts.query.id.hasOwnProperty('value') &&
              Array.isArray(queryOpts.query.id.value)
            ) {
              queryOpts.query.id.symbol = 'IN';
            }

            const loaderName = association.plugin ? `${association.plugin}__${params.model}`: params.model;

            return association.model ?
              Loaders.loaders[loaderName].load({ params, options: queryOpts, single: true }):
              Loaders.loaders[loaderName].load({ options: queryOpts, association });
          },
        });
      });

      return acc;
    }, initialState);
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import { FormattedMessage } from 'react-intl';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Message from '../Message';
import {
  units,
  Row,
} from '../../styles/js/shared';

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

    this.state = {
      confirmed: false,
      keepCompleted: false,
    };
  }

  handleConfirmation = () => {
    this.setState({ confirmed: !this.state.confirmed });
  };

  handlekeepCompleted= () => {
    this.setState({ keepCompleted: !this.state.keepCompleted });
  };

  handleCancel = () => {
    this.setState({ confirmed: false, keepCompleted: false });
    if (this.props.handleClose) {
      this.props.handleClose();
    }
  }

  handleProceed = () => {
    this.setState({ confirmed: false });
    if (this.props.handleConfirm) {
      this.props.handleConfirm(this.state.keepCompleted);
      this.setState({ keepCompleted: false });
    }
  }

  render() {
    const { projects } = this.props;
    let action = 'delete';
    if (this.props.action === 'edit') {
      action = this.props.editLabelOrDescription ? 'editLabelOrDescription' : 'edit';
    }
    const confirmDialogTitle = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditTitle"
        defaultMessage="Are you sure you want to edit this task?"
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeleteTitle"
        defaultMessage="Are you sure you want to delete this task?"
      />,
    };
    let affectedItems = 0;
    if (projects !== null) {
      let { selectedProjects } = this.props;
      if (action === 'editLabelOrDescription' && this.props.editedTask !== null) {
        selectedProjects = JSON.parse(this.props.editedTask.json_project_ids);
      }
      projects.forEach((project) => {
        if (selectedProjects.length === 0 || selectedProjects.indexOf(project.node.dbid) > -1) {
          affectedItems += project.node.medias_count;
        }
      });
    }

    const confirmDialogBlurb = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditBlurb"
        defaultMessage="Related item tasks will be modified as a consequence of applying this change, except for those that have already been completed."
      />,
      editLabelOrDescription: <FormattedMessage
        id="teamTasks.confirmEditLabelOrDescriptionBlurb"
        defaultMessage="You are about to edit tasks in {itemsNumber, plural, one {1 item} other {# items}}. If you proceed, all those tasks will also modified."
        values={{ itemsNumber: affectedItems }}
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeleteBlurb"
        defaultMessage="You are about to delete the selected tasks from {itemsNumber, plural, one {1 item} other {# items}}. If you proceed, the answers to these tasks will also be deleted."
        values={{ itemsNumber: affectedItems }}
      />,
    };

    const confirmkeepCompleted = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditkeepCompleted"
        defaultMessage="Keep the completed tasks, with their current name and description."
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeletekeepCompleted"
        defaultMessage="Keep the completed tasks, with their current answers."
      />,
    };
    return (
      <Dialog
        open={this.props.open}
        onClose={this.props.handleClose}
      >
        <DialogTitle>
          {confirmDialogTitle[this.props.action]}
        </DialogTitle>
        <DialogContent>
          <Message message={this.props.message} />
          <div style={{ margin: `${units(2)} 0` }}>
            { affectedItems > 0 ?

                <Row>
                  {confirmDialogBlurb[action]}
                </Row>
                { action !== 'edit' ?
                  <Row>
                    <FormControlLabel
                      control={
                        <Checkbox
                          id="keep-dialog__checkbox"
                          onChange={this.handlekeepCompleted.bind(this)}
                          checked={this.state.keepCompleted}
                        />
                      }
                      label={confirmkeepCompleted[this.props.action]}
                    />
                  </Row>
                  : null
                }
                <Row>
                  <FormattedMessage
                    id="teamTasks.processMessage"
                    defaultMessage="Do you want to proceed?"
                  />
                </Row>

 : null
            }
            <Row>
              <FormControlLabel
                control={
                  <Checkbox
                    id="confirm-dialog__checkbox"
                    onChange={this.handleConfirmation.bind(this)}
                    checked={this.state.confirmed}
                  />
                }
                label={<FormattedMessage id="teamTasks.confirmAction" defaultMessage="Yes" />}
              />
            </Row>

        </DialogContent>
        <DialogActions>
          <Button
            id="confirm-dialog__cancel-action-button"
            onClick={this.handleCancel}
          >
            <FormattedMessage id="teamTasks.cancelAction" defaultMessage="Cancel" />
          </Button>
          <Button
            id="confirm-dialog__confirm-action-button"
            onClick={this.handleProceed}
            color="primary"
            disabled={this.props.disabled || !this.state.confirmed}
          >
            <FormattedMessage id="teamTasks.continue" defaultMessage="Continue" />
          </Button>
        </DialogActions>
      </Dialog>
    );
  }
}

export default TeamTaskConfirmDialog;
<commit_msg>Fix typo<commit_after>import React from 'react';
import { FormattedMessage } from 'react-intl';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Message from '../Message';
import {
  units,
  Row,
} from '../../styles/js/shared';

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

    this.state = {
      confirmed: false,
      keepCompleted: false,
    };
  }

  handleConfirmation = () => {
    this.setState({ confirmed: !this.state.confirmed });
  };

  handlekeepCompleted= () => {
    this.setState({ keepCompleted: !this.state.keepCompleted });
  };

  handleCancel = () => {
    this.setState({ confirmed: false, keepCompleted: false });
    if (this.props.handleClose) {
      this.props.handleClose();
    }
  }

  handleProceed = () => {
    this.setState({ confirmed: false });
    if (this.props.handleConfirm) {
      this.props.handleConfirm(this.state.keepCompleted);
      this.setState({ keepCompleted: false });
    }
  }

  render() {
    const { projects } = this.props;
    let action = 'delete';
    if (this.props.action === 'edit') {
      action = this.props.editLabelOrDescription ? 'editLabelOrDescription' : 'edit';
    }
    const confirmDialogTitle = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditTitle"
        defaultMessage="Are you sure you want to edit this task?"
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeleteTitle"
        defaultMessage="Are you sure you want to delete this task?"
      />,
    };
    let affectedItems = 0;
    if (projects !== null) {
      let { selectedProjects } = this.props;
      if (action === 'editLabelOrDescription' && this.props.editedTask !== null) {
        selectedProjects = JSON.parse(this.props.editedTask.json_project_ids);
      }
      projects.forEach((project) => {
        if (selectedProjects.length === 0 || selectedProjects.indexOf(project.node.dbid) > -1) {
          affectedItems += project.node.medias_count;
        }
      });
    }

    const confirmDialogBlurb = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditBlurb"
        defaultMessage="Related item tasks will be modified as a consequence of applying this change, except for those that have already been completed."
      />,
      editLabelOrDescription: <FormattedMessage
        id="teamTasks.confirmEditLabelOrDescriptionBlurb"
        defaultMessage="You are about to edit tasks in {itemsNumber, plural, one {1 item} other {# items}}. If you proceed, all those tasks will also be modified."
        values={{ itemsNumber: affectedItems }}
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeleteBlurb"
        defaultMessage="You are about to delete the selected tasks from {itemsNumber, plural, one {1 item} other {# items}}. If you proceed, the answers to these tasks will also be deleted."
        values={{ itemsNumber: affectedItems }}
      />,
    };

    const confirmkeepCompleted = {
      edit: <FormattedMessage
        id="teamTasks.confirmEditkeepCompleted"
        defaultMessage="Keep the completed tasks, with their current name and description."
      />,
      delete: <FormattedMessage
        id="teamTasks.confirmDeletekeepCompleted"
        defaultMessage="Keep the completed tasks, with their current answers."
      />,
    };
    return (
      <Dialog
        open={this.props.open}
        onClose={this.props.handleClose}
      >
        <DialogTitle>
          {confirmDialogTitle[this.props.action]}
        </DialogTitle>
        <DialogContent>
          <Message message={this.props.message} />
          <div style={{ margin: `${units(2)} 0` }}>
            { affectedItems > 0 ?

                <Row>
                  {confirmDialogBlurb[action]}
                </Row>
                { action !== 'edit' ?
                  <Row>
                    <FormControlLabel
                      control={
                        <Checkbox
                          id="keep-dialog__checkbox"
                          onChange={this.handlekeepCompleted.bind(this)}
                          checked={this.state.keepCompleted}
                        />
                      }
                      label={confirmkeepCompleted[this.props.action]}
                    />
                  </Row>
                  : null
                }
                <Row>
                  <FormattedMessage
                    id="teamTasks.processMessage"
                    defaultMessage="Do you want to proceed?"
                  />
                </Row>

 : null
            }
            <Row>
              <FormControlLabel
                control={
                  <Checkbox
                    id="confirm-dialog__checkbox"
                    onChange={this.handleConfirmation.bind(this)}
                    checked={this.state.confirmed}
                  />
                }
                label={<FormattedMessage id="teamTasks.confirmAction" defaultMessage="Yes" />}
              />
            </Row>

        </DialogContent>
        <DialogActions>
          <Button
            id="confirm-dialog__cancel-action-button"
            onClick={this.handleCancel}
          >
            <FormattedMessage id="teamTasks.cancelAction" defaultMessage="Cancel" />
          </Button>
          <Button
            id="confirm-dialog__confirm-action-button"
            onClick={this.handleProceed}
            color="primary"
            disabled={this.props.disabled || !this.state.confirmed}
          >
            <FormattedMessage id="teamTasks.continue" defaultMessage="Continue" />
          </Button>
        </DialogActions>
      </Dialog>
    );
  }
}

export default TeamTaskConfirmDialog;
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name vega-lite-ui.directive:visListItem
 * @description
 * # visListItem
 */
angular.module('vlui')
  .directive('vlPlotGroup', function (Bookmarks, consts, dl, vl, Dataset, Logger, _) {
    return {
      templateUrl: 'vlplotgroup/vlplotgroup.html',
      restrict: 'E',
      replace: true,
      controller: function($scope, $element) {
        this.getDropTarget = function() {
          return $element.find('.fa-wrench')[0];
        };
      },
      scope: {
        /* pass to vlplot **/
        chart: '=',

        //optional
        disabled: '=',
        isInList: '=',

        alwaysScrollable: '=',
        configSet: '@',
        maxHeight: '=',
        maxWidth: '=',
        overflow: '=',
        priority: '=',
        rescale: '=',
        thumbnail: '=',
        tooltip: '=',

        /* vlplotgroup specific */

        fieldSet: '=',

        showBookmark: '@',
        showDebug: '=',
        showExpand: '=',
        showFilterNull: '@',
        showLabel: '@',
        showLog: '@',
        showMarkType: '@',
        showSort: '@',
        showTranspose: '@',

        alwaysSelected: '=',
        isSelected: '=',
        highlighted: '=',
        expandAction: '&',
      },
      link: function postLink(scope) {
        scope.Bookmarks = Bookmarks;
        scope.consts = consts;
        scope.Dataset = Dataset;

        // Defer rendering the debug Drop popup until it is requested
        scope.renderPopup = false;
        // Use _.once because the popup only needs to be initialized once
        scope.initializePopup = _.once(function() {
          scope.renderPopup = true;
        });

        scope.logCode = function(name, value) {
          console.log(name+':\n\n', JSON.stringify(value));
        };

        // TOGGLE LOG

        scope.log = {};
        scope.log.support = function(spec, encType) {
          if (!spec) { return false; }
          var encoding = spec.encoding,
            field = encoding[encType];

          return field && field.type === vl.Type.Quantitative && !field.bin;
        };

        scope.log.toggle = function(spec, encType) {
          if (!scope.log.support(spec, encType)) { return; }

          var field = spec.encoding[encType],
            scale = field.scale = field.scale || {};

          scale.type = scale.type === 'log' ? 'linear' : 'log';
          Logger.logInteraction(Logger.actions.LOG_TOGGLE, scope.chart.shorthand);
        };
        scope.log.active = function(spec, encType) {
          if (!scope.log.support(spec, encType)) { return; }

          var field = spec.encoding[encType],
            scale = field.scale = field.scale || {};

          return scale.type === 'log';
        };

        // TOGGLE FILTER
        // TODO: extract toggleFilterNull to be its own class

        scope.toggleFilterNull = function(spec) {
          Logger.logInteraction(Logger.actions.NULL_FILTER_TOGGLE, scope.chart.shorthand);

          spec.config = spec.config || {};
          spec.config.filterNull = spec.config.filterNull || {
            // TODO: initiate this from filterNull's schema instead
            nominal: false,
            ordinal: false,
            temporal: true,
            quantitative: true
          };
          spec.config.filterNull.ordinal = !spec.config.filterNull.ordinal;
          spec.config.filterNull.nominal = !spec.config.filterNull.nominal;
        };

        scope.toggleFilterNull.support = function(spec, stats) {
          var fields = vl.enc.fields(spec.encoding);
          for (var fieldName in fields) {
            var fieldList = fields[fieldName];
            if (
                (fieldList.containsType.ordinal || fieldList.containsType.nominal) &&
                (fieldName in stats) &&
                stats[fieldName].missing > 0
              ) {
              return true;
            }
          }
          return false;
        };

        // TOGGLE SORT
        // TODO: extract toggleSort to be its own class

        var toggleSort = scope.toggleSort = {};

        toggleSort.modes = ['ordinal-ascending', 'ordinal-descending',
          'quantitative-ascending', 'quantitative-descending', 'custom'];

        toggleSort.toggle = function(spec) {
          Logger.logInteraction(Logger.actions.SORT_TOGGLE, scope.chart.shorthand);
          var currentMode = toggleSort.mode(spec);
          var currentModeIndex = toggleSort.modes.indexOf(currentMode);

          var newModeIndex = (currentModeIndex + 1) % (toggleSort.modes.length - 1);
          var newMode = toggleSort.modes[newModeIndex];

          console.log('toggleSort', currentMode, newMode);

          var channels = toggleSort.channels(spec);
          spec.encoding[channels.ordinal].sort = toggleSort.getSort(newMode, spec);
        };

        /** Get sort property definition that matches each mode. */
        toggleSort.getSort = function(mode, spec) {
          if (mode === 'ordinal-ascending') {
            return 'ascending';
          }

          if (mode === 'ordinal-descending') {
            return 'descending';
          }

          var channels = toggleSort.channels(spec);
          var qEncDef = spec.encoding[channels.quantitative];

          if (mode === 'quantitative-ascending') {
            return {
              op: qEncDef.aggregate,
              field: qEncDef.name,
              order: 'ascending'
            };
          }

          if (mode === 'quantitative-descending') {
            return {
              op: qEncDef.aggregate,
              field: qEncDef.name,
              order: 'descending'
            };
          }

          return null;
        };

        toggleSort.mode = function(spec) {
          var channels = toggleSort.channels(spec);
          var sort = spec.encoding[channels.ordinal].sort;

          if (sort === undefined) {
            return 'ordinal-ascending';
          }

          for (var i = 0; i < toggleSort.modes.length - 1 ; i++) {
            // check if sort matches any of the sort for each mode except 'custom'.
            var mode = toggleSort.modes[i];
            var sortOfMode = toggleSort.getSort(mode, spec);

            if (_.isEqual(sort, sortOfMode)) {
              return mode;
            }
          }

          if (dl.isObject(sort) && sort.op && sort.field) {
            return 'custom';
          }
          console.error('invalid mode');
          return null;
        };

        toggleSort.channels = function(spec) {
          return spec.encoding.x.type === vl.Type.Nominal || spec.encoding.x.type === vl.Type.Ordinal ?
                  {ordinal: 'x', quantitative: 'y'} :
                  {ordinal: 'y', quantitative: 'x'};
        };

        toggleSort.support = function(spec, stats) {
          var enc = spec.encoding;

          if (vl.enc.has(enc, 'row') || vl.enc.has(enc, 'col') ||
            !vl.enc.has(enc, 'x') || !vl.enc.has(enc, 'y') ||
            !vl.Encoding.alwaysNoOcclusion(spec, stats)) {
            return false;
          }

          return (
              (enc.x.type === vl.Type.Nominal || enc.x.type === vl.Type.Ordinal) &&
              vl.encDef.isMeasure(enc.y)
            ) ? 'x' :
            (
              (enc.y.type === vl.Type.Nominal || enc.y.type === vl.Type.Ordinal) &&
              vl.encDef.isMeasure(enc.x)
            ) ? 'y' : false;
        };

        scope.toggleSortClass = function(vlSpec) {
          if (!vlSpec || !toggleSort.support(vlSpec, Dataset.stats)) {
            return 'invisible';
          }

          var ordinalChannel = vlSpec && toggleSort.channels(vlSpec).ordinal,
            mode = vlSpec && toggleSort.mode(vlSpec);

          var directionClass = ordinalChannel === 'x' ? 'sort-x ' : '';

          switch (mode) {
            case 'ordinal-ascending':
              return directionClass + 'fa-sort-alpha-asc';
            case 'ordinal-descending':
              return directionClass + 'fa-sort-alpha-desc';
            case 'quantitative-ascending':
              return directionClass + 'fa-sort-amount-asc';
            case 'quantitative-descending':
              return directionClass + 'fa-sort-amount-desc';
            default: // custom
              return directionClass + 'fa-sort';
          }
        };

        scope.transpose = function() {
          Logger.logInteraction(Logger.actions.TRANSPOSE_TOGGLE, scope.chart.shorthand);
          vl.Encoding.transpose(scope.chart.vlSpec);
        };

        scope.$on('$destroy', function() {
          scope.chart = null;
        });
      }
    };
  });
<commit_msg>old `field` => `encDef`<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name vega-lite-ui.directive:visListItem
 * @description
 * # visListItem
 */
angular.module('vlui')
  .directive('vlPlotGroup', function (Bookmarks, consts, dl, vl, Dataset, Logger, _) {
    return {
      templateUrl: 'vlplotgroup/vlplotgroup.html',
      restrict: 'E',
      replace: true,
      controller: function($scope, $element) {
        this.getDropTarget = function() {
          return $element.find('.fa-wrench')[0];
        };
      },
      scope: {
        /* pass to vlplot **/
        chart: '=',

        //optional
        disabled: '=',
        isInList: '=',

        alwaysScrollable: '=',
        configSet: '@',
        maxHeight: '=',
        maxWidth: '=',
        overflow: '=',
        priority: '=',
        rescale: '=',
        thumbnail: '=',
        tooltip: '=',

        /* vlplotgroup specific */

        fieldSet: '=',

        showBookmark: '@',
        showDebug: '=',
        showExpand: '=',
        showFilterNull: '@',
        showLabel: '@',
        showLog: '@',
        showMarkType: '@',
        showSort: '@',
        showTranspose: '@',

        alwaysSelected: '=',
        isSelected: '=',
        highlighted: '=',
        expandAction: '&',
      },
      link: function postLink(scope) {
        scope.Bookmarks = Bookmarks;
        scope.consts = consts;
        scope.Dataset = Dataset;

        // Defer rendering the debug Drop popup until it is requested
        scope.renderPopup = false;
        // Use _.once because the popup only needs to be initialized once
        scope.initializePopup = _.once(function() {
          scope.renderPopup = true;
        });

        scope.logCode = function(name, value) {
          console.log(name+':\n\n', JSON.stringify(value));
        };

        // TOGGLE LOG

        scope.log = {};
        scope.log.support = function(spec, encType) {
          if (!spec) { return false; }
          var encoding = spec.encoding,
            encDef = encoding[encType];

          return encDef && encDef.type === vl.Type.Quantitative && !encDef.bin;
        };

        scope.log.toggle = function(spec, encType) {
          if (!scope.log.support(spec, encType)) { return; }

          var encDef = spec.encoding[encType],
            scale = encDef.scale = encDef.scale || {};

          scale.type = scale.type === 'log' ? 'linear' : 'log';
          Logger.logInteraction(Logger.actions.LOG_TOGGLE, scope.chart.shorthand);
        };
        scope.log.active = function(spec, encType) {
          if (!scope.log.support(spec, encType)) { return; }

          var encDef = spec.encoding[encType],
            scale = encDef.scale = encDef.scale || {};

          return scale.type === 'log';
        };

        // TOGGLE FILTER
        // TODO: extract toggleFilterNull to be its own class

        scope.toggleFilterNull = function(spec) {
          Logger.logInteraction(Logger.actions.NULL_FILTER_TOGGLE, scope.chart.shorthand);

          spec.config = spec.config || {};
          spec.config.filterNull = spec.config.filterNull || {
            // TODO: initiate this from filterNull's schema instead
            nominal: false,
            ordinal: false,
            temporal: true,
            quantitative: true
          };
          spec.config.filterNull.ordinal = !spec.config.filterNull.ordinal;
          spec.config.filterNull.nominal = !spec.config.filterNull.nominal;
        };

        scope.toggleFilterNull.support = function(spec, stats) {
          var fields = vl.enc.fields(spec.encoding);
          for (var fieldName in fields) {
            var fieldList = fields[fieldName];
            if (
                (fieldList.containsType.ordinal || fieldList.containsType.nominal) &&
                (fieldName in stats) &&
                stats[fieldName].missing > 0
              ) {
              return true;
            }
          }
          return false;
        };

        // TOGGLE SORT
        // TODO: extract toggleSort to be its own class

        var toggleSort = scope.toggleSort = {};

        toggleSort.modes = ['ordinal-ascending', 'ordinal-descending',
          'quantitative-ascending', 'quantitative-descending', 'custom'];

        toggleSort.toggle = function(spec) {
          Logger.logInteraction(Logger.actions.SORT_TOGGLE, scope.chart.shorthand);
          var currentMode = toggleSort.mode(spec);
          var currentModeIndex = toggleSort.modes.indexOf(currentMode);

          var newModeIndex = (currentModeIndex + 1) % (toggleSort.modes.length - 1);
          var newMode = toggleSort.modes[newModeIndex];

          console.log('toggleSort', currentMode, newMode);

          var channels = toggleSort.channels(spec);
          spec.encoding[channels.ordinal].sort = toggleSort.getSort(newMode, spec);
        };

        /** Get sort property definition that matches each mode. */
        toggleSort.getSort = function(mode, spec) {
          if (mode === 'ordinal-ascending') {
            return 'ascending';
          }

          if (mode === 'ordinal-descending') {
            return 'descending';
          }

          var channels = toggleSort.channels(spec);
          var qEncDef = spec.encoding[channels.quantitative];

          if (mode === 'quantitative-ascending') {
            return {
              op: qEncDef.aggregate,
              field: qEncDef.name,
              order: 'ascending'
            };
          }

          if (mode === 'quantitative-descending') {
            return {
              op: qEncDef.aggregate,
              field: qEncDef.name,
              order: 'descending'
            };
          }

          return null;
        };

        toggleSort.mode = function(spec) {
          var channels = toggleSort.channels(spec);
          var sort = spec.encoding[channels.ordinal].sort;

          if (sort === undefined) {
            return 'ordinal-ascending';
          }

          for (var i = 0; i < toggleSort.modes.length - 1 ; i++) {
            // check if sort matches any of the sort for each mode except 'custom'.
            var mode = toggleSort.modes[i];
            var sortOfMode = toggleSort.getSort(mode, spec);

            if (_.isEqual(sort, sortOfMode)) {
              return mode;
            }
          }

          if (dl.isObject(sort) && sort.op && sort.field) {
            return 'custom';
          }
          console.error('invalid mode');
          return null;
        };

        toggleSort.channels = function(spec) {
          return spec.encoding.x.type === vl.Type.Nominal || spec.encoding.x.type === vl.Type.Ordinal ?
                  {ordinal: 'x', quantitative: 'y'} :
                  {ordinal: 'y', quantitative: 'x'};
        };

        toggleSort.support = function(spec, stats) {
          var enc = spec.encoding;

          if (vl.enc.has(enc, 'row') || vl.enc.has(enc, 'col') ||
            !vl.enc.has(enc, 'x') || !vl.enc.has(enc, 'y') ||
            !vl.Encoding.alwaysNoOcclusion(spec, stats)) {
            return false;
          }

          return (
              (enc.x.type === vl.Type.Nominal || enc.x.type === vl.Type.Ordinal) &&
              vl.encDef.isMeasure(enc.y)
            ) ? 'x' :
            (
              (enc.y.type === vl.Type.Nominal || enc.y.type === vl.Type.Ordinal) &&
              vl.encDef.isMeasure(enc.x)
            ) ? 'y' : false;
        };

        scope.toggleSortClass = function(vlSpec) {
          if (!vlSpec || !toggleSort.support(vlSpec, Dataset.stats)) {
            return 'invisible';
          }

          var ordinalChannel = vlSpec && toggleSort.channels(vlSpec).ordinal,
            mode = vlSpec && toggleSort.mode(vlSpec);

          var directionClass = ordinalChannel === 'x' ? 'sort-x ' : '';

          switch (mode) {
            case 'ordinal-ascending':
              return directionClass + 'fa-sort-alpha-asc';
            case 'ordinal-descending':
              return directionClass + 'fa-sort-alpha-desc';
            case 'quantitative-ascending':
              return directionClass + 'fa-sort-amount-asc';
            case 'quantitative-descending':
              return directionClass + 'fa-sort-amount-desc';
            default: // custom
              return directionClass + 'fa-sort';
          }
        };

        scope.transpose = function() {
          Logger.logInteraction(Logger.actions.TRANSPOSE_TOGGLE, scope.chart.shorthand);
          vl.Encoding.transpose(scope.chart.vlSpec);
        };

        scope.$on('$destroy', function() {
          scope.chart = null;
        });
      }
    };
  });
<|endoftext|>


<commit_before>import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import auth from './userSignUp';
import login from './login';
import book from './book';
import favorites from './favorites';
import profile from './profile';
import { books, mostUpvotedBooks } from './books';

const rootReducer = combineReducers({
  form: formReducer,
  auth,
  login,
  books,
  book,
  mostUpvotedBooks,
  favorites,
  profile,
  routing: routerReducer,
});

export default rootReducer;
<commit_msg>Add addBook reducer to root reducer<commit_after>import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import auth from './userSignUp';
import login from './login';
import book from './book';
import favorites from './favorites';
import profile from './profile';
import addBook from './addBook';
import { books, mostUpvotedBooks } from './books';

const rootReducer = combineReducers({
  form: formReducer,
  auth,
  login,
  books,
  book,
  addBook,
  mostUpvotedBooks,
  favorites,
  profile,
  routing: routerReducer,
});

export default rootReducer;
<|endoftext|>


<commit_before>import { combineReducers } from 'redux';
import errorReducer from './errorReducer';
import userGroupsReducer from './userGroupsReducer';
import userReducer from './userReducer';
import postItInfoReducer from './postItInfoReducer';
import loadingReducer from './loading';
import authStateReducer from './authStateReducer';
import allUserGroupsReducer from './allUserGroupsReducer';
import loadedChatReducer from './loadedChatReducer';

const postItApp = combineReducers({
  groups: userGroupsReducer,
  allUserGroups: allUserGroupsReducer,
  apiError: errorReducer,
  dataLoading: loadingReducer,
  appInfo: combineReducers({
    userDetails: userReducer,
    authState: authStateReducer,
    loadedChat: loadedChatReducer
  }),
  postItInfo: postItInfoReducer
});

export default postItApp;
<commit_msg>rename reducer to reflect purpose<commit_after>import { combineReducers } from 'redux';
import errorReducer from './errorReducer';
import userGroupsReducer from './userGroupsReducer';
import userReducer from './userReducer';
import postItInfoReducer from './postItInfoReducer';
import loadingReducer from './loading';
import authStateReducer from './authStateReducer';
import allUserGroupsReducer from './allUserGroupsReducer';
import loadedMessagesReducer from './loadedMessagesReducer';

const postItApp = combineReducers({
  groups: userGroupsReducer,
  allUserGroups: allUserGroupsReducer,
  apiError: errorReducer,
  dataLoading: loadingReducer,
  appInfo: combineReducers({
    userDetails: userReducer,
    authState: authStateReducer,
    loadedMessages: loadedMessagesReducer
  }),
  postItInfo: postItInfoReducer
});

export default postItApp;
<|endoftext|>


<commit_before>var metrics;
var timeseries;

nv.addGraph(function() {
  var chart = nv.models.lineWithFocusChart();

  chart.xAxis
      .tickFormat(d3.format(',f'));

  chart.yAxis
      .tickFormat(d3.format(',.2f'));

  chart.y2Axis
      .tickFormat(d3.format(',.2f'));

  datapoints = get_datapoints()

  d3.select('#chart svg')
      .datum(datapoints)
      .transition().duration(500)
      .call(chart);

  nv.utils.windowResize(chart.update);

  return chart;
});

/**************************************
 *  Cloudbrain data */

function get_datapoints() {

  load_data();
  datapoints = build_datapoints();
  return datapoints;
}

function load_metrics(){

    $.ajax({
      url : '/metrics',
      async: false,
      dataType : 'JSON',
      success : function(data) {
          metrics = data;
      }
    })

    return metrics;
}

function load_data(){

  load_metrics();
  load_timeseries();

}

function load_timeseries(){

  timeseries = [];
  nbMetrics = metrics.length;
  for (i=0;i< nbMetrics;  i++) {
    metric_name = metrics[i];
    $.ajax({
      url : '/api?metric=' + metric_name,
      dataType : 'JSON',
      async: false,
      success : function(data) {
         timeseries.push(data);
      }
    })

  }
  return timeseries;

}

function build_datapoints(){

    datapoints = []
    nbMetrics = metrics.length
      for (i=0; i< nbMetrics; i++) {
      datapoint = {key:metrics[i], values: timeseries[i]}
      datapoints.push(datapoint)
     }

    return datapoints;
}

<commit_msg>fixed chart<commit_after>var metrics;
var timeseries;

nv.addGraph(function() {
  var chart = nv.models.lineWithFocusChart();

  chart.xAxis
      .tickFormat(d3.format(',f'));

  chart.yAxis
      .tickFormat(d3.format(',.2f'));

  chart.y2Axis
      .tickFormat(d3.format(',.2f'));

  datapoints = get_datapoints()

  d3.select('#chart svg')
      .datum(datapoints)
      .transition().duration(500)
      .call(chart);

  nv.utils.windowResize(chart.update);

  return chart;
});

/**************************************
 *  Cloudbrain data */

function get_datapoints() {

  load_data();
  datapoints = build_datapoints();
  return datapoints;
}

function load_metrics(){

    $.ajax({
      url : '/metrics',
      async: false,
      dataType : 'JSON',
      success : function(data) {
          metrics = data['results'];
      }
    })

    return metrics;
}

function load_data(){

  load_metrics();
  load_timeseries();

}

function load_timeseries(){

  timeseries = [];
  nbMetrics = metrics.length;
  for (i=0;i< nbMetrics;  i++) {
    metric_name = metrics[i];
    $.ajax({
      url : '/api?metric=' + metric_name,
      dataType : 'JSON',
      async: false,
      success : function(data) {
         timeseries.push(data['results']);
      }
    })

  }
  return timeseries;

}

function build_datapoints(){

    datapoints = []
    nbMetrics = metrics.length
      for (i=0; i< nbMetrics; i++) {
      datapoint = {key:metrics[i], values: timeseries[i]}
      datapoints.push(datapoint)
     }

    return datapoints;
}

<|endoftext|>


<commit_before>const fs = require('fs');
let shortid = require('shortid');
const path = require("path");
const url = require('url');

let usersList = [{userId:'bb', userPwd:'ffff'}, {userId:'bbrr', userPwd:'bg012'}, {userId:'marion', userPwd:'70roBert'}];

function createDir(filePath) {

  filePath = path.dirname(filePath);
  console.log('create dir ',filePath );

  if (checkExist(filePath)) {
    return true;
  }
  checkExist(filePath);
  fs.mkdirSync(filePath);
}

function checkExist(path) {
  console.log('checkExist ',path );

  try {
    return fs.statSync(path).isDirectory();
  }
  catch (err) {
    return false;
  }
}

class ServerStorage {

  constructor() {

    this.picturesPath = '../../../../dist/assets/img/';
    this.serverType = 'local';
  }

  savePicture(bodyReqTitle, bodyReqPictureData) {

    return new Promise((resolve, reject) => {

      //Create base64 decoded buffer
      let picData = bodyReqPictureData.replace(/^data:image\/\w+;base64,/, "");
      let decodedPicData = new Buffer(picData, 'base64');

      let uniqueID = shortid.generate();
      let generatedFileName = bodyReqTitle + '' + uniqueID + ".jpg";

      let fileName = this.picturesPath + '\\' + generatedFileName;
      let filePath = path.join(__dirname, fileName);

      console.log("write file: ", filePath);

      createDir(filePath);
      //this.picturesPath = storePath;

      fs.writeFile(filePath, decodedPicData, 'base64', (err) => {

        if (err) {
          generatedFileName = null;
          console.log("write error: ", err);
          reject(err);
        }
        else {
          resolve({
            id: generatedFileName
          });
        }
      })
    })

  }

  getPicture(fileName) {

    return new Promise((resolve, reject) => {
      let data = null;
      fs.readFile(this.picturesPath + '/' + fileName, (err, data) => {
        if (err) {
          reject(console.log('getPicture error:', err))
        }
        else {
          data = data;
          resolve(data)
        }
      })
    })
  }

  getUrl(fileName)
  {
    return '/assets/img/' + path.join(fileName);

    //return `${this.picturesPath}/${fileName}`;
  }

  findUser(user) {
    console.log("find user ", user);

    return new Promise((resolve, reject) => {

      if (usersList.filter(function(u) {console.log("FILTER ", user, usersList); u.userId === user.userId && u.userPwd === user.userPwd; }).length == 1)
      {
        let generatedToken = shortid.generate();
        console.log('user found ', user, generatedToken );
        resolve({userId:user.userId, userToken:generatedToken});
      }

      else {
        console.log("User not found, create user first");
        reject("User not found, create user first");
      }
    })
  }
}

module.exports = ServerStorage;
<commit_msg>test if it works like that<commit_after>const fs = require('fs');
let shortid = require('shortid');
const path = require("path");
const url = require('url');

let usersList = [{userId:'bb', userPwd:'ffff'}, {userId:'bbrr', userPwd:'bg012'}, {userId:'marion', userPwd:'70roBert'}];

function createDir(filePath) {

  filePath = path.dirname(filePath);
  console.log('create dir ',filePath );

  if (checkExist(filePath)) {
    return true;
  }
  checkExist(filePath);
  fs.mkdirSync(filePath);
}

function checkExist(path) {
  console.log('checkExist ',path );

  try {
    return fs.statSync(path).isDirectory();
  }
  catch (err) {
    return false;
  }
}

class ServerStorage {

  constructor() {

    this.picturesPath = '../../../../dist/assets/img/';
    this.serverType = 'local';
  }

  savePicture(bodyReqTitle, bodyReqPictureData) {

    return new Promise((resolve, reject) => {

      //Create base64 decoded buffer
      let picData = bodyReqPictureData.replace(/^data:image\/\w+;base64,/, "");
      let decodedPicData = new Buffer(picData, 'base64');

      let uniqueID = shortid.generate();
      let generatedFileName = bodyReqTitle + '' + uniqueID + ".jpg";

      let fileName = this.picturesPath + '\\' + generatedFileName;
      let filePath = path.join(__dirname, fileName);

      console.log("write file: ", filePath);

      //createDir(filePath);
      //this.picturesPath = storePath;

      fs.writeFile(filePath, decodedPicData, 'base64', (err) => {

        if (err) {
          generatedFileName = null;
          console.log("write error: ", err);
          reject(err);
        }
        else {
          resolve({
            id: generatedFileName
          });
        }
      })
    })

  }

  getPicture(fileName) {

    return new Promise((resolve, reject) => {
      let data = null;
      fs.readFile(this.picturesPath + '/' + fileName, (err, data) => {
        if (err) {
          reject(console.log('getPicture error:', err))
        }
        else {
          data = data;
          resolve(data)
        }
      })
    })
  }

  getUrl(fileName)
  {
    return '/assets/img/' + path.join(fileName);

    //return `${this.picturesPath}/${fileName}`;
  }

  findUser(user) {
    console.log("find user ", user);

    return new Promise((resolve, reject) => {

      if (usersList.filter(function(u) {console.log("FILTER ", user, usersList); u.userId === user.userId && u.userPwd === user.userPwd; }).length == 1)
      {
        let generatedToken = shortid.generate();
        console.log('user found ', user, generatedToken );
        resolve({userId:user.userId, userToken:generatedToken});
      }

      else {
        console.log("User not found, create user first");
        reject("User not found, create user first");
      }
    })
  }
}

module.exports = ServerStorage;
<|endoftext|>