public inbox for [email protected]  
help / color / mirror / Atom feed
Bug #3083 fix
13+ messages / 5 participants
[nested] [flat]

* Bug #3083 fix
@ 2018-02-27 17:17 Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Neethu Mariya Joy @ 2018-02-27 17:17 UTC (permalink / raw)
  To: pgadmin-hackers

Hi,
I am Neethu Mariya Joy, an undergraduate pursuing BE in Computer Science at
BITS Pilani.

I've attempted to fix https://redmine.postgresql.org/issues/3083. Since the
textarea resize feature is the default HTML feature, I have not changed it.
Instead, I've added draggable borders to the wrapper which expands the
textarea inside it.

I'm attaching my patch as bug3083.diff below as per the contribution
guidelines.

Hope this helps. Thank you for your consideration!

Sincerely,
Neethu Mariya Joy
GitHub <https://github.com/Roboneet; | Linkedin
<https://www.linkedin.com/in/neethu-mariya-joy-653655128/;

diff --git a/web/pgadmin/static/js/slickgrid/editors.js b/web/pgadmin/static/js/slickgrid/editors.js
index 7652bf3..d369928 100644
--- a/web/pgadmin/static/js/slickgrid/editors.js
+++ b/web/pgadmin/static/js/slickgrid/editors.js
@@ -123,6 +123,53 @@
     return position;
   }
 
+  function resizeContentOnDrag($wrapper, $input){
+    // right border, bottom border and right bottom corner of the wrapper are draggable
+    $wrapper.append('<div class="drag-border" data="right"></div>\
+      <div class="drag-border" data="bottom"></div>\
+      <div class="drag-border" data="both"></div>');
+    
+    $wrapper.find('.drag-border').on('drag', (event)=>{
+      event.preventDefault();
+      var mouseX = event.clientX;
+      var mouseY = event.clientY;
+
+      // mouseX == 0 && mouseY == 0 mouse up / end of drag
+      if(mouseX == 0 && mouseY == 0)return;
+      
+      // default spacing between $input and cursor
+      var paddingBottom = 30;
+      var paddingRight = 10;
+      var dir = event.target.getAttribute('data');
+      
+      // size of $input is changed according to cursor position
+      switch(dir){
+      case 'right':
+        changeWidth($input, mouseX, paddingRight);
+        break;
+      case 'bottom':
+        changeHeight($input, mouseY, paddingBottom);
+        break;
+      case 'both':
+        changeHeight($input, mouseY, paddingBottom);
+        changeWidth($input, mouseX, paddingRight);
+      }      
+    });
+  }
+
+  function changeWidth($input, mouseX, padding){
+    var rect = $input[0].getBoundingClientRect();    
+    var newWidth = rect.width + mouseX - rect.right - padding;
+    $input.css('width', newWidth.toString() + 'px');
+  }
+
+  function changeHeight($input, mouseY, padding){
+    var rect = $input[0].getBoundingClientRect();
+    var newHeight = rect.height + mouseY - rect.bottom - padding;
+    $input.css('height', newHeight.toString() + 'px');
+  }
+
+
   // Text data type editor
   function pgTextEditor(args) {
     var $input, $wrapper, $buttons;
@@ -140,6 +187,7 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -297,6 +345,7 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -419,6 +468,7 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -518,6 +568,7 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 1e29c3f..288e57f 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -505,6 +505,38 @@ input.editor-checkbox:focus {
   -moz-border-radius:10px;
   border-radius:10px;
 }
+
+.drag-border{
+  background: transparent;
+  position: absolute;
+}
+
+.drag-border[data=right]{
+  cursor: ew-resize;  
+  top: 0;
+  right: -10px;
+  bottom: 0;
+  width: 20px;
+}
+
+.drag-border[data=bottom]{
+  cursor: ns-resize;
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: -10px;
+  height: 20px; 
+}
+
+.drag-border[data=both]{
+  cursor: move;
+  position: absolute;
+  bottom: -10px;
+  right: -10px;
+  width: 20px;
+  height: 20px;
+}
+
 .pg_textarea {
   backround:#fff;
   width:250px;


Attachments:

  [text/plain] bug3083.diff (3.9K, 3-bug3083.diff)
  download | inline diff:
diff --git a/web/pgadmin/static/js/slickgrid/editors.js b/web/pgadmin/static/js/slickgrid/editors.js
index 7652bf3..d369928 100644
--- a/web/pgadmin/static/js/slickgrid/editors.js
+++ b/web/pgadmin/static/js/slickgrid/editors.js
@@ -123,6 +123,53 @@
     return position;
   }
 
+  function resizeContentOnDrag($wrapper, $input){
+    // right border, bottom border and right bottom corner of the wrapper are draggable
+    $wrapper.append('<div class="drag-border" data="right"></div>\
+      <div class="drag-border" data="bottom"></div>\
+      <div class="drag-border" data="both"></div>');
+    
+    $wrapper.find('.drag-border').on('drag', (event)=>{
+      event.preventDefault();
+      var mouseX = event.clientX;
+      var mouseY = event.clientY;
+
+      // mouseX == 0 && mouseY == 0 mouse up / end of drag
+      if(mouseX == 0 && mouseY == 0)return;
+      
+      // default spacing between $input and cursor
+      var paddingBottom = 30;
+      var paddingRight = 10;
+      var dir = event.target.getAttribute('data');
+      
+      // size of $input is changed according to cursor position
+      switch(dir){
+      case 'right':
+        changeWidth($input, mouseX, paddingRight);
+        break;
+      case 'bottom':
+        changeHeight($input, mouseY, paddingBottom);
+        break;
+      case 'both':
+        changeHeight($input, mouseY, paddingBottom);
+        changeWidth($input, mouseX, paddingRight);
+      }      
+    });
+  }
+
+  function changeWidth($input, mouseX, padding){
+    var rect = $input[0].getBoundingClientRect();    
+    var newWidth = rect.width + mouseX - rect.right - padding;
+    $input.css('width', newWidth.toString() + 'px');
+  }
+
+  function changeHeight($input, mouseY, padding){
+    var rect = $input[0].getBoundingClientRect();
+    var newHeight = rect.height + mouseY - rect.bottom - padding;
+    $input.css('height', newHeight.toString() + 'px');
+  }
+
+
   // Text data type editor
   function pgTextEditor(args) {
     var $input, $wrapper, $buttons;
@@ -140,6 +187,7 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -297,6 +345,7 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -419,6 +468,7 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
@@ -518,6 +568,7 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 1e29c3f..288e57f 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -505,6 +505,38 @@ input.editor-checkbox:focus {
   -moz-border-radius:10px;
   border-radius:10px;
 }
+
+.drag-border{
+  background: transparent;
+  position: absolute;
+}
+
+.drag-border[data=right]{
+  cursor: ew-resize;  
+  top: 0;
+  right: -10px;
+  bottom: 0;
+  width: 20px;
+}
+
+.drag-border[data=bottom]{
+  cursor: ns-resize;
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: -10px;
+  height: 20px; 
+}
+
+.drag-border[data=both]{
+  cursor: move;
+  position: absolute;
+  bottom: -10px;
+  right: -10px;
+  width: 20px;
+  height: 20px;
+}
+
 .pg_textarea {
   backround:#fff;
   width:250px;


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
@ 2018-03-01 22:10 ` Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Joao De Almeida Pereira @ 2018-03-01 22:10 UTC (permalink / raw)
  To: Neethu Mariya Joy <[email protected]>; +Cc: pgadmin-hackers

Hello Neethu,
We passed the patch through our CI pipeline and all tests pass.
The code looks good, but we are trying to decouple files as much  as we can
so that we do not end up with files with over 1000 lines, that are hard to
read and to maintain. Also we are trying to create Unit Tests to have more
coverage in our Javascript code.

Can you split the new implementation code into it's own file and create
some tests to ensure the behavior will not be broken in the future?iYou
have some examples
on: pgadmin/browser/server_groups/servers/databases/external_tables/*

Thanks
Joao

On Thu, Mar 1, 2018 at 10:37 AM Neethu Mariya Joy <[email protected]>
wrote:

> Hi,
> I am Neethu Mariya Joy, an undergraduate pursuing BE in Computer Science
> at BITS Pilani.
>
> I've attempted to fix https://redmine.postgresql.org/issues/3083. Since
> the textarea resize feature is the default HTML feature, I have not changed
> it. Instead, I've added draggable borders to the wrapper which expands the
> textarea inside it.
>
> I'm attaching my patch as bug3083.diff below as per the contribution
> guidelines.
>
> Hope this helps. Thank you for your consideration!
>
> Sincerely,
> Neethu Mariya Joy
> GitHub <https://github.com/Roboneet; | Linkedin
> <https://www.linkedin.com/in/neethu-mariya-joy-653655128/;
>
>
>


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
@ 2018-03-28 12:03   ` Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Akshay Joshi @ 2018-03-28 12:03 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi

On Fri, Mar 2, 2018 at 3:40 AM, Joao De Almeida Pereira <
[email protected]> wrote:

> Hello Neethu,
> We passed the patch through our CI pipeline and all tests pass.
> The code looks good, but we are trying to decouple files as much  as we
> can so that we do not end up with files with over 1000 lines, that are hard
> to read and to maintain. Also we are trying to create Unit Tests to have
> more coverage in our Javascript code.
>
> Can you split the new implementation code into it's own file and create
> some tests to ensure the behavior will not be broken in the future?iYou
> have some examples on: pgadmin/browser/server_groups/servers/databases/
> external_tables/*
>

    I have spilt the new implementation into different file. Its' been hard
to write jasmine/feature test case as it requires drag event and exact
co-ordinate to resize the slickgrid cell.
    Attached is the modified patch.


>
> Thanks
> Joao
>
> On Thu, Mar 1, 2018 at 10:37 AM Neethu Mariya Joy <
> [email protected]> wrote:
>
>> Hi,
>> I am Neethu Mariya Joy, an undergraduate pursuing BE in Computer Science
>> at BITS Pilani.
>>
>> I've attempted to fix https://redmine.postgresql.org/issues/3083. Since
>> the textarea resize feature is the default HTML feature, I have not changed
>> it. Instead, I've added draggable borders to the wrapper which expands the
>> textarea inside it.
>>
>> I'm attaching my patch as bug3083.diff below as per the contribution
>> guidelines.
>>
>> Hope this helps. Thank you for your consideration!
>>
>> Sincerely,
>> Neethu Mariya Joy
>> GitHub <https://github.com/Roboneet; | Linkedin
>> <https://www.linkedin.com/in/neethu-mariya-joy-653655128/;
>>
>>
>>


-- 
*Akshay Joshi*

*Sr. Software Architect *



*Phone: +91 20-3058-9517Mobile: +91 976-788-8246*


Attachments:

  [application/octet-stream] RM_3083_v2.patch (54.2K, 3-RM_3083_v2.patch)
  download | inline diff:
diff --git a/web/pgadmin/static/js/slickgrid/editors.js b/web/pgadmin/static/js/slickgrid/editors.js
index 7652bf3..ccd9167 100644
--- a/web/pgadmin/static/js/slickgrid/editors.js
+++ b/web/pgadmin/static/js/slickgrid/editors.js
@@ -3,961 +3,970 @@
  * @module Editors
  * @namespace Slick
  */
-
-(function($) {
-  // register namespace
-  $.extend(true, window, {
-    'Slick': {
-      'Editors': {
-        'pgText': pgTextEditor,
-        'JsonText': JsonTextEditor,
-        'CustomNumber': CustomNumberEditor,
-        'Checkbox': pgCheckboxEditor,
-        // Below editor will read only editors, Just to display data
-        'ReadOnlyText': ReadOnlyTextEditor,
-        'ReadOnlyCheckbox': ReadOnlyCheckboxEditor,
-        'ReadOnlypgText': ReadOnlypgTextEditor,
-        'ReadOnlyJsonText': ReadOnlyJsonTextEditor,
+define([
+  'sources/slickgrid/resize_editor',
+],
+function (resizeEditor) {
+
+  (function($) {
+    // register namespace
+    $.extend(true, window, {
+      'Slick': {
+        'Editors': {
+          'pgText': pgTextEditor,
+          'JsonText': JsonTextEditor,
+          'CustomNumber': CustomNumberEditor,
+          'Checkbox': pgCheckboxEditor,
+          // Below editor will read only editors, Just to display data
+          'ReadOnlyText': ReadOnlyTextEditor,
+          'ReadOnlyCheckbox': ReadOnlyCheckboxEditor,
+          'ReadOnlypgText': ReadOnlypgTextEditor,
+          'ReadOnlyJsonText': ReadOnlyJsonTextEditor,
+        },
       },
-    },
-  });
-
-  // return wrapper element
-  function getWrapper() {
-    return $('<div class=\'pg_text_editor\' />');
-  }
-
-  // return textarea element
-  function getTextArea() {
-    return $('<textarea class=\'pg_textarea text-12\' hidefocus rows=5\'>');
-  }
-
-  // Generate and return editor buttons
-  function getButtons(editable) {
-    var $buttons = $('<div class=\'pg_buttons\' />'),
-      label = editable ? 'Cancel' : 'OK',
-      button_type = editable ? 'btn-danger' : 'btn-primary';
-
-    if (editable) {
-      $('<button class=\'btn btn-primary fa fa-lg fa-save long_text_editor pg-alertify-button\'>Save</button>')
-        .appendTo($buttons);
+    });
+
+    // return wrapper element
+    function getWrapper() {
+      return $('<div class=\'pg_text_editor\' />');
     }
 
-    $('<button class=\'btn ' + button_type + ' fa fa-lg fa-times long_text_editor pg-alertify-button\'>' + label + '</button>')
-      .appendTo($buttons);
-    return $buttons;
-  }
-
-  function is_valid_array(val) {
-    val = $.trim(val);
-    return !(val != '' && (val.charAt(0) != '{' || val.charAt(val.length - 1) != '}'));
-  }
-  /*
-   * This function handles the [default] and [null] values for cells
-   * if row is copied, otherwise returns the editor value.
-   * @param {args} editor object
-   * @param {item} row cell values
-   * @param {state} entered value
-   * @param {column_type} type of column
-   */
-  function setValue(args, item, state, column_type) {
-    // declare a 2-d array which tracks the status of each updated cell
-    // If a cell is edited for the 1st time and state is null,
-    // set cell value to [default] and update its status [row][cell] to 1.
-    // If same cell is edited again, and kept blank, set cell value to [null]
-
-    // If a row is copied
-    var grid = args.grid;
-    if (item.is_row_copied) {
-      if (!grid.copied_rows) {
-        grid.copied_rows = [
-          [],
-        ];
-      }
+    // return textarea element
+    function getTextArea() {
+      return $('<textarea class=\'pg_textarea text-12\' hidefocus rows=5\'>');
+    }
 
-      var active_cell = grid.getActiveCell(),
-        row = active_cell['row'],
-        cell = active_cell['cell'],
-        last_value = item[args.column.pos];
-
-      last_value = (column_type === 'number') ?
-        (_.isEmpty(last_value) || last_value) : last_value;
-
-      item[args.column.field] = state;
-      if (last_value && _.isNull(state) &&
-        (_.isUndefined(grid.copied_rows[row]) ||
-          _.isUndefined(grid.copied_rows[row][cell]))
-      ) {
-        item[args.column.field] = undefined;
-        if (grid.copied_rows[row] == undefined) grid.copied_rows[row] = [];
-        grid.copied_rows[row][cell] = 1;
+    // Generate and return editor buttons
+    function getButtons(editable) {
+      var $buttons = $('<div class=\'pg_buttons\' />'),
+        label = editable ? 'Cancel' : 'OK',
+        button_type = editable ? 'btn-danger' : 'btn-primary';
+
+      if (editable) {
+        $('<button class=\'btn btn-primary fa fa-lg fa-save long_text_editor pg-alertify-button\'>Save</button>')
+          .appendTo($buttons);
       }
-    } else {
-      item[args.column.field] = state;
+
+      $('<button class=\'btn ' + button_type + ' fa fa-lg fa-times long_text_editor pg-alertify-button\'>' + label + '</button>')
+        .appendTo($buttons);
+      return $buttons;
     }
-  }
-
-  function calculateEditorPosition(position, $wrapper) {
-    var $edit_grid = $wrapper.parent().find('#datagrid');
-    var _elem_height = $edit_grid.height(),
-      is_hidden, _position;
-    // We cannot display editor partially visible so we will lift it above select column
-    if (position.top > _elem_height) {
-      is_hidden = position.bottom - _elem_height;
+
+    function is_valid_array(val) {
+      val = $.trim(val);
+      return !(val != '' && (val.charAt(0) != '{' || val.charAt(val.length - 1) != '}'));
     }
+    /*
+     * This function handles the [default] and [null] values for cells
+     * if row is copied, otherwise returns the editor value.
+     * @param {args} editor object
+     * @param {item} row cell values
+     * @param {state} entered value
+     * @param {column_type} type of column
+     */
+    function setValue(args, item, state, column_type) {
+      // declare a 2-d array which tracks the status of each updated cell
+      // If a cell is edited for the 1st time and state is null,
+      // set cell value to [default] and update its status [row][cell] to 1.
+      // If same cell is edited again, and kept blank, set cell value to [null]
+
+      // If a row is copied
+      var grid = args.grid;
+      if (item.is_row_copied) {
+        if (!grid.copied_rows) {
+          grid.copied_rows = [
+            [],
+          ];
+        }
 
-    if (is_hidden) {
-      _position = position.top - is_hidden;
-    } else {
-      _position = position.top - 7;
+        var active_cell = grid.getActiveCell(),
+          row = active_cell['row'],
+          cell = active_cell['cell'],
+          last_value = item[args.column.pos];
+
+        last_value = (column_type === 'number') ?
+          (_.isEmpty(last_value) || last_value) : last_value;
+
+        item[args.column.field] = state;
+        if (last_value && _.isNull(state) &&
+          (_.isUndefined(grid.copied_rows[row]) ||
+            _.isUndefined(grid.copied_rows[row][cell]))
+        ) {
+          item[args.column.field] = undefined;
+          if (grid.copied_rows[row] == undefined) grid.copied_rows[row] = [];
+          grid.copied_rows[row][cell] = 1;
+        }
+      } else {
+        item[args.column.field] = state;
+      }
     }
-    position.top = _position;
 
-    var grid_width = $edit_grid.width(),
-      popup_width = $wrapper.width() + 32;
-    popup_width += position.left;
+    function calculateEditorPosition(position, $wrapper) {
+      var $edit_grid = $wrapper.parent().find('#datagrid');
+      var _elem_height = $edit_grid.height(),
+        is_hidden, _position;
+      // We cannot display editor partially visible so we will lift it above select column
+      if (position.top > _elem_height) {
+        is_hidden = position.bottom - _elem_height;
+      }
 
-    if (popup_width > grid_width) {
-      position.left -= (popup_width - grid_width);
-    }
-    return position;
-  }
-
-  // Text data type editor
-  function pgTextEditor(args) {
-    var $input, $wrapper, $buttons;
-    var defaultValue;
-    var scope = this;
-
-    this.init = function() {
-      var $container = $('body');
-
-      $wrapper = getWrapper().appendTo($container);
-      $input = getTextArea().appendTo($wrapper);
-      $buttons = getButtons(true).appendTo($wrapper);
-
-      $buttons.find('button:first').on('click', this.save);
-      $buttons.find('button:last').on('click', this.cancel);
-      $input.bind('keydown', this.handleKeyDown);
-
-      scope.position(args.position);
-      $input.focus().select();
-    };
-
-    this.handleKeyDown = function(e) {
-      if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
-        scope.save();
-      } else if (e.which == $.ui.keyCode.ESCAPE) {
-        e.preventDefault();
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
-        e.preventDefault();
-        args.grid.navigatePrev();
-      } else if (e.which == $.ui.keyCode.TAB) {
-        e.preventDefault();
-        args.grid.navigateNext();
+      if (is_hidden) {
+        _position = position.top - is_hidden;
+      } else {
+        _position = position.top - 7;
       }
-    };
-
-    this.save = function() {
-      args.commitChanges();
-    };
-
-    this.cancel = function() {
-      $input.val(defaultValue);
-      args.cancelChanges();
-    };
-
-    this.hide = function() {
-      $wrapper.hide();
-    };
-
-    this.show = function() {
-      $wrapper.show();
-    };
-
-    this.position = function(position) {
-      calculateEditorPosition(position, $wrapper);
-      $wrapper
-        .css('top', position.top)
-        .css('left', position.left);
-    };
-
-    this.destroy = function() {
-      $wrapper.remove();
-    };
-
-    this.focus = function() {
-      $input.focus();
-    };
-
-    // When text editor opens
-    this.loadValue = function(item) {
-      if (
-        _.isUndefined(item[args.column.field]) ||
-        _.isNull(item[args.column.field])
-      ) {
-        $input.val(defaultValue = '');
-        return;
+      position.top = _position;
+
+      var grid_width = $edit_grid.width(),
+        popup_width = $wrapper.width() + 32;
+      popup_width += position.left;
+
+      if (popup_width > grid_width) {
+        position.left -= (popup_width - grid_width);
       }
+      return position;
+    }
+
+    // Text data type editor
+    function pgTextEditor(args) {
+      var $input, $wrapper, $buttons;
+      var defaultValue;
+      var scope = this;
+
+      this.init = function() {
+        var $container = $('body');
+
+        $wrapper = getWrapper().appendTo($container);
+        $input = getTextArea().appendTo($wrapper);
+        $buttons = getButtons(true).appendTo($wrapper);
+
+        $buttons.find('button:first').on('click', this.save);
+        $buttons.find('button:last').on('click', this.cancel);
+        $input.bind('keydown', this.handleKeyDown);
+
+        resizeEditor.resizeContentOnDrag($wrapper, $input);
+        scope.position(args.position);
+        $input.focus().select();
+      };
+
+      this.handleKeyDown = function(e) {
+        if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
+          scope.save();
+        } else if (e.which == $.ui.keyCode.ESCAPE) {
+          e.preventDefault();
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
+          e.preventDefault();
+          args.grid.navigatePrev();
+        } else if (e.which == $.ui.keyCode.TAB) {
+          e.preventDefault();
+          args.grid.navigateNext();
+        }
+      };
+
+      this.save = function() {
+        args.commitChanges();
+      };
+
+      this.cancel = function() {
+        $input.val(defaultValue);
+        args.cancelChanges();
+      };
+
+      this.hide = function() {
+        $wrapper.hide();
+      };
+
+      this.show = function() {
+        $wrapper.show();
+      };
+
+      this.position = function(position) {
+        calculateEditorPosition(position, $wrapper);
+        $wrapper
+          .css('top', position.top)
+          .css('left', position.left);
+      };
 
-      if (!args.column.is_array) {
-        if (item[args.column.field] === '') {
-          $input.val(defaultValue = '\'\'');
-        } else if (item[args.column.field] === '\'\'') {
-          $input.val(defaultValue = '\\\'\\\'');
-        } else if (item[args.column.field] === '""') {
-          $input.val(defaultValue = '\\"\\"');
+      this.destroy = function() {
+        $wrapper.remove();
+      };
+
+      this.focus = function() {
+        $input.focus();
+      };
+
+      // When text editor opens
+      this.loadValue = function(item) {
+        if (
+          _.isUndefined(item[args.column.field]) ||
+          _.isNull(item[args.column.field])
+        ) {
+          $input.val(defaultValue = '');
+          return;
+        }
+
+        if (!args.column.is_array) {
+          if (item[args.column.field] === '') {
+            $input.val(defaultValue = '\'\'');
+          } else if (item[args.column.field] === '\'\'') {
+            $input.val(defaultValue = '\\\'\\\'');
+          } else if (item[args.column.field] === '""') {
+            $input.val(defaultValue = '\\"\\"');
+          } else {
+            $input.val(defaultValue = item[args.column.field]);
+            $input.select();
+          }
         } else {
           $input.val(defaultValue = item[args.column.field]);
           $input.select();
         }
-      } else {
-        $input.val(defaultValue = item[args.column.field]);
-        $input.select();
-      }
-    };
+      };
 
-    this.serializeValue = function() {
+      this.serializeValue = function() {
 
-      var value = $input.val();
-      // If empty return null
-      if (value === '') {
-        return null;
-      }
+        var value = $input.val();
+        // If empty return null
+        if (value === '') {
+          return null;
+        }
 
-      if (!args.column.is_array) {
-        if (value === '\'\'' || value === '""') {
-          return '';
-        } else if (value === '\\\'\\\'') {
-          return '\'\'';
-        } else if (value === '\\"\\"') {
-          return '""';
+        if (!args.column.is_array) {
+          if (value === '\'\'' || value === '""') {
+            return '';
+          } else if (value === '\\\'\\\'') {
+            return '\'\'';
+          } else if (value === '\\"\\"') {
+            return '""';
+          } else {
+            return value;
+          }
         } else {
-          return value;
+          return $.trim(value);
         }
-      } else {
-        return $.trim(value);
-      }
-    };
+      };
 
-    this.applyValue = function(item, state) {
-      setValue(args, item, state, 'text');
-    };
+      this.applyValue = function(item, state) {
+        setValue(args, item, state, 'text');
+      };
 
-    this.isValueChanged = function() {
-      // Use _.isNull(value) for comparison for null instead of
-      // defaultValue == null, because it returns true for undefined value.
-      if ($input.val() == '' && _.isUndefined(defaultValue)) {
-        return false;
-      } else {
-        return (!($input.val() == '' && _.isNull(defaultValue))) &&
-          ($input.val() !== defaultValue);
-      }
-    };
+      this.isValueChanged = function() {
+        // Use _.isNull(value) for comparison for null instead of
+        // defaultValue == null, because it returns true for undefined value.
+        if ($input.val() == '' && _.isUndefined(defaultValue)) {
+          return false;
+        } else {
+          return (!($input.val() == '' && _.isNull(defaultValue))) &&
+            ($input.val() !== defaultValue);
+        }
+      };
 
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator($input.val());
-        if (!validationResults.valid) {
-          return validationResults;
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator($input.val());
+          if (!validationResults.valid) {
+            return validationResults;
+          }
+        }
+
+        if (args.column.is_array && !is_valid_array($input.val())) {
+          return {
+            valid: false,
+            msg: 'Array must start with \'{\' and end with \'}\'',
+          };
         }
-      }
 
-      if (args.column.is_array && !is_valid_array($input.val())) {
         return {
-          valid: false,
-          msg: 'Array must start with \'{\' and end with \'}\'',
+          valid: true,
+          msg: null,
         };
-      }
+      };
 
-      return {
-        valid: true,
-        msg: null,
-      };
-    };
-
-    this.init();
-  }
-
-  // JSON data type editor
-  function JsonTextEditor(args) {
-    var $input, $wrapper, $buttons;
-    var defaultValue;
-    var scope = this;
-
-    this.init = function() {
-      var $container = $('body');
-
-      $wrapper = getWrapper().appendTo($container);
-      $input = getTextArea().appendTo($wrapper);
-      $buttons = getButtons(true).appendTo($wrapper);
-
-      $buttons.find('button:first').on('click', this.save);
-      $buttons.find('button:last').on('click', this.cancel);
-      $input.bind('keydown', this.handleKeyDown);
-
-      scope.position(args.position);
-      $input.focus().select();
-    };
-
-    this.handleKeyDown = function(e) {
-      if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
-        scope.save();
-      } else if (e.which == $.ui.keyCode.ESCAPE) {
-        e.preventDefault();
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
-        e.preventDefault();
-        args.grid.navigatePrev();
-      } else if (e.which == $.ui.keyCode.TAB) {
-        e.preventDefault();
-        args.grid.navigateNext();
-      }
-    };
-
-    this.save = function() {
-      args.commitChanges();
-    };
-
-    this.cancel = function() {
-      $input.val(defaultValue);
-      args.cancelChanges();
-    };
-
-    this.hide = function() {
-      $wrapper.hide();
-    };
-
-    this.show = function() {
-      $wrapper.show();
-    };
-
-    this.position = function(position) {
-      calculateEditorPosition(position, $wrapper);
-      $wrapper
-        .css('top', position.top)
-        .css('left', position.left);
-    };
-
-    this.destroy = function() {
-      $wrapper.remove();
-    };
-
-    this.focus = function() {
-      $input.focus();
-    };
-
-    this.loadValue = function(item) {
-      var data = defaultValue = item[args.column.field];
-      if (data && typeof data === 'object' && !Array.isArray(data)) {
-        data = JSON.stringify(data, null, 4);
-      } else if (Array.isArray(data)) {
-        var temp = [];
-        $.each(data, function(i, val) {
-          if (typeof val === 'object') {
-            temp.push(JSON.stringify(val, null, 4));
-          } else {
-            temp.push(val);
-          }
-        });
-        data = '[' + temp.join() + ']';
-      }
-      $input.val(data);
-      $input.select();
-    };
+      this.init();
+    }
 
-    this.serializeValue = function() {
-      if ($input.val() === '') {
-        return null;
-      }
-      return $input.val();
-    };
+    // JSON data type editor
+    function JsonTextEditor(args) {
+      var $input, $wrapper, $buttons;
+      var defaultValue;
+      var scope = this;
 
-    this.applyValue = function(item, state) {
-      setValue(args, item, state, 'text');
-    };
+      this.init = function() {
+        var $container = $('body');
 
-    this.isValueChanged = function() {
-      if ($input.val() == '' && _.isUndefined(defaultValue)) {
-        return false;
-      } else {
-        return (!($input.val() == '' && _.isNull(defaultValue))) && ($input.val() != defaultValue);
-      }
-    };
+        $wrapper = getWrapper().appendTo($container);
+        $input = getTextArea().appendTo($wrapper);
+        $buttons = getButtons(true).appendTo($wrapper);
+
+        $buttons.find('button:first').on('click', this.save);
+        $buttons.find('button:last').on('click', this.cancel);
+        $input.bind('keydown', this.handleKeyDown);
+
+        resizeEditor.resizeContentOnDrag($wrapper, $input);
+        scope.position(args.position);
+        $input.focus().select();
+      };
 
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator($input.val());
-        if (!validationResults.valid) {
-          return validationResults;
+      this.handleKeyDown = function(e) {
+        if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
+          scope.save();
+        } else if (e.which == $.ui.keyCode.ESCAPE) {
+          e.preventDefault();
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
+          e.preventDefault();
+          args.grid.navigatePrev();
+        } else if (e.which == $.ui.keyCode.TAB) {
+          e.preventDefault();
+          args.grid.navigateNext();
         }
-      }
+      };
 
-      return {
-        valid: true,
-        msg: null,
-      };
-    };
-
-    this.init();
-  }
-
-  // Text data type editor
-  function ReadOnlypgTextEditor(args) {
-    var $input, $wrapper, $buttons;
-    var defaultValue;
-    var scope = this;
-
-    this.init = function() {
-      var $container = $('body');
-
-      $wrapper = getWrapper().appendTo($container);
-      $input = getTextArea().appendTo($wrapper);
-      $buttons = getButtons(false).appendTo($wrapper);
-
-      $buttons.find('button:first').on('click', this.cancel);
-      $input.bind('keydown', this.handleKeyDown);
-
-      scope.position(args.position);
-      $input.focus().select();
-    };
-
-    this.handleKeyDown = function(e) {
-      if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.ESCAPE) {
-        e.preventDefault();
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
-        scope.cancel();
-        e.preventDefault();
-        args.grid.navigatePrev();
-      } else if (e.which == $.ui.keyCode.TAB) {
-        scope.cancel();
-        e.preventDefault();
-        args.grid.navigateNext();
-      }
-    };
-
-    this.cancel = function() {
-      $input.val(defaultValue);
-      args.cancelChanges();
-    };
-
-    this.hide = function() {
-      $wrapper.hide();
-    };
-
-    this.show = function() {
-      $wrapper.show();
-    };
-
-    this.position = function(position) {
-      calculateEditorPosition(position, $wrapper);
-      $wrapper
-        .css('top', position.top)
-        .css('left', position.left);
-    };
-
-    this.destroy = function() {
-      $wrapper.remove();
-    };
-
-    this.focus = function() {
-      $input.focus();
-    };
-
-    this.loadValue = function(item) {
-      $input.val(defaultValue = item[args.column.field]);
-      $input.select();
-    };
-
-    this.serializeValue = function() {
-      return $input.val();
-    };
-
-    this.applyValue = function(item, state) {
-      item[args.column.field] = state;
-    };
-
-    this.isValueChanged = function() {
-      return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
-    };
-
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator($input.val());
-        if (!validationResults.valid) {
-          return validationResults;
+      this.save = function() {
+        args.commitChanges();
+      };
+
+      this.cancel = function() {
+        $input.val(defaultValue);
+        args.cancelChanges();
+      };
+
+      this.hide = function() {
+        $wrapper.hide();
+      };
+
+      this.show = function() {
+        $wrapper.show();
+      };
+
+      this.position = function(position) {
+        calculateEditorPosition(position, $wrapper);
+        $wrapper
+          .css('top', position.top)
+          .css('left', position.left);
+      };
+
+      this.destroy = function() {
+        $wrapper.remove();
+      };
+
+      this.focus = function() {
+        $input.focus();
+      };
+
+      this.loadValue = function(item) {
+        var data = defaultValue = item[args.column.field];
+        if (data && typeof data === 'object' && !Array.isArray(data)) {
+          data = JSON.stringify(data, null, 4);
+        } else if (Array.isArray(data)) {
+          var temp = [];
+          $.each(data, function(i, val) {
+            if (typeof val === 'object') {
+              temp.push(JSON.stringify(val, null, 4));
+            } else {
+              temp.push(val);
+            }
+          });
+          data = '[' + temp.join() + ']';
         }
-      }
+        $input.val(data);
+        $input.select();
+      };
 
-      return {
-        valid: true,
-        msg: null,
-      };
-    };
-
-    this.init();
-  }
-
-  // JSON data type editor
-  function ReadOnlyJsonTextEditor(args) {
-    var $input, $wrapper, $buttons;
-    var defaultValue;
-    var scope = this;
-
-    this.init = function() {
-      var $container = $('body');
-
-      $wrapper = getWrapper().appendTo($container);
-      $input = getTextArea().appendTo($wrapper);
-      $buttons = getButtons(false).appendTo($wrapper);
-
-      $buttons.find('button:first').on('click', this.cancel);
-      $input.bind('keydown', this.handleKeyDown);
-
-      scope.position(args.position);
-      $input.focus().select();
-    };
-
-    this.handleKeyDown = function(e) {
-      if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.ESCAPE) {
-        e.preventDefault();
-        scope.cancel();
-      } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
-        scope.cancel();
-        e.preventDefault();
-        args.grid.navigatePrev();
-      } else if (e.which == $.ui.keyCode.TAB) {
-        scope.cancel();
-        e.preventDefault();
-        args.grid.navigateNext();
-      }
-    };
-
-    this.cancel = function() {
-      $input.val(defaultValue);
-      args.cancelChanges();
-    };
-
-    this.hide = function() {
-      $wrapper.hide();
-    };
-
-    this.show = function() {
-      $wrapper.show();
-    };
-
-    this.position = function(position) {
-      calculateEditorPosition(position, $wrapper);
-      $wrapper
-        .css('top', position.top)
-        .css('left', position.left);
-    };
-
-    this.destroy = function() {
-      $wrapper.remove();
-    };
-
-    this.focus = function() {
-      $input.focus();
-    };
-
-    this.loadValue = function(item) {
-      var data = defaultValue = item[args.column.field];
-      if (typeof data === 'object' && !Array.isArray(data)) {
-        data = JSON.stringify(data, null, 4);
-      } else if (Array.isArray(data)) {
-        var temp = [];
-        $.each(data, function(i, val) {
-          if (typeof val === 'object') {
-            temp.push(JSON.stringify(val, null, 4));
-          } else {
-            temp.push(val);
+      this.serializeValue = function() {
+        if ($input.val() === '') {
+          return null;
+        }
+        return $input.val();
+      };
+
+      this.applyValue = function(item, state) {
+        setValue(args, item, state, 'text');
+      };
+
+      this.isValueChanged = function() {
+        if ($input.val() == '' && _.isUndefined(defaultValue)) {
+          return false;
+        } else {
+          return (!($input.val() == '' && _.isNull(defaultValue))) && ($input.val() != defaultValue);
+        }
+      };
+
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator($input.val());
+          if (!validationResults.valid) {
+            return validationResults;
           }
-        });
-        data = '[' + temp.join() + ']';
-      }
-      $input.val(data);
-      $input.select();
-    };
+        }
 
-    this.serializeValue = function() {
-      return $input.val();
-    };
+        return {
+          valid: true,
+          msg: null,
+        };
+      };
 
-    this.applyValue = function(item, state) {
-      item[args.column.field] = state;
-    };
+      this.init();
+    }
+
+    // Text data type editor
+    function ReadOnlypgTextEditor(args) {
+      var $input, $wrapper, $buttons;
+      var defaultValue;
+      var scope = this;
+
+      this.init = function() {
+        var $container = $('body');
 
-    this.isValueChanged = function() {
-      return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
-    };
+        $wrapper = getWrapper().appendTo($container);
+        $input = getTextArea().appendTo($wrapper);
+        $buttons = getButtons(false).appendTo($wrapper);
 
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator($input.val());
-        if (!validationResults.valid) {
-          return validationResults;
+        $buttons.find('button:first').on('click', this.cancel);
+        $input.bind('keydown', this.handleKeyDown);
+
+        resizeEditor.resizeContentOnDrag($wrapper, $input);
+        scope.position(args.position);
+        $input.focus().select();
+      };
+
+      this.handleKeyDown = function(e) {
+        if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.ESCAPE) {
+          e.preventDefault();
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
+          scope.cancel();
+          e.preventDefault();
+          args.grid.navigatePrev();
+        } else if (e.which == $.ui.keyCode.TAB) {
+          scope.cancel();
+          e.preventDefault();
+          args.grid.navigateNext();
         }
-      }
+      };
+
+      this.cancel = function() {
+        $input.val(defaultValue);
+        args.cancelChanges();
+      };
 
-      return {
-        valid: true,
-        msg: null,
+      this.hide = function() {
+        $wrapper.hide();
       };
-    };
 
-    this.init();
-  }
+      this.show = function() {
+        $wrapper.show();
+      };
 
-  function ReadOnlyTextEditor(args) {
-    var $input;
-    var defaultValue;
+      this.position = function(position) {
+        calculateEditorPosition(position, $wrapper);
+        $wrapper
+          .css('top', position.top)
+          .css('left', position.left);
+      };
 
-    this.init = function() {
-      $input = $('<INPUT type=text class=\'editor-text\' readonly/>')
-        .appendTo(args.container)
-        .bind('keydown.nav', function(e) {
-          if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
-            e.stopImmediatePropagation();
-          }
-        })
-        .focus()
-        .select();
-    };
+      this.destroy = function() {
+        $wrapper.remove();
+      };
 
-    this.destroy = function() {
-      $input.remove();
-    };
+      this.focus = function() {
+        $input.focus();
+      };
 
-    this.focus = function() {
-      $input.focus();
-    };
+      this.loadValue = function(item) {
+        $input.val(defaultValue = item[args.column.field]);
+        $input.select();
+      };
 
-    this.getValue = function() {
-      return $input.val();
-    };
+      this.serializeValue = function() {
+        return $input.val();
+      };
 
-    this.loadValue = function(item) {
-      var value = item[args.column.field];
+      this.applyValue = function(item, state) {
+        item[args.column.field] = state;
+      };
 
-      // Check if value is null or undefined
-      if (value === undefined && typeof value === 'undefined') {
-        value = '';
-      }
-      defaultValue = value;
-      $input.val(defaultValue);
-      $input[0].defaultValue = defaultValue;
-      $input.select();
-    };
-
-    this.serializeValue = function() {
-      return $input.val();
-    };
-
-    this.applyValue = function(item, state) {
-      item[args.column.field] = state;
-    };
-
-    this.isValueChanged = function() {
-      return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
-    };
-
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator($input.val());
-        if (!validationResults.valid) {
-          return validationResults;
+      this.isValueChanged = function() {
+        return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
+      };
+
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator($input.val());
+          if (!validationResults.valid) {
+            return validationResults;
+          }
         }
-      }
 
-      return {
-        valid: true,
-        msg: null,
+        return {
+          valid: true,
+          msg: null,
+        };
       };
-    };
 
-    this.init();
-  }
+      this.init();
+    }
 
-  function ReadOnlyCheckboxEditor(args) {
-    var $select;
-    var defaultValue;
+    // JSON data type editor
+    function ReadOnlyJsonTextEditor(args) {
+      var $input, $wrapper, $buttons;
+      var defaultValue;
+      var scope = this;
 
-    this.init = function() {
-      $select = $('<INPUT type=checkbox value=\'true\' class=\'editor-checkbox\' hideFocus disabled>');
-      $select.appendTo(args.container);
-      $select.focus();
-    };
+      this.init = function() {
+        var $container = $('body');
 
-    this.destroy = function() {
-      $select.remove();
-    };
+        $wrapper = getWrapper().appendTo($container);
+        $input = getTextArea().appendTo($wrapper);
+        $buttons = getButtons(false).appendTo($wrapper);
 
-    this.focus = function() {
-      $select.focus();
-    };
+        $buttons.find('button:first').on('click', this.cancel);
+        $input.bind('keydown', this.handleKeyDown);
 
-    this.loadValue = function(item) {
-      defaultValue = item[args.column.pos];
-      if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
-        $select.prop('indeterminate', true);
-        $select.data('checked', 2);
-      } else {
-        defaultValue = !!item[args.column.pos];
-        if (defaultValue) {
-          $select.prop('checked', true);
-          $select.data('checked', 0);
-        } else {
-          $select.prop('checked', false);
-          $select.data('checked', 1);
+        resizeEditor.resizeContentOnDrag($wrapper, $input);
+        scope.position(args.position);
+        $input.focus().select();
+      };
+
+      this.handleKeyDown = function(e) {
+        if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.ESCAPE) {
+          e.preventDefault();
+          scope.cancel();
+        } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
+          scope.cancel();
+          e.preventDefault();
+          args.grid.navigatePrev();
+        } else if (e.which == $.ui.keyCode.TAB) {
+          scope.cancel();
+          e.preventDefault();
+          args.grid.navigateNext();
         }
-      }
-    };
+      };
 
-    this.serializeValue = function() {
-      if ($select.prop('indeterminate')) {
-        return null;
-      }
-      return $select.prop('checked');
-    };
+      this.cancel = function() {
+        $input.val(defaultValue);
+        args.cancelChanges();
+      };
 
-    this.applyValue = function(item, state) {
-      item[args.column.pos] = state;
-    };
+      this.hide = function() {
+        $wrapper.hide();
+      };
+
+      this.show = function() {
+        $wrapper.show();
+      };
+
+      this.position = function(position) {
+        calculateEditorPosition(position, $wrapper);
+        $wrapper
+          .css('top', position.top)
+          .css('left', position.left);
+      };
+
+      this.destroy = function() {
+        $wrapper.remove();
+      };
 
-    this.isValueChanged = function() {
-      // var select_value = this.serializeValue();
-      var select_value = $select.data('checked');
-      return (!(select_value === 2 && (defaultValue == null || defaultValue == undefined))) &&
-        (select_value !== defaultValue);
-    };
+      this.focus = function() {
+        $input.focus();
+      };
 
-    this.validate = function() {
-      return {
-        valid: true,
-        msg: null,
+      this.loadValue = function(item) {
+        var data = defaultValue = item[args.column.field];
+        if (typeof data === 'object' && !Array.isArray(data)) {
+          data = JSON.stringify(data, null, 4);
+        } else if (Array.isArray(data)) {
+          var temp = [];
+          $.each(data, function(i, val) {
+            if (typeof val === 'object') {
+              temp.push(JSON.stringify(val, null, 4));
+            } else {
+              temp.push(val);
+            }
+          });
+          data = '[' + temp.join() + ']';
+        }
+        $input.val(data);
+        $input.select();
       };
-    };
 
-    this.init();
-  }
+      this.serializeValue = function() {
+        return $input.val();
+      };
 
-  function CustomNumberEditor(args) {
-    var $input;
-    var defaultValue;
+      this.applyValue = function(item, state) {
+        item[args.column.field] = state;
+      };
 
-    this.init = function() {
-      $input = $('<INPUT type=text class=\'editor-text\' />');
+      this.isValueChanged = function() {
+        return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
+      };
 
-      $input.bind('keydown.nav', function(e) {
-        if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
-          e.stopImmediatePropagation();
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator($input.val());
+          if (!validationResults.valid) {
+            return validationResults;
+          }
         }
-      });
 
-      $input.appendTo(args.container);
-      $input.focus().select();
-    };
+        return {
+          valid: true,
+          msg: null,
+        };
+      };
 
-    this.destroy = function() {
-      $input.remove();
-    };
+      this.init();
+    }
 
-    this.focus = function() {
-      $input.focus();
-    };
+    function ReadOnlyTextEditor(args) {
+      var $input;
+      var defaultValue;
+
+      this.init = function() {
+        $input = $('<INPUT type=text class=\'editor-text\' readonly/>')
+          .appendTo(args.container)
+          .bind('keydown.nav', function(e) {
+            if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
+              e.stopImmediatePropagation();
+            }
+          })
+          .focus()
+          .select();
+      };
 
-    this.loadValue = function(item) {
-      defaultValue = item[args.column.field];
+      this.destroy = function() {
+        $input.remove();
+      };
 
-      if (args.column.is_array && !_.isNull(defaultValue) && !_.isUndefined(defaultValue)) {
-        $input.val('{' + defaultValue.join() + '}');
-      } else {
-        $input.val(defaultValue);
-      }
+      this.focus = function() {
+        $input.focus();
+      };
 
-      $input[0].defaultValue = defaultValue;
-      $input.select();
-    };
+      this.getValue = function() {
+        return $input.val();
+      };
 
-    this.serializeValue = function() {
-      var value = $input.val();
+      this.loadValue = function(item) {
+        var value = item[args.column.field];
 
-      if (value === '') {
-        return null;
-      }
+        // Check if value is null or undefined
+        if (value === undefined && typeof value === 'undefined') {
+          value = '';
+        }
+        defaultValue = value;
+        $input.val(defaultValue);
+        $input[0].defaultValue = defaultValue;
+        $input.select();
+      };
+
+      this.serializeValue = function() {
+        return $input.val();
+      };
 
-      if (args.column.is_array) {
-        // Remove leading { and trailing }.
-        // Also remove leading and trailing whitespaces.
-        var val = $.trim(value.slice(1, -1));
+      this.applyValue = function(item, state) {
+        item[args.column.field] = state;
+      };
 
-        if (val == '') {
-          return [];
+      this.isValueChanged = function() {
+        return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
+      };
+
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator($input.val());
+          if (!validationResults.valid) {
+            return validationResults;
+          }
         }
-        val = val.split(',');
-        for (var k in val) {
-          if (val[k] == '') {
-            val[k] = null; //empty string from editor is null value.
+
+        return {
+          valid: true,
+          msg: null,
+        };
+      };
+
+      this.init();
+    }
+
+    function ReadOnlyCheckboxEditor(args) {
+      var $select;
+      var defaultValue;
+
+      this.init = function() {
+        $select = $('<INPUT type=checkbox value=\'true\' class=\'editor-checkbox\' hideFocus disabled>');
+        $select.appendTo(args.container);
+        $select.focus();
+      };
+
+      this.destroy = function() {
+        $select.remove();
+      };
+
+      this.focus = function() {
+        $select.focus();
+      };
+
+      this.loadValue = function(item) {
+        defaultValue = item[args.column.pos];
+        if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
+          $select.prop('indeterminate', true);
+          $select.data('checked', 2);
+        } else {
+          defaultValue = !!item[args.column.pos];
+          if (defaultValue) {
+            $select.prop('checked', true);
+            $select.data('checked', 0);
+          } else {
+            $select.prop('checked', false);
+            $select.data('checked', 1);
           }
         }
-        return val;
-      }
+      };
 
-      return value;
-    };
+      this.serializeValue = function() {
+        if ($select.prop('indeterminate')) {
+          return null;
+        }
+        return $select.prop('checked');
+      };
 
-    this.applyValue = function(item, state) {
-      setValue(args, item, state, 'number');
-    };
+      this.applyValue = function(item, state) {
+        item[args.column.pos] = state;
+      };
 
-    this.isValueChanged = function() {
-      if ($input.val() == '' && _.isUndefined(defaultValue)) {
-        return false;
-      } else if ($input.val() == '' && defaultValue == '') {
-        return true;
-      } else {
-        return (!($input.val() == '' && _.isNull(defaultValue))) &&
-          ($input.val() != defaultValue);
-      }
-    };
+      this.isValueChanged = function() {
+        // var select_value = this.serializeValue();
+        var select_value = $select.data('checked');
+        return (!(select_value === 2 && (defaultValue == null || defaultValue == undefined))) &&
+          (select_value !== defaultValue);
+      };
 
-    this.validate = function() {
-      var value = $input.val();
-      if (!args.column.is_array && isNaN(value)) {
+      this.validate = function() {
         return {
-          valid: false,
-          msg: 'Please enter a valid number',
+          valid: true,
+          msg: null,
         };
-      }
-      if (args.column.validator) {
-        var validationResults = args.column.validator(value);
-        if (!validationResults.valid) {
-          return validationResults;
+      };
+
+      this.init();
+    }
+
+    function CustomNumberEditor(args) {
+      var $input;
+      var defaultValue;
+
+      this.init = function() {
+        $input = $('<INPUT type=text class=\'editor-text\' />');
+
+        $input.bind('keydown.nav', function(e) {
+          if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
+            e.stopImmediatePropagation();
+          }
+        });
+
+        $input.appendTo(args.container);
+        $input.focus().select();
+      };
+
+      this.destroy = function() {
+        $input.remove();
+      };
+
+      this.focus = function() {
+        $input.focus();
+      };
+
+      this.loadValue = function(item) {
+        defaultValue = item[args.column.field];
+
+        if (args.column.is_array && !_.isNull(defaultValue) && !_.isUndefined(defaultValue)) {
+          $input.val('{' + defaultValue.join() + '}');
+        } else {
+          $input.val(defaultValue);
         }
-      }
 
-      if (args.column.is_array) {
-        if (!is_valid_array(value)) {
-          return {
-            valid: false,
-            msg: 'Array must start with \'{\' and end with \'}\'',
-          };
+        $input[0].defaultValue = defaultValue;
+        $input.select();
+      };
+
+      this.serializeValue = function() {
+        var value = $input.val();
+
+        if (value === '') {
+          return null;
         }
 
-        var val = $.trim(value.slice(1, -1)),
-          arr;
+        if (args.column.is_array) {
+          // Remove leading { and trailing }.
+          // Also remove leading and trailing whitespaces.
+          var val = $.trim(value.slice(1, -1));
+
+          if (val == '') {
+            return [];
+          }
+          val = val.split(',');
+          for (var k in val) {
+            if (val[k] == '') {
+              val[k] = null; //empty string from editor is null value.
+            }
+          }
+          return val;
+        }
 
-        if (val == '') {
-          arr = [];
+        return value;
+      };
+
+      this.applyValue = function(item, state) {
+        setValue(args, item, state, 'number');
+      };
+
+      this.isValueChanged = function() {
+        if ($input.val() == '' && _.isUndefined(defaultValue)) {
+          return false;
+        } else if ($input.val() == '' && defaultValue == '') {
+          return true;
         } else {
-          arr = val.split(',');
+          return (!($input.val() == '' && _.isNull(defaultValue))) &&
+            ($input.val() != defaultValue);
+        }
+      };
+
+      this.validate = function() {
+        var value = $input.val();
+        if (!args.column.is_array && isNaN(value)) {
+          return {
+            valid: false,
+            msg: 'Please enter a valid number',
+          };
+        }
+        if (args.column.validator) {
+          var validationResults = args.column.validator(value);
+          if (!validationResults.valid) {
+            return validationResults;
+          }
         }
 
-        for (var k in arr) {
-          if (isNaN(arr[k])) {
+        if (args.column.is_array) {
+          if (!is_valid_array(value)) {
             return {
               valid: false,
-              msg: 'Please enter a valid numbers',
+              msg: 'Array must start with \'{\' and end with \'}\'',
             };
           }
+
+          var val = $.trim(value.slice(1, -1)),
+            arr;
+
+          if (val == '') {
+            arr = [];
+          } else {
+            arr = val.split(',');
+          }
+
+          for (var k in arr) {
+            if (isNaN(arr[k])) {
+              return {
+                valid: false,
+                msg: 'Please enter a valid numbers',
+              };
+            }
+          }
         }
-      }
 
-      return {
-        valid: true,
-        msg: null,
-      };
-    };
-
-    this.init();
-  }
-
-  // Custom checkbox editor, We need it for runtime as it does not render
-  // indeterminate checkbox state
-  function pgCheckboxEditor(args) {
-    var $select, el;
-    var defaultValue, previousState;
-
-    this.init = function() {
-      $select = $('<div class=\'multi-checkbox\'><span class=\'check\' hideFocus></span></div>');
-      $select.appendTo(args.container);
-      $select.focus();
-
-      // The following code is taken from https://css-tricks.com/indeterminate-checkboxes/
-      $select.bind('click', function() {
-        el = $(this);
-        var states = ['unchecked', 'partial', 'checked'];
-        var curState = el.find('.check').data('state');
-        curState++;
-        el.find('.check')
-          .removeClass('unchecked partial checked')
-          .addClass(states[curState % states.length])
-          .data('state', curState % states.length);
-      });
-    };
-
-    this.destroy = function() {
-      $select.remove();
-    };
-
-    this.focus = function() {
-      $select.focus();
-    };
-
-    this.loadValue = function(item) {
-      defaultValue = item[args.column.field];
-      previousState = 1;
-      if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
-        $select.find('.check').data('state', 1).addClass('partial');
-      } else {
-        defaultValue = !!item[args.column.field];
-        if (defaultValue) {
-          $select.find('.check').data('state', 2).addClass('checked');
-          previousState = 2;
+        return {
+          valid: true,
+          msg: null,
+        };
+      };
+
+      this.init();
+    }
+
+    // Custom checkbox editor, We need it for runtime as it does not render
+    // indeterminate checkbox state
+    function pgCheckboxEditor(args) {
+      var $select, el;
+      var defaultValue, previousState;
+
+      this.init = function() {
+        $select = $('<div class=\'multi-checkbox\'><span class=\'check\' hideFocus></span></div>');
+        $select.appendTo(args.container);
+        $select.focus();
+
+        // The following code is taken from https://css-tricks.com/indeterminate-checkboxes/
+        $select.bind('click', function() {
+          el = $(this);
+          var states = ['unchecked', 'partial', 'checked'];
+          var curState = el.find('.check').data('state');
+          curState++;
+          el.find('.check')
+            .removeClass('unchecked partial checked')
+            .addClass(states[curState % states.length])
+            .data('state', curState % states.length);
+        });
+      };
+
+      this.destroy = function() {
+        $select.remove();
+      };
+
+      this.focus = function() {
+        $select.focus();
+      };
+
+      this.loadValue = function(item) {
+        defaultValue = item[args.column.field];
+        previousState = 1;
+        if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
+          $select.find('.check').data('state', 1).addClass('partial');
         } else {
-          $select.find('.check').data('state', 0).addClass('unchecked');
-          previousState = 0;
+          defaultValue = !!item[args.column.field];
+          if (defaultValue) {
+            $select.find('.check').data('state', 2).addClass('checked');
+            previousState = 2;
+          } else {
+            $select.find('.check').data('state', 0).addClass('unchecked');
+            previousState = 0;
+          }
         }
-      }
-    };
+      };
 
-    this.serializeValue = function() {
-      if ($select.find('.check').data('state') == 1) {
-        return null;
-      }
-      return $select.find('.check').data('state') == 2 ? true : false;
-    };
+      this.serializeValue = function() {
+        if ($select.find('.check').data('state') == 1) {
+          return null;
+        }
+        return $select.find('.check').data('state') == 2 ? true : false;
+      };
 
-    this.applyValue = function(item, state) {
-      item[args.column.field] = state;
-    };
+      this.applyValue = function(item, state) {
+        item[args.column.field] = state;
+      };
 
-    this.isValueChanged = function() {
-      var currentState = $select.find('.check').data('state');
-      return currentState !== previousState;
-    };
+      this.isValueChanged = function() {
+        var currentState = $select.find('.check').data('state');
+        return currentState !== previousState;
+      };
 
-    this.validate = function() {
-      if (args.column.validator) {
-        var validationResults = args.column.validator(this.serializeValue());
-        if (!validationResults.valid) {
-          return validationResults;
+      this.validate = function() {
+        if (args.column.validator) {
+          var validationResults = args.column.validator(this.serializeValue());
+          if (!validationResults.valid) {
+            return validationResults;
+          }
         }
-      }
-      return {
-        valid: true,
-        msg: null,
+        return {
+          valid: true,
+          msg: null,
+        };
       };
-    };
 
-    this.init();
-  }
+      this.init();
+    }
 
-})(window.jQuery);
+  })(window.jQuery);
+});
diff --git a/web/pgadmin/static/js/slickgrid/resize_editor.js b/web/pgadmin/static/js/slickgrid/resize_editor.js
new file mode 100644
index 0000000..3a3ec34
--- /dev/null
+++ b/web/pgadmin/static/js/slickgrid/resize_editor.js
@@ -0,0 +1,45 @@
+export function resizeContentOnDrag($wrapper, $input){
+  // right border, bottom border and right bottom corner of the wrapper are draggable
+  $wrapper.append('<div class="drag-border" data="right"></div>\
+    <div class="drag-border" data="bottom"></div>\
+    <div class="drag-border" data="both"></div>');
+
+  $wrapper.find('.drag-border').on('drag', (event)=>{
+    event.preventDefault();
+    var mouseX = event.clientX;
+    var mouseY = event.clientY;
+
+    // mouseX == 0 && mouseY == 0 mouse up / end of drag
+    if(mouseX == 0 && mouseY == 0)return;
+
+    // default spacing between $input and cursor
+    var paddingBottom = 30;
+    var paddingRight = 10;
+    var dir = event.target.getAttribute('data');
+
+    // size of $input is changed according to cursor position
+    switch(dir){
+    case 'right':
+      changeWidth($input, mouseX, paddingRight);
+      break;
+    case 'bottom':
+      changeHeight($input, mouseY, paddingBottom);
+      break;
+    case 'both':
+      changeHeight($input, mouseY, paddingBottom);
+      changeWidth($input, mouseX, paddingRight);
+    }
+  });
+}
+
+function changeWidth($input, mouseX, padding){
+  var rect = $input[0].getBoundingClientRect();
+  var newWidth = rect.width + mouseX - rect.right - padding;
+  $input.css('width', newWidth.toString() + 'px');
+}
+
+function changeHeight($input, mouseY, padding){
+  var rect = $input[0].getBoundingClientRect();
+  var newHeight = rect.height + mouseY - rect.bottom - padding;
+  $input.css('height', newHeight.toString() + 'px');
+}
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 46588dc..034e405 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -505,6 +505,38 @@ input.editor-checkbox:focus {
   -moz-border-radius:10px;
   border-radius:10px;
 }
+
+.drag-border{
+  background: transparent;
+  position: absolute;
+}
+
+.drag-border[data=right]{
+  cursor: ew-resize;
+  top: 0;
+  right: -10px;
+  bottom: 0;
+  width: 20px;
+}
+
+.drag-border[data=bottom]{
+  cursor: ns-resize;
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: -10px;
+  height: 20px;
+}
+
+.drag-border[data=both]{
+  cursor: move;
+  position: absolute;
+  bottom: -10px;
+  right: -10px;
+  width: 20px;
+  height: 20px;
+}
+
 .pg_textarea {
   backround:#fff;
   width:250px;


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
@ 2018-03-28 18:06     ` Joao De Almeida Pereira <[email protected]>
  2018-03-29 10:32       ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  0 siblings, 2 replies; 13+ messages in thread

From: Joao De Almeida Pereira @ 2018-03-28 18:06 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hey Akshay and Neethu

We refactored the patch to add tests for the resize feature.  We were able
to write test cases for the drag event by using spies and setting the rect
dimensions.  In cases like this, we can just test some components in order
to have enough confidence in the code.  So we isolated the function that
implements the behavior of this feature and tested that it was performing
as expected.

We ran the patch through the pipelines and all of the tests passed.

Sincerely,

Joao and Victoria

On Wed, Mar 28, 2018 at 8:03 AM Akshay Joshi <[email protected]>
wrote:

> Hi
>
> On Fri, Mar 2, 2018 at 3:40 AM, Joao De Almeida Pereira <
> [email protected]> wrote:
>
>> Hello Neethu,
>> We passed the patch through our CI pipeline and all tests pass.
>> The code looks good, but we are trying to decouple files as much  as we
>> can so that we do not end up with files with over 1000 lines, that are hard
>> to read and to maintain. Also we are trying to create Unit Tests to have
>> more coverage in our Javascript code.
>>
>> Can you split the new implementation code into it's own file and create
>> some tests to ensure the behavior will not be broken in the future?iYou
>> have some examples
>> on: pgadmin/browser/server_groups/servers/databases/external_tables/*
>>
>
>     I have spilt the new implementation into different file. Its' been
> hard to write jasmine/feature test case as it requires drag event and exact
> co-ordinate to resize the slickgrid cell.
>     Attached is the modified patch.
>
>
>>
>> Thanks
>> Joao
>>
>> On Thu, Mar 1, 2018 at 10:37 AM Neethu Mariya Joy <
>> [email protected]> wrote:
>>
>>> Hi,
>>> I am Neethu Mariya Joy, an undergraduate pursuing BE in Computer Science
>>> at BITS Pilani.
>>>
>>> I've attempted to fix https://redmine.postgresql.org/issues/3083. Since
>>> the textarea resize feature is the default HTML feature, I have not changed
>>> it. Instead, I've added draggable borders to the wrapper which expands the
>>> textarea inside it.
>>>
>>> I'm attaching my patch as bug3083.diff below as per the contribution
>>> guidelines.
>>>
>>> Hope this helps. Thank you for your consideration!
>>>
>>> Sincerely,
>>> Neethu Mariya Joy
>>> GitHub <https://github.com/Roboneet; | Linkedin
>>> <https://www.linkedin.com/in/neethu-mariya-joy-653655128/;
>>>
>>>
>>>
>
>
> --
> *Akshay Joshi*
>
> *Sr. Software Architect *
>
>
>
> *Phone: +91 20-3058-9517 <+91%2020%203058%209517>Mobile: +91 976-788-8246
> <+91%2097678%2088246>*
>


Attachments:

  [text/x-patch] RM_3083_v3.patch (24.7K, 3-RM_3083_v3.patch)
  download | inline diff:
diff --git a/web/pgadmin/static/js/slickgrid/editors.js b/web/pgadmin/static/js/slickgrid/editors.js
index 7652bf3b..a7df4baf 100644
--- a/web/pgadmin/static/js/slickgrid/editors.js
+++ b/web/pgadmin/static/js/slickgrid/editors.js
@@ -3,8 +3,9 @@
  * @module Editors
  * @namespace Slick
  */
+import {resizeContentOnDrag} from 'resize_editor';
 
-(function($) {
+(function ($) {
   // register namespace
   $.extend(true, window, {
     'Slick': {
@@ -52,6 +53,7 @@
     val = $.trim(val);
     return !(val != '' && (val.charAt(0) != '{' || val.charAt(val.length - 1) != '}'));
   }
+
   /*
    * This function handles the [default] and [null] values for cells
    * if row is copied, otherwise returns the editor value.
@@ -129,7 +131,7 @@
     var defaultValue;
     var scope = this;
 
-    this.init = function() {
+    this.init = function () {
       var $container = $('body');
 
       $wrapper = getWrapper().appendTo($container);
@@ -140,11 +142,12 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
 
-    this.handleKeyDown = function(e) {
+    this.handleKeyDown = function (e) {
       if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
         scope.save();
       } else if (e.which == $.ui.keyCode.ESCAPE) {
@@ -159,40 +162,40 @@
       }
     };
 
-    this.save = function() {
+    this.save = function () {
       args.commitChanges();
     };
 
-    this.cancel = function() {
+    this.cancel = function () {
       $input.val(defaultValue);
       args.cancelChanges();
     };
 
-    this.hide = function() {
+    this.hide = function () {
       $wrapper.hide();
     };
 
-    this.show = function() {
+    this.show = function () {
       $wrapper.show();
     };
 
-    this.position = function(position) {
+    this.position = function (position) {
       calculateEditorPosition(position, $wrapper);
       $wrapper
         .css('top', position.top)
         .css('left', position.left);
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $wrapper.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
     // When text editor opens
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       if (
         _.isUndefined(item[args.column.field]) ||
         _.isNull(item[args.column.field])
@@ -218,7 +221,7 @@
       }
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
 
       var value = $input.val();
       // If empty return null
@@ -241,11 +244,11 @@
       }
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       setValue(args, item, state, 'text');
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       // Use _.isNull(value) for comparison for null instead of
       // defaultValue == null, because it returns true for undefined value.
       if ($input.val() == '' && _.isUndefined(defaultValue)) {
@@ -256,7 +259,7 @@
       }
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator($input.val());
         if (!validationResults.valid) {
@@ -286,7 +289,7 @@
     var defaultValue;
     var scope = this;
 
-    this.init = function() {
+    this.init = function () {
       var $container = $('body');
 
       $wrapper = getWrapper().appendTo($container);
@@ -297,11 +300,12 @@
       $buttons.find('button:last').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
 
-    this.handleKeyDown = function(e) {
+    this.handleKeyDown = function (e) {
       if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
         scope.save();
       } else if (e.which == $.ui.keyCode.ESCAPE) {
@@ -316,45 +320,45 @@
       }
     };
 
-    this.save = function() {
+    this.save = function () {
       args.commitChanges();
     };
 
-    this.cancel = function() {
+    this.cancel = function () {
       $input.val(defaultValue);
       args.cancelChanges();
     };
 
-    this.hide = function() {
+    this.hide = function () {
       $wrapper.hide();
     };
 
-    this.show = function() {
+    this.show = function () {
       $wrapper.show();
     };
 
-    this.position = function(position) {
+    this.position = function (position) {
       calculateEditorPosition(position, $wrapper);
       $wrapper
         .css('top', position.top)
         .css('left', position.left);
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $wrapper.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       var data = defaultValue = item[args.column.field];
       if (data && typeof data === 'object' && !Array.isArray(data)) {
         data = JSON.stringify(data, null, 4);
       } else if (Array.isArray(data)) {
         var temp = [];
-        $.each(data, function(i, val) {
+        $.each(data, function (i, val) {
           if (typeof val === 'object') {
             temp.push(JSON.stringify(val, null, 4));
           } else {
@@ -367,18 +371,18 @@
       $input.select();
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       if ($input.val() === '') {
         return null;
       }
       return $input.val();
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       setValue(args, item, state, 'text');
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       if ($input.val() == '' && _.isUndefined(defaultValue)) {
         return false;
       } else {
@@ -386,7 +390,7 @@
       }
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator($input.val());
         if (!validationResults.valid) {
@@ -409,7 +413,7 @@
     var defaultValue;
     var scope = this;
 
-    this.init = function() {
+    this.init = function () {
       var $container = $('body');
 
       $wrapper = getWrapper().appendTo($container);
@@ -419,11 +423,12 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
 
-    this.handleKeyDown = function(e) {
+    this.handleKeyDown = function (e) {
       if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
         scope.cancel();
       } else if (e.which == $.ui.keyCode.ESCAPE) {
@@ -440,52 +445,52 @@
       }
     };
 
-    this.cancel = function() {
+    this.cancel = function () {
       $input.val(defaultValue);
       args.cancelChanges();
     };
 
-    this.hide = function() {
+    this.hide = function () {
       $wrapper.hide();
     };
 
-    this.show = function() {
+    this.show = function () {
       $wrapper.show();
     };
 
-    this.position = function(position) {
+    this.position = function (position) {
       calculateEditorPosition(position, $wrapper);
       $wrapper
         .css('top', position.top)
         .css('left', position.left);
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $wrapper.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       $input.val(defaultValue = item[args.column.field]);
       $input.select();
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       return $input.val();
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       item[args.column.field] = state;
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator($input.val());
         if (!validationResults.valid) {
@@ -508,7 +513,7 @@
     var defaultValue;
     var scope = this;
 
-    this.init = function() {
+    this.init = function () {
       var $container = $('body');
 
       $wrapper = getWrapper().appendTo($container);
@@ -518,11 +523,12 @@
       $buttons.find('button:first').on('click', this.cancel);
       $input.bind('keydown', this.handleKeyDown);
 
+      resizeContentOnDrag($wrapper, $input);
       scope.position(args.position);
       $input.focus().select();
     };
 
-    this.handleKeyDown = function(e) {
+    this.handleKeyDown = function (e) {
       if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
         scope.cancel();
       } else if (e.which == $.ui.keyCode.ESCAPE) {
@@ -539,41 +545,41 @@
       }
     };
 
-    this.cancel = function() {
+    this.cancel = function () {
       $input.val(defaultValue);
       args.cancelChanges();
     };
 
-    this.hide = function() {
+    this.hide = function () {
       $wrapper.hide();
     };
 
-    this.show = function() {
+    this.show = function () {
       $wrapper.show();
     };
 
-    this.position = function(position) {
+    this.position = function (position) {
       calculateEditorPosition(position, $wrapper);
       $wrapper
         .css('top', position.top)
         .css('left', position.left);
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $wrapper.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       var data = defaultValue = item[args.column.field];
       if (typeof data === 'object' && !Array.isArray(data)) {
         data = JSON.stringify(data, null, 4);
       } else if (Array.isArray(data)) {
         var temp = [];
-        $.each(data, function(i, val) {
+        $.each(data, function (i, val) {
           if (typeof val === 'object') {
             temp.push(JSON.stringify(val, null, 4));
           } else {
@@ -586,19 +592,19 @@
       $input.select();
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       return $input.val();
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       item[args.column.field] = state;
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator($input.val());
         if (!validationResults.valid) {
@@ -619,10 +625,10 @@
     var $input;
     var defaultValue;
 
-    this.init = function() {
+    this.init = function () {
       $input = $('<INPUT type=text class=\'editor-text\' readonly/>')
         .appendTo(args.container)
-        .bind('keydown.nav', function(e) {
+        .bind('keydown.nav', function (e) {
           if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
             e.stopImmediatePropagation();
           }
@@ -631,19 +637,19 @@
         .select();
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $input.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
-    this.getValue = function() {
+    this.getValue = function () {
       return $input.val();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       var value = item[args.column.field];
 
       // Check if value is null or undefined
@@ -656,19 +662,19 @@
       $input.select();
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       return $input.val();
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       item[args.column.field] = state;
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       return (!($input.val() == '' && defaultValue == null)) && ($input.val() != defaultValue);
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator($input.val());
         if (!validationResults.valid) {
@@ -689,21 +695,21 @@
     var $select;
     var defaultValue;
 
-    this.init = function() {
+    this.init = function () {
       $select = $('<INPUT type=checkbox value=\'true\' class=\'editor-checkbox\' hideFocus disabled>');
       $select.appendTo(args.container);
       $select.focus();
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $select.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $select.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       defaultValue = item[args.column.pos];
       if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
         $select.prop('indeterminate', true);
@@ -720,25 +726,25 @@
       }
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       if ($select.prop('indeterminate')) {
         return null;
       }
       return $select.prop('checked');
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       item[args.column.pos] = state;
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       // var select_value = this.serializeValue();
       var select_value = $select.data('checked');
       return (!(select_value === 2 && (defaultValue == null || defaultValue == undefined))) &&
         (select_value !== defaultValue);
     };
 
-    this.validate = function() {
+    this.validate = function () {
       return {
         valid: true,
         msg: null,
@@ -752,10 +758,10 @@
     var $input;
     var defaultValue;
 
-    this.init = function() {
+    this.init = function () {
       $input = $('<INPUT type=text class=\'editor-text\' />');
 
-      $input.bind('keydown.nav', function(e) {
+      $input.bind('keydown.nav', function (e) {
         if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
           e.stopImmediatePropagation();
         }
@@ -765,15 +771,15 @@
       $input.focus().select();
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $input.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $input.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       defaultValue = item[args.column.field];
 
       if (args.column.is_array && !_.isNull(defaultValue) && !_.isUndefined(defaultValue)) {
@@ -786,7 +792,7 @@
       $input.select();
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       var value = $input.val();
 
       if (value === '') {
@@ -813,11 +819,11 @@
       return value;
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       setValue(args, item, state, 'number');
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       if ($input.val() == '' && _.isUndefined(defaultValue)) {
         return false;
       } else if ($input.val() == '' && defaultValue == '') {
@@ -828,7 +834,7 @@
       }
     };
 
-    this.validate = function() {
+    this.validate = function () {
       var value = $input.val();
       if (!args.column.is_array && isNaN(value)) {
         return {
@@ -885,13 +891,13 @@
     var $select, el;
     var defaultValue, previousState;
 
-    this.init = function() {
+    this.init = function () {
       $select = $('<div class=\'multi-checkbox\'><span class=\'check\' hideFocus></span></div>');
       $select.appendTo(args.container);
       $select.focus();
 
       // The following code is taken from https://css-tricks.com/indeterminate-checkboxes/
-      $select.bind('click', function() {
+      $select.bind('click', function () {
         el = $(this);
         var states = ['unchecked', 'partial', 'checked'];
         var curState = el.find('.check').data('state');
@@ -903,15 +909,15 @@
       });
     };
 
-    this.destroy = function() {
+    this.destroy = function () {
       $select.remove();
     };
 
-    this.focus = function() {
+    this.focus = function () {
       $select.focus();
     };
 
-    this.loadValue = function(item) {
+    this.loadValue = function (item) {
       defaultValue = item[args.column.field];
       previousState = 1;
       if (_.isNull(defaultValue) || _.isUndefined(defaultValue)) {
@@ -928,23 +934,23 @@
       }
     };
 
-    this.serializeValue = function() {
+    this.serializeValue = function () {
       if ($select.find('.check').data('state') == 1) {
         return null;
       }
       return $select.find('.check').data('state') == 2 ? true : false;
     };
 
-    this.applyValue = function(item, state) {
+    this.applyValue = function (item, state) {
       item[args.column.field] = state;
     };
 
-    this.isValueChanged = function() {
+    this.isValueChanged = function () {
       var currentState = $select.find('.check').data('state');
       return currentState !== previousState;
     };
 
-    this.validate = function() {
+    this.validate = function () {
       if (args.column.validator) {
         var validationResults = args.column.validator(this.serializeValue());
         if (!validationResults.valid) {
diff --git a/web/pgadmin/static/js/slickgrid/resize_editor.js b/web/pgadmin/static/js/slickgrid/resize_editor.js
new file mode 100644
index 00000000..7e781cda
--- /dev/null
+++ b/web/pgadmin/static/js/slickgrid/resize_editor.js
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+export function resizeContentOnDrag($wrapper, $input) {
+  // right border, bottom border and right bottom corner of the wrapper are draggable
+  $wrapper.append('<div class="drag-border" data="right"></div>\
+    <div class="drag-border" data="bottom"></div>\
+    <div class="drag-border" data="both"></div>');
+
+  $wrapper.find('.drag-border').on('drag', (event) => {
+    onDragEvent(event, $input);
+  });
+}
+
+function dragEnded(mouseX, mouseY) {
+  return mouseX === 0 && mouseY === 0;
+}
+
+export function onDragEvent(event, $input) {
+  event.preventDefault();
+  const mouseX = event.clientX;
+  const mouseY = event.clientY;
+
+  if (dragEnded(mouseX, mouseY)) {
+    return;
+  }
+
+  // default spacing between $input and cursor
+  const paddingBottom = 30;
+  const paddingRight = 10;
+  const dir = event.target.getAttribute('data');
+
+  // size of $input is changed according to cursor position
+  switch (dir) {
+  case 'right':
+    changeWidth($input, mouseX, paddingRight);
+    break;
+  case 'bottom':
+    changeHeight($input, mouseY, paddingBottom);
+    break;
+  case 'both':
+    changeHeight($input, mouseY, paddingBottom);
+    changeWidth($input, mouseX, paddingRight);
+  }
+}
+
+function changeWidth($input, mouseX, padding) {
+  const rect = $input[0].getBoundingClientRect();
+  const newWidth = rect.width + mouseX - rect.right - padding;
+  $input.css('width', newWidth.toString() + 'px');
+}
+
+function changeHeight($input, mouseY, padding) {
+  const rect = $input[0].getBoundingClientRect();
+  const newHeight = rect.height + mouseY - rect.bottom - padding;
+  $input.css('height', newHeight.toString() + 'px');
+}
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 46588dce..034e4050 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -505,6 +505,38 @@ input.editor-checkbox:focus {
   -moz-border-radius:10px;
   border-radius:10px;
 }
+
+.drag-border{
+  background: transparent;
+  position: absolute;
+}
+
+.drag-border[data=right]{
+  cursor: ew-resize;
+  top: 0;
+  right: -10px;
+  bottom: 0;
+  width: 20px;
+}
+
+.drag-border[data=bottom]{
+  cursor: ns-resize;
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: -10px;
+  height: 20px;
+}
+
+.drag-border[data=both]{
+  cursor: move;
+  position: absolute;
+  bottom: -10px;
+  right: -10px;
+  width: 20px;
+  height: 20px;
+}
+
 .pg_textarea {
   backround:#fff;
   width:250px;
diff --git a/web/regression/javascript/selection/resize_editor_spec.js b/web/regression/javascript/selection/resize_editor_spec.js
new file mode 100644
index 00000000..30080d97
--- /dev/null
+++ b/web/regression/javascript/selection/resize_editor_spec.js
@@ -0,0 +1,113 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import {onDragEvent} from "../../../pgadmin/static/js/slickgrid/resize_editor";
+
+const context = describe;
+
+describe('onDragEvent', () => {
+  context('when the drag event ends', () => {
+    let event;
+    let input;
+    beforeEach(() => {
+      event = {clientX: 0, clientY: 0};
+      event.preventDefault = jasmine.createSpy('preventDefault');
+      input = {
+        css: jasmine.createSpy('css'),
+      };
+
+      onDragEvent(event, input);
+    });
+
+    it('prevents default action from being triggered on event', () => {
+      expect(event.preventDefault).toHaveBeenCalled();
+    });
+
+    it('does not change dimensions of element', () => {
+      expect(input.css).not.toHaveBeenCalled();
+    });
+  });
+
+  context('when the drag event is in progress', () => {
+    let event;
+    let input;
+    beforeEach(() => {
+      event = {
+        clientX: 50,
+        clientY: 101,
+        target: jasmine.createSpyObj('target', ['getAttribute']),
+      };
+      event.preventDefault = jasmine.createSpy('preventDefault');
+      input = [{
+        getBoundingClientRect: jasmine.createSpy('getBoundingClientRect')
+      }];
+      input.css = jasmine.createSpy('css');
+    });
+
+    context('drag to the right', () => {
+      beforeEach(() => {
+        event.target.getAttribute.and.returnValue('right');
+        input[0].getBoundingClientRect.and.returnValue({
+          width: 11,
+          right: 9,
+        });
+        onDragEvent(event, input);
+      });
+
+      it('prevents default action from being triggered on event', () => {
+        expect(event.preventDefault).toHaveBeenCalled();
+      });
+
+      it('increases the width of the element', () => {
+        expect(input.css).toHaveBeenCalledWith('width', '42px');
+      });
+    });
+
+    context('drag to the bottom', () => {
+      beforeEach(() => {
+        event.target.getAttribute.and.returnValue('bottom');
+        input[0].getBoundingClientRect.and.returnValue({
+          height: 20,
+          bottom: 30,
+        });
+        onDragEvent(event, input);
+      });
+
+      it('prevents default action from being triggered on event', () => {
+        expect(event.preventDefault).toHaveBeenCalled();
+      });
+
+      it('increases the height of the element', () => {
+        expect(input.css).toHaveBeenCalledWith('height', '61px');
+      });
+    });
+
+    context('drag to the bottom and right at the same time', () => {
+      beforeEach(() => {
+        event.target.getAttribute.and.returnValue('both');
+        input[0].getBoundingClientRect.and.returnValue({
+          width: 10,
+          height: 19,
+          right: 10,
+          bottom: 30,
+        });
+        onDragEvent(event, input);
+      });
+
+      it('prevents default action from being triggered on event', () => {
+        expect(event.preventDefault).toHaveBeenCalled();
+      });
+
+      it('increases the height of the element', () => {
+        expect(input.css).toHaveBeenCalledWith('width', '40px');
+        expect(input.css).toHaveBeenCalledWith('height', '60px');
+      });
+    });
+  });
+});


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
@ 2018-03-29 10:32       ` Akshay Joshi <[email protected]>
  1 sibling, 0 replies; 13+ messages in thread

From: Akshay Joshi @ 2018-03-29 10:32 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Thanks Joao.

On Wed, Mar 28, 2018 at 11:36 PM, Joao De Almeida Pereira <
[email protected]> wrote:

> Hey Akshay and Neethu
>
> We refactored the patch to add tests for the resize feature.  We were able
> to write test cases for the drag event by using spies and setting the rect
> dimensions.  In cases like this, we can just test some components in order
> to have enough confidence in the code.  So we isolated the function that
> implements the behavior of this feature and tested that it was performing
> as expected.
>
> We ran the patch through the pipelines and all of the tests passed.
>
> Sincerely,
>
> Joao and Victoria
>
> On Wed, Mar 28, 2018 at 8:03 AM Akshay Joshi <
> [email protected]> wrote:
>
>> Hi
>>
>> On Fri, Mar 2, 2018 at 3:40 AM, Joao De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hello Neethu,
>>> We passed the patch through our CI pipeline and all tests pass.
>>> The code looks good, but we are trying to decouple files as much  as we
>>> can so that we do not end up with files with over 1000 lines, that are hard
>>> to read and to maintain. Also we are trying to create Unit Tests to have
>>> more coverage in our Javascript code.
>>>
>>> Can you split the new implementation code into it's own file and create
>>> some tests to ensure the behavior will not be broken in the future?iYou
>>> have some examples on: pgadmin/browser/server_groups/servers/databases/
>>> external_tables/*
>>>
>>
>>     I have spilt the new implementation into different file. Its' been
>> hard to write jasmine/feature test case as it requires drag event and exact
>> co-ordinate to resize the slickgrid cell.
>>     Attached is the modified patch.
>>
>>
>>>
>>> Thanks
>>> Joao
>>>
>>> On Thu, Mar 1, 2018 at 10:37 AM Neethu Mariya Joy <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>> I am Neethu Mariya Joy, an undergraduate pursuing BE in Computer
>>>> Science at BITS Pilani.
>>>>
>>>> I've attempted to fix https://redmine.postgresql.org/issues/3083.
>>>> Since the textarea resize feature is the default HTML feature, I have not
>>>> changed it. Instead, I've added draggable borders to the wrapper which
>>>> expands the textarea inside it.
>>>>
>>>> I'm attaching my patch as bug3083.diff below as per the contribution
>>>> guidelines.
>>>>
>>>> Hope this helps. Thank you for your consideration!
>>>>
>>>> Sincerely,
>>>> Neethu Mariya Joy
>>>> GitHub <https://github.com/Roboneet; | Linkedin
>>>> <https://www.linkedin.com/in/neethu-mariya-joy-653655128/;
>>>>
>>>>
>>>>
>>
>>
>> --
>> *Akshay Joshi*
>>
>> *Sr. Software Architect *
>>
>>
>>
>> *Phone: +91 20-3058-9517 <+91%2020%203058%209517>Mobile: +91 976-788-8246
>> <+91%2097678%2088246>*
>>
>


-- 
*Akshay Joshi*

*Sr. Software Architect *



*Phone: +91 20-3058-9517Mobile: +91 976-788-8246*


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
@ 2018-03-29 13:03       ` Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  1 sibling, 1 reply; 13+ messages in thread

From: Dave Page @ 2018-03-29 13:03 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi

On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
[email protected]> wrote:

> Hey Akshay and Neethu
>
> We refactored the patch to add tests for the resize feature.  We were able
> to write test cases for the drag event by using spies and setting the rect
> dimensions.  In cases like this, we can just test some components in order
> to have enough confidence in the code.  So we isolated the function that
> implements the behavior of this feature and tested that it was performing
> as expected.
>
> We ran the patch through the pipelines and all of the tests passed.
>

I'm consistently seeing the feature test failure below with this patch
applied:

======================================================================
FAIL: runTest
(pgadmin.feature_tests.view_data_dml_queries.CheckForViewDataTest)
Validate Insert, Update operations in View/Edit data with given test data
----------------------------------------------------------------------
Traceback (most recent call last):
  File
"/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
line 125, in runTest
    self._verify_row_data(True)
  File
"/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
line 325, in _verify_row_data
    self.assertEquals(cells[idx], config_data[str(idx)][1])
AssertionError: u'[null]' != u'1'
- [null]
+ 1


-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
@ 2018-03-29 15:29         ` Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Joao De Almeida Pereira @ 2018-03-29 15:29 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi Dave,
That looks like in the surrounding area of the change. We run our pipeline
and everything was green.
Can you provide more details, which python version are you using? OS?

Thanks
Joao

On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:

> Hi
>
> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
> [email protected]> wrote:
>
>> Hey Akshay and Neethu
>>
>> We refactored the patch to add tests for the resize feature.  We were
>> able to write test cases for the drag event by using spies and setting the
>> rect dimensions.  In cases like this, we can just test some components in
>> order to have enough confidence in the code.  So we isolated the function
>> that implements the behavior of this feature and tested that it was
>> performing as expected.
>>
>> We ran the patch through the pipelines and all of the tests passed.
>>
>
> I'm consistently seeing the feature test failure below with this patch
> applied:
>
> ======================================================================
> FAIL: runTest
> (pgadmin.feature_tests.view_data_dml_queries.CheckForViewDataTest)
> Validate Insert, Update operations in View/Edit data with given test data
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File
> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
> line 125, in runTest
>     self._verify_row_data(True)
>   File
> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
> line 325, in _verify_row_data
>     self.assertEquals(cells[idx], config_data[str(idx)][1])
> AssertionError: u'[null]' != u'1'
> - [null]
> + 1
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
@ 2018-04-03 12:38           ` Dave Page <[email protected]>
  2018-04-03 12:40             ` Re: Bug #3083 fix Dave Page <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Dave Page @ 2018-04-03 12:38 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi

On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
[email protected]> wrote:

> Hi Dave,
> That looks like in the surrounding area of the change. We run our pipeline
> and everything was green.
> Can you provide more details, which python version are you using? OS?
>

That was on my travel laptop, which is macOS Sierra with the Apple supplied
Python 2.7.

Interestingly, I'm on my dev laptop today (same OS and Python) and it's
working just fine. The difference is that the travel machine is a 12"
Macbook, whilst the dev machine is


>
> Thanks
> Joao
>
> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>
>> Hi
>>
>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hey Akshay and Neethu
>>>
>>> We refactored the patch to add tests for the resize feature.  We were
>>> able to write test cases for the drag event by using spies and setting the
>>> rect dimensions.  In cases like this, we can just test some components in
>>> order to have enough confidence in the code.  So we isolated the function
>>> that implements the behavior of this feature and tested that it was
>>> performing as expected.
>>>
>>> We ran the patch through the pipelines and all of the tests passed.
>>>
>>
>> I'm consistently seeing the feature test failure below with this patch
>> applied:
>>
>> ======================================================================
>> FAIL: runTest (pgadmin.feature_tests.view_data_dml_queries.
>> CheckForViewDataTest)
>> Validate Insert, Update operations in View/Edit data with given test data
>> ----------------------------------------------------------------------
>> Traceback (most recent call last):
>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>> line 125, in runTest
>>     self._verify_row_data(True)
>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>> line 325, in _verify_row_data
>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>> AssertionError: u'[null]' != u'1'
>> - [null]
>> + 1
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>


-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
@ 2018-04-03 12:40             ` Dave Page <[email protected]>
  2018-04-03 13:03               ` Re: Bug #3083 fix Harshal Dhumal <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Dave Page @ 2018-04-03 12:40 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Argh, managed to send before I finished typing...

On Tue, Apr 3, 2018 at 1:38 PM, Dave Page <[email protected]> wrote:

> Hi
>
> On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
> [email protected]> wrote:
>
>> Hi Dave,
>> That looks like in the surrounding area of the change. We run our
>> pipeline and everything was green.
>> Can you provide more details, which python version are you using? OS?
>>
>
> That was on my travel laptop, which is macOS Sierra with the Apple
> supplied Python 2.7.
>
> Interestingly, I'm on my dev laptop today (same OS and Python) and it's
> working just fine. The difference is that the travel machine is a 12"
> Macbook, whilst the dev machine is
>

a 15" MacBook Pro with 2 24" external monitors. That makes me wonder if the
small screen size is causing a problem with this test, something we have
seen before.


>
>
>>
>> Thanks
>> Joao
>>
>> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>>
>>> Hi
>>>
>>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>>> [email protected]> wrote:
>>>
>>>> Hey Akshay and Neethu
>>>>
>>>> We refactored the patch to add tests for the resize feature.  We were
>>>> able to write test cases for the drag event by using spies and setting the
>>>> rect dimensions.  In cases like this, we can just test some components in
>>>> order to have enough confidence in the code.  So we isolated the function
>>>> that implements the behavior of this feature and tested that it was
>>>> performing as expected.
>>>>
>>>> We ran the patch through the pipelines and all of the tests passed.
>>>>
>>>
>>> I'm consistently seeing the feature test failure below with this patch
>>> applied:
>>>
>>> ======================================================================
>>> FAIL: runTest (pgadmin.feature_tests.view_da
>>> ta_dml_queries.CheckForViewDataTest)
>>> Validate Insert, Update operations in View/Edit data with given test data
>>> ----------------------------------------------------------------------
>>> Traceback (most recent call last):
>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>> line 125, in runTest
>>>     self._verify_row_data(True)
>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>> line 325, in _verify_row_data
>>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>>> AssertionError: u'[null]' != u'1'
>>> - [null]
>>> + 1
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EnterpriseDB UK: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>



-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 12:40             ` Re: Bug #3083 fix Dave Page <[email protected]>
@ 2018-04-03 13:03               ` Harshal Dhumal <[email protected]>
  2018-04-11 09:56                 ` Re: Bug #3083 fix Dave Page <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Harshal Dhumal @ 2018-04-03 13:03 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Joao De Almeida Pereira <[email protected]>; Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

-- 
*Harshal Dhumal*
*Sr. Software Engineer*

EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

On Tue, Apr 3, 2018 at 6:10 PM, Dave Page <[email protected]> wrote:

> Argh, managed to send before I finished typing...
>
> On Tue, Apr 3, 2018 at 1:38 PM, Dave Page <[email protected]> wrote:
>
>> Hi
>>
>> On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hi Dave,
>>> That looks like in the surrounding area of the change. We run our
>>> pipeline and everything was green.
>>> Can you provide more details, which python version are you using? OS?
>>>
>>
>> That was on my travel laptop, which is macOS Sierra with the Apple
>> supplied Python 2.7.
>>
>> Interestingly, I'm on my dev laptop today (same OS and Python) and it's
>> working just fine. The difference is that the travel machine is a 12"
>> Macbook, whilst the dev machine is
>>
>
> a 15" MacBook Pro with 2 24" external monitors. That makes me wonder if
> the small screen size is causing a problem with this test, something we
> have seen before.
>
>

Yes, screen size does cause problem. Slick grid does not render all columns
if viewport is not wide enough (like it does for rows).
Remaining columns would render when user scrolls right.

To avoid similar problem in datatype feature test (commit:
88bcd3b5129db88975421e26c1bf188daf4892f9
<https://git.postgresql.org/gitweb/?p=pgadmin4.git;a=commitdiff;h=88bcd3b5129db88975421e26c1bf188daf4...;)
I have executed
queries in batch to limit number of columns in single query result.



>
>>
>>>
>>> Thanks
>>> Joao
>>>
>>> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>>>
>>>> Hi
>>>>
>>>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>>>> [email protected]> wrote:
>>>>
>>>>> Hey Akshay and Neethu
>>>>>
>>>>> We refactored the patch to add tests for the resize feature.  We were
>>>>> able to write test cases for the drag event by using spies and setting the
>>>>> rect dimensions.  In cases like this, we can just test some components in
>>>>> order to have enough confidence in the code.  So we isolated the function
>>>>> that implements the behavior of this feature and tested that it was
>>>>> performing as expected.
>>>>>
>>>>> We ran the patch through the pipelines and all of the tests passed.
>>>>>
>>>>
>>>> I'm consistently seeing the feature test failure below with this patch
>>>> applied:
>>>>
>>>> ======================================================================
>>>> FAIL: runTest (pgadmin.feature_tests.view_da
>>>> ta_dml_queries.CheckForViewDataTest)
>>>> Validate Insert, Update operations in View/Edit data with given test
>>>> data
>>>> ----------------------------------------------------------------------
>>>> Traceback (most recent call last):
>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>> line 125, in runTest
>>>>     self._verify_row_data(True)
>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>> line 325, in _verify_row_data
>>>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>>>> AssertionError: u'[null]' != u'1'
>>>> - [null]
>>>> + 1
>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 12:40             ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 13:03               ` Re: Bug #3083 fix Harshal Dhumal <[email protected]>
@ 2018-04-11 09:56                 ` Dave Page <[email protected]>
  2018-04-11 15:46                   ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Dave Page @ 2018-04-11 09:56 UTC (permalink / raw)
  To: Harshal Dhumal <[email protected]>; +Cc: Joao De Almeida Pereira <[email protected]>; Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Joao, are you looking at this?

On Tue, Apr 3, 2018 at 2:03 PM, Harshal Dhumal <
[email protected]> wrote:

>
>
> --
> *Harshal Dhumal*
> *Sr. Software Engineer*
>
> EnterpriseDB India: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Tue, Apr 3, 2018 at 6:10 PM, Dave Page <[email protected]> wrote:
>
>> Argh, managed to send before I finished typing...
>>
>> On Tue, Apr 3, 2018 at 1:38 PM, Dave Page <[email protected]> wrote:
>>
>>> Hi
>>>
>>> On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
>>> [email protected]> wrote:
>>>
>>>> Hi Dave,
>>>> That looks like in the surrounding area of the change. We run our
>>>> pipeline and everything was green.
>>>> Can you provide more details, which python version are you using? OS?
>>>>
>>>
>>> That was on my travel laptop, which is macOS Sierra with the Apple
>>> supplied Python 2.7.
>>>
>>> Interestingly, I'm on my dev laptop today (same OS and Python) and it's
>>> working just fine. The difference is that the travel machine is a 12"
>>> Macbook, whilst the dev machine is
>>>
>>
>> a 15" MacBook Pro with 2 24" external monitors. That makes me wonder if
>> the small screen size is causing a problem with this test, something we
>> have seen before.
>>
>>
>
> Yes, screen size does cause problem. Slick grid does not render all
> columns if viewport is not wide enough (like it does for rows).
> Remaining columns would render when user scrolls right.
>
> To avoid similar problem in datatype feature test (commit:
> 88bcd3b5129db88975421e26c1bf188daf4892f9
> <https://git.postgresql.org/gitweb/?p=pgadmin4.git;a=commitdiff;h=88bcd3b5129db88975421e26c1bf188daf4...;)
> I have executed
> queries in batch to limit number of columns in single query result.
>
>
>
>>
>>>
>>>>
>>>> Thanks
>>>> Joao
>>>>
>>>> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hey Akshay and Neethu
>>>>>>
>>>>>> We refactored the patch to add tests for the resize feature.  We were
>>>>>> able to write test cases for the drag event by using spies and setting the
>>>>>> rect dimensions.  In cases like this, we can just test some components in
>>>>>> order to have enough confidence in the code.  So we isolated the function
>>>>>> that implements the behavior of this feature and tested that it was
>>>>>> performing as expected.
>>>>>>
>>>>>> We ran the patch through the pipelines and all of the tests passed.
>>>>>>
>>>>>
>>>>> I'm consistently seeing the feature test failure below with this patch
>>>>> applied:
>>>>>
>>>>> ======================================================================
>>>>> FAIL: runTest (pgadmin.feature_tests.view_da
>>>>> ta_dml_queries.CheckForViewDataTest)
>>>>> Validate Insert, Update operations in View/Edit data with given test
>>>>> data
>>>>> ----------------------------------------------------------------------
>>>>> Traceback (most recent call last):
>>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>> line 125, in runTest
>>>>>     self._verify_row_data(True)
>>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>> line 325, in _verify_row_data
>>>>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>>>>> AssertionError: u'[null]' != u'1'
>>>>> - [null]
>>>>> + 1
>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EnterpriseDB UK: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>
>


-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 12:40             ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 13:03               ` Re: Bug #3083 fix Harshal Dhumal <[email protected]>
  2018-04-11 09:56                 ` Re: Bug #3083 fix Dave Page <[email protected]>
@ 2018-04-11 15:46                   ` Joao De Almeida Pereira <[email protected]>
  2018-04-11 16:04                     ` Re: Bug #3083 fix Dave Page <[email protected]>
  0 siblings, 1 reply; 13+ messages in thread

From: Joao De Almeida Pereira @ 2018-04-11 15:46 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Harshal Dhumal <[email protected]>; Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi Dave,
Do you still have issues in your environment?

Thanks
Joao

On Wed, Apr 11, 2018 at 5:56 AM Dave Page <[email protected]> wrote:

> Joao, are you looking at this?
>
> On Tue, Apr 3, 2018 at 2:03 PM, Harshal Dhumal <
> [email protected]> wrote:
>
>>
>>
>> --
>> *Harshal Dhumal*
>> *Sr. Software Engineer*
>>
>> EnterpriseDB India: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Tue, Apr 3, 2018 at 6:10 PM, Dave Page <[email protected]> wrote:
>>
>>> Argh, managed to send before I finished typing...
>>>
>>> On Tue, Apr 3, 2018 at 1:38 PM, Dave Page <[email protected]> wrote:
>>>
>>>> Hi
>>>>
>>>> On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi Dave,
>>>>> That looks like in the surrounding area of the change. We run our
>>>>> pipeline and everything was green.
>>>>> Can you provide more details, which python version are you using? OS?
>>>>>
>>>>
>>>> That was on my travel laptop, which is macOS Sierra with the Apple
>>>> supplied Python 2.7.
>>>>
>>>> Interestingly, I'm on my dev laptop today (same OS and Python) and it's
>>>> working just fine. The difference is that the travel machine is a 12"
>>>> Macbook, whilst the dev machine is
>>>>
>>>
>>> a 15" MacBook Pro with 2 24" external monitors. That makes me wonder if
>>> the small screen size is causing a problem with this test, something we
>>> have seen before.
>>>
>>>
>>
>> Yes, screen size does cause problem. Slick grid does not render all
>> columns if viewport is not wide enough (like it does for rows).
>> Remaining columns would render when user scrolls right.
>>
>> To avoid similar problem in datatype feature test (commit:
>> 88bcd3b5129db88975421e26c1bf188daf4892f9
>> <https://git.postgresql.org/gitweb/?p=pgadmin4.git;a=commitdiff;h=88bcd3b5129db88975421e26c1bf188daf4...;)
>> I have executed
>> queries in batch to limit number of columns in single query result.
>>
>>
>>
>>>
>>>>
>>>>>
>>>>> Thanks
>>>>> Joao
>>>>>
>>>>> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>>>>>
>>>>>> Hi
>>>>>>
>>>>>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hey Akshay and Neethu
>>>>>>>
>>>>>>> We refactored the patch to add tests for the resize feature.  We
>>>>>>> were able to write test cases for the drag event by using spies and setting
>>>>>>> the rect dimensions.  In cases like this, we can just test some components
>>>>>>> in order to have enough confidence in the code.  So we isolated the
>>>>>>> function that implements the behavior of this feature and tested that it
>>>>>>> was performing as expected.
>>>>>>>
>>>>>>> We ran the patch through the pipelines and all of the tests passed.
>>>>>>>
>>>>>>
>>>>>> I'm consistently seeing the feature test failure below with this
>>>>>> patch applied:
>>>>>>
>>>>>> ======================================================================
>>>>>> FAIL: runTest
>>>>>> (pgadmin.feature_tests.view_data_dml_queries.CheckForViewDataTest)
>>>>>> Validate Insert, Update operations in View/Edit data with given test
>>>>>> data
>>>>>> ----------------------------------------------------------------------
>>>>>> Traceback (most recent call last):
>>>>>>   File
>>>>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>>> line 125, in runTest
>>>>>>     self._verify_row_data(True)
>>>>>>   File
>>>>>> "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>>> line 325, in _verify_row_data
>>>>>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>>>>>> AssertionError: u'[null]' != u'1'
>>>>>> - [null]
>>>>>> + 1
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Dave Page
>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>> Twitter: @pgsnake
>>>>>>
>>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>>> The Enterprise PostgreSQL Company
>>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EnterpriseDB UK: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>
>>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>


^ permalink  raw  reply  [nested|flat] 13+ messages in thread

* Re: Bug #3083 fix
  2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
  2018-03-01 22:10 ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-28 12:03   ` Re: Bug #3083 fix Akshay Joshi <[email protected]>
  2018-03-28 18:06     ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-03-29 13:03       ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-03-29 15:29         ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
  2018-04-03 12:38           ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 12:40             ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-03 13:03               ` Re: Bug #3083 fix Harshal Dhumal <[email protected]>
  2018-04-11 09:56                 ` Re: Bug #3083 fix Dave Page <[email protected]>
  2018-04-11 15:46                   ` Re: Bug #3083 fix Joao De Almeida Pereira <[email protected]>
@ 2018-04-11 16:04                     ` Dave Page <[email protected]>
  0 siblings, 0 replies; 13+ messages in thread

From: Dave Page @ 2018-04-11 16:04 UTC (permalink / raw)
  To: Joao De Almeida Pereira <[email protected]>; +Cc: Harshal Dhumal <[email protected]>; Akshay Joshi <[email protected]>; Neethu Mariya Joy <[email protected]>; pgadmin-hackers

Hi

On Wed, Apr 11, 2018 at 4:46 PM, Joao De Almeida Pereira <
[email protected]> wrote:

> Hi Dave,
> Do you still have issues in your environment?
>

I just tested on my MBP, and got the following failure:

======================================================================
ERROR: runTest (pgadmin.feature_tests.query_tool_tests.QueryToolFeatureTest)
Query tool feature test
----------------------------------------------------------------------
Traceback (most recent call last):
  File
"/Users/dpage/git/pgadmin4/web/regression/feature_utils/base_feature_test.py",
line 43, in setUp
    self.before()
  File
"/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_tests.py",
line 46, in before
    self._reset_options()
  File
"/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/query_tool_tests.py",
line 113, in _reset_options
    self.page.fill_codemirror_area_with('')
  File
"/Users/dpage/git/pgadmin4/web/regression/feature_utils/pgadmin_page.py",
line 227, in fill_codemirror_area_with
    until(find_codemirror, "Timed out waiting for codemirror "
  File
"/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py",
line 80, in click
    self._execute(Command.CLICK_ELEMENT)
  File
"/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/selenium/webdriver/remote/webelement.py",
line 628, in _execute
    return self._parent.execute(command, params)
  File
"/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py",
line 312, in execute
    self.error_handler.check_response(response)
  File
"/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py",
line 242, in check_response
    raise exception_class(message, screen, stacktrace)
WebDriverException: Message: unknown error: Element <iframe
cd_frame_id_="6af0765089f43a73f733471ef04cb792">...</iframe> is not
clickable at point (813, 155). Other element would receive the click: <div
class="wcLoadingIconContainer">...</div>
  (Session info: chrome=65.0.3325.181)
  (Driver info: chromedriver=2.37.544337
(8c0344a12e552148c185f7d5117db1f28d6c9e85),platform=Mac OS X 10.12.6 x86_64)



>
> Thanks
> Joao
>
> On Wed, Apr 11, 2018 at 5:56 AM Dave Page <[email protected]> wrote:
>
>> Joao, are you looking at this?
>>
>> On Tue, Apr 3, 2018 at 2:03 PM, Harshal Dhumal <
>> [email protected]> wrote:
>>
>>>
>>>
>>> --
>>> *Harshal Dhumal*
>>> *Sr. Software Engineer*
>>>
>>> EnterpriseDB India: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Tue, Apr 3, 2018 at 6:10 PM, Dave Page <[email protected]> wrote:
>>>
>>>> Argh, managed to send before I finished typing...
>>>>
>>>> On Tue, Apr 3, 2018 at 1:38 PM, Dave Page <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> On Thu, Mar 29, 2018 at 4:29 PM, Joao De Almeida Pereira <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi Dave,
>>>>>> That looks like in the surrounding area of the change. We run our
>>>>>> pipeline and everything was green.
>>>>>> Can you provide more details, which python version are you using? OS?
>>>>>>
>>>>>
>>>>> That was on my travel laptop, which is macOS Sierra with the Apple
>>>>> supplied Python 2.7.
>>>>>
>>>>> Interestingly, I'm on my dev laptop today (same OS and Python) and
>>>>> it's working just fine. The difference is that the travel machine is a 12"
>>>>> Macbook, whilst the dev machine is
>>>>>
>>>>
>>>> a 15" MacBook Pro with 2 24" external monitors. That makes me wonder if
>>>> the small screen size is causing a problem with this test, something we
>>>> have seen before.
>>>>
>>>>
>>>
>>> Yes, screen size does cause problem. Slick grid does not render all
>>> columns if viewport is not wide enough (like it does for rows).
>>> Remaining columns would render when user scrolls right.
>>>
>>> To avoid similar problem in datatype feature test (commit:
>>> 88bcd3b5129db88975421e26c1bf188daf4892f9
>>> <https://git.postgresql.org/gitweb/?p=pgadmin4.git;a=commitdiff;h=88bcd3b5129db88975421e26c1bf188daf4...;)
>>> I have executed
>>> queries in batch to limit number of columns in single query result.
>>>
>>>
>>>
>>>>
>>>>>
>>>>>>
>>>>>> Thanks
>>>>>> Joao
>>>>>>
>>>>>> On Thu, Mar 29, 2018 at 9:03 AM Dave Page <[email protected]> wrote:
>>>>>>
>>>>>>> Hi
>>>>>>>
>>>>>>> On Wed, Mar 28, 2018 at 7:06 PM, Joao De Almeida Pereira <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hey Akshay and Neethu
>>>>>>>>
>>>>>>>> We refactored the patch to add tests for the resize feature.  We
>>>>>>>> were able to write test cases for the drag event by using spies and setting
>>>>>>>> the rect dimensions.  In cases like this, we can just test some components
>>>>>>>> in order to have enough confidence in the code.  So we isolated the
>>>>>>>> function that implements the behavior of this feature and tested that it
>>>>>>>> was performing as expected.
>>>>>>>>
>>>>>>>> We ran the patch through the pipelines and all of the tests passed.
>>>>>>>>
>>>>>>>
>>>>>>> I'm consistently seeing the feature test failure below with this
>>>>>>> patch applied:
>>>>>>>
>>>>>>> ============================================================
>>>>>>> ==========
>>>>>>> FAIL: runTest (pgadmin.feature_tests.view_data_dml_queries.
>>>>>>> CheckForViewDataTest)
>>>>>>> Validate Insert, Update operations in View/Edit data with given test
>>>>>>> data
>>>>>>> ------------------------------------------------------------
>>>>>>> ----------
>>>>>>> Traceback (most recent call last):
>>>>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>>>> line 125, in runTest
>>>>>>>     self._verify_row_data(True)
>>>>>>>   File "/Users/dpage/git/pgadmin4/web/pgadmin/feature_tests/view_data_dml_queries.py",
>>>>>>> line 325, in _verify_row_data
>>>>>>>     self.assertEquals(cells[idx], config_data[str(idx)][1])
>>>>>>> AssertionError: u'[null]' != u'1'
>>>>>>> - [null]
>>>>>>> + 1
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Dave Page
>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>> Twitter: @pgsnake
>>>>>>>
>>>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>>>> The Enterprise PostgreSQL Company
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>
>>>
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>


-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


^ permalink  raw  reply  [nested|flat] 13+ messages in thread


end of thread, other threads:[~2018-04-11 16:04 UTC | newest]

Thread overview: 13+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2018-02-27 17:17 Bug #3083 fix Neethu Mariya Joy <[email protected]>
2018-03-01 22:10 ` Joao De Almeida Pereira <[email protected]>
2018-03-28 12:03   ` Akshay Joshi <[email protected]>
2018-03-28 18:06     ` Joao De Almeida Pereira <[email protected]>
2018-03-29 10:32       ` Akshay Joshi <[email protected]>
2018-03-29 13:03       ` Dave Page <[email protected]>
2018-03-29 15:29         ` Joao De Almeida Pereira <[email protected]>
2018-04-03 12:38           ` Dave Page <[email protected]>
2018-04-03 12:40             ` Dave Page <[email protected]>
2018-04-03 13:03               ` Harshal Dhumal <[email protected]>
2018-04-11 09:56                 ` Dave Page <[email protected]>
2018-04-11 15:46                   ` Joao De Almeida Pereira <[email protected]>
2018-04-11 16:04                     ` Dave Page <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox