public inbox for [email protected]  
help / color / mirror / Atom feed
From: Aditya Toshniwal <[email protected]>
To: pgadmin-hackers <[email protected]>
Cc: Akshay Joshi <[email protected]>
Subject: Re: [pgAdmin][RM6130] React based framework for properties dialog and port Server Group, Server and Database dialogs
Date: Mon, 28 Jun 2021 14:50:36 +0530
Message-ID: <CAM9w-_=UjoitLEooheh5yF3vvZHdoSv4hMpD0z3Ge9g0ri1cwQ@mail.gmail.com> (raw)
In-Reply-To: <CANxoLDexFZ4=EMO-r45RAJwopo-k54o6+QYr08H=KziEAm11dQ@mail.gmail.com>
References: <CAM9w-_=RbH2Nt9cWRf5ZaE509-a2nxvDxdNYN=BakLGvM288Lg@mail.gmail.com>
	<CA+OCxoxSOEBPErd-FXTHLi6gpVbo3TzkVQcZwzMg9P3+Cmnj6w@mail.gmail.com>
	<CAM9w-_=FJqY-kJkEDzq7vXmBVv0SdbWe=Gkq2qBL9mbxYyA8pw@mail.gmail.com>
	<CANxoLDexFZ4=EMO-r45RAJwopo-k54o6+QYr08H=KziEAm11dQ@mail.gmail.com>

Hi Hackers,

I made some changes to the core code that will be helpful for other nodes.
Please review.


On Thu, Jun 24, 2021 at 5:39 PM Akshay Joshi <[email protected]>
wrote:

> Thanks, the patch applied in the "React_Porting" branch.
>
> On Mon, Jun 21, 2021 at 9:35 AM Aditya Toshniwal <
> [email protected]> wrote:
>
>> Hi Dave,
>>
>> On Thu, Jun 17, 2021 at 7:26 PM Dave Page <[email protected]> wrote:
>>
>>> Hi
>>>
>>> On Thu, Jun 17, 2021 at 11:01 AM Aditya Toshniwal <
>>> [email protected]> wrote:
>>>
>>>> Hi Hackers,
>>>>
>>>> Attached patch marks the beginning of migrating properties dialog/tab
>>>> to React based code, which is easy to maintain, performant and testable
>>>> using automation.
>>>> Patch includes:
>>>> - Framework for creating React based dynamic form view out of a
>>>> pre-defined UI schema. Previously, it was based on Backform/Backbone.
>>>> - The new framework and components will use MaterialUI as base.
>>>> Previously, Bootstrap/Backform/jQuery components were used.
>>>> - The new code uses JSS instead of CSS since material ui and most
>>>> modern React libraries also use JSS. In future, this will allow us to
>>>> change the theme in real-time without refresh.
>>>> - 90% code covered by 80-85 new jasmine test cases.
>>>> - Server group node UI Schema migration to new, with schema test cases.
>>>> - Server node UI Schema migration to new, with schema test cases.
>>>> - Database node UI Schema migration to new, with schema test cases.
>>>> - Few other UI changes.
>>>>
>>>
>>> Nice!
>>>
>>>
>>>>
>>>> PS: Until all the nodes are migrated, this will not go in the main
>>>> branch.
>>>>
>>>
>>> Yeah, how are we going to manage this? I agree with building it out in a
>>> branch until we have full coverage of the dialogues, but I'm concerned that
>>> it'll become a merge nightmare. Though, I guess we aren't touching the
>>> dialogues much for other things right now, so maybe not.
>>>
>> We'll right now work only on the dialogs. So merging should be manageable.
>> BTW, the patch can be merged in the main branch as well. It is backward
>> compatible, and it will work fine. Only the UI components would look
>> slightly different from the non-migrated dialogs.
>>
>>>
>>> --
>>> Dave Page
>>> Blog: https://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: https://www.enterprisedb.com
>>>
>>>
>>
>> --
>> Thanks,
>> Aditya Toshniwal
>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>> <http://edbpostgres.com;
>> "Don't Complain about Heat, Plant a TREE"
>>
>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


-- 
Thanks,
Aditya Toshniwal
pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
<http://edbpostgres.com;
"Don't Complain about Heat, Plant a TREE"


Attachments:

  [application/octet-stream] RM6130.part2.patch (11.8K, 3-RM6130.part2.patch)
  download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.ui.js b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.ui.js
index fb42b37c5..769570961 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.ui.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.ui.js
@@ -17,7 +17,7 @@ export class DefaultPrivSchema extends BaseUISchema {
     this.getPrivilegeRoleSchema = getPrivilegeRoleSchema;
   }
 
-  get fields() {
+  get baseFields() {
     return [
       {
         id: 'deftblacl', type: 'collection', group: gettext('Tables'),
@@ -89,7 +89,7 @@ export default class DatabaseSchema extends BaseUISchema {
     return 'did';
   }
 
-  get fields() {
+  get baseFields() {
     let obj = this;
     return [
       {
diff --git a/web/pgadmin/browser/static/js/node_view.jsx b/web/pgadmin/browser/static/js/node_view.jsx
index 837364769..9067b5a1b 100644
--- a/web/pgadmin/browser/static/js/node_view.jsx
+++ b/web/pgadmin/browser/static/js/node_view.jsx
@@ -171,12 +171,18 @@ export function getNodeView(nodeType, treeNodeInfo, actionType, itemNodeData, fo
     inCatalog: inCatalog,
   };
 
+  let schema = nodeObj.getSchema.call(nodeObj, treeNodeInfo, itemNodeData);
+  // Show/Hide security group for nodes under the catalog
+  if('catalog' in treeNodeInfo) {
+    schema.filterGroups = [gettext('Security')];
+  }
+
   /* Fire at will, mount the DOM */
   ReactDOM.render(
     <SchemaView
       formType={formType}
       getInitData={initData}
-      schema={nodeObj.getSchema.call(nodeObj, treeNodeInfo, itemNodeData)}
+      schema={schema}
       viewHelperProps={viewHelperProps}
       onSave={onSaveClick}
       onClose={()=>containerPanel.close()}
diff --git a/web/pgadmin/static/js/SchemaView/DataGridView.jsx b/web/pgadmin/static/js/SchemaView/DataGridView.jsx
index 3cf16783b..89f9b519f 100644
--- a/web/pgadmin/static/js/SchemaView/DataGridView.jsx
+++ b/web/pgadmin/static/js/SchemaView/DataGridView.jsx
@@ -257,16 +257,16 @@ export default function DataGridView({
                     (viewHelperProps.serverInfo.version <= field.max_version))));
                 let _readonly = viewHelperProps.inCatalog || (viewHelperProps.mode == 'properties');
                 if(!_readonly) {
-                  _readonly = evalFunc(readonly, row.original || {});
+                  _readonly = evalFunc(schema, readonly, row.original || {});
                 }
 
                 let _visible = true;
                 if(visible) {
-                  _visible = evalFunc(visible, row.original || {});
+                  _visible = evalFunc(schema, visible, row.original || {});
                 }
                 _visible = _visible && verInLimit;
 
-                disabled = evalFunc(disabled, row.original || {});
+                disabled = evalFunc(schema, disabled, row.original || {});
 
                 return <MappedCellControl rowIndex={row.index} value={value}
                   row={row.original} {..._field}
diff --git a/web/pgadmin/static/js/SchemaView/FormView.jsx b/web/pgadmin/static/js/SchemaView/FormView.jsx
index 485d983dd..49d133d17 100644
--- a/web/pgadmin/static/js/SchemaView/FormView.jsx
+++ b/web/pgadmin/static/js/SchemaView/FormView.jsx
@@ -105,17 +105,17 @@ export default function FormView({
 
       let _readonly = viewHelperProps.inCatalog || (viewHelperProps.mode == 'properties');
       if(!_readonly) {
-        _readonly = evalFunc(readonly, value);
+        _readonly = evalFunc(schema, readonly, value);
       }
 
       let _visible = true;
 
       if(visible) {
-        _visible = evalFunc(visible, value);
+        _visible = evalFunc(schema, visible, value);
       }
       _visible = _visible && verInLimit;
 
-      disabled = evalFunc(disabled, value);
+      disabled = evalFunc(schema, disabled, value);
 
 
       if(!tabs[group]) tabs[group] = [];
@@ -151,6 +151,7 @@ export default function FormView({
                 firstEleRef.current = ele;
               }
             }}
+            state={value}
             key={field.id}
             viewHelperProps={viewHelperProps}
             name={field.id}
diff --git a/web/pgadmin/static/js/SchemaView/MappedControl.jsx b/web/pgadmin/static/js/SchemaView/MappedControl.jsx
index 46a815245..6195d610f 100644
--- a/web/pgadmin/static/js/SchemaView/MappedControl.jsx
+++ b/web/pgadmin/static/js/SchemaView/MappedControl.jsx
@@ -158,7 +158,7 @@ const ALLOWED_PROPS_FIELD_COMMON = [
 ];
 
 const ALLOWED_PROPS_FIELD_FORM = [
-  'type', 'onChange'
+  'type', 'onChange', 'state',
 ];
 
 const ALLOWED_PROPS_FIELD_CELL = [
@@ -168,7 +168,7 @@ const ALLOWED_PROPS_FIELD_CELL = [
 
 export const MappedFormControl = (props)=>{
   let newProps = {...props};
-  let typeProps = evalFunc(newProps.type, newProps.value);
+  let typeProps = evalFunc(null, newProps.type, newProps.state);
   if(typeof(typeProps) === 'object') {
     newProps = {
       ...newProps,
@@ -184,7 +184,7 @@ export const MappedFormControl = (props)=>{
 
 export const MappedCellControl = (props)=>{
   let newProps = {...props};
-  let cellProps = evalFunc(newProps.cell, newProps.row);
+  let cellProps = evalFunc(null, newProps.cell, newProps.row);
   if(typeof(cellProps) === 'object') {
     newProps = {
       ...newProps,
diff --git a/web/pgadmin/static/js/SchemaView/base_schema.ui.js b/web/pgadmin/static/js/SchemaView/base_schema.ui.js
index fb01a24d2..7f9091dda 100644
--- a/web/pgadmin/static/js/SchemaView/base_schema.ui.js
+++ b/web/pgadmin/static/js/SchemaView/base_schema.ui.js
@@ -17,6 +17,7 @@ export default class BaseUISchema {
     this._defaults = defaults;
 
     this.keys = null; // If set, other fields except keys will be filtered
+    this.filterGroups = []; // If set, these groups will be filtered out
     this.informText = null; // Inform text to show after save, this only saves it
     this._top = null;
   }
@@ -59,13 +60,26 @@ export default class BaseUISchema {
   concat base fields with extraFields.
   */
   get fields() {
-    /* Select only keys if specified */
     return this.baseFields
-      .filter((field)=>this.keys ? this.keys.indexOf(field.id) > -1 : true);
+      .filter((field)=>{
+        let retval;
+
+        /* If any groups are to be filtered */
+        retval = this.filterGroups.indexOf(field.group) == -1;
+
+        /* Select only keys, if specified */
+        if(this.keys) {
+          retval = retval && this.keys.indexOf(field.id) > -1;
+        }
+        return retval;
+      });
   }
 
   /* Check if current data is new or existing */
   isNew(state) {
+    if(_.isUndefined(state)) {
+      state = this.origData;
+    }
     if(_.has(state, this.idAttribute)) {
       return _.isUndefined(state[this.idAttribute])
         || _.isNull(state[this.idAttribute]);
diff --git a/web/pgadmin/static/js/SchemaView/index.jsx b/web/pgadmin/static/js/SchemaView/index.jsx
index c3106b36c..c8c4167c4 100644
--- a/web/pgadmin/static/js/SchemaView/index.jsx
+++ b/web/pgadmin/static/js/SchemaView/index.jsx
@@ -85,7 +85,10 @@ function getChangedData(topSchema, mode, sessData, stringify=false) {
       return;
     } else {
       change = change || _.get(sessData, currPath);
-      _.set(changedData, currPath, stringify ? JSON.stringify(change) : change);
+      if(stringify && (_.isArray(change) || _.isObject(change))) {
+        change = JSON.stringify(change);
+      }
+      _.set(changedData, currPath, change);
     }
   };
 
@@ -104,8 +107,8 @@ function getChangedData(topSchema, mode, sessData, stringify=false) {
             /* Use diffArray package to get the array diff and extract the info
             cid is used to identify the rows uniquely */
             const changeDiff = diffArray(
-              _.get(topSchema.origData, currPath),
-              _.get(sessData, currPath),
+              _.get(topSchema.origData, currPath) || [],
+              _.get(sessData, currPath) || [],
               'cid'
             );
             change = {};
@@ -130,9 +133,9 @@ function getChangedData(topSchema, mode, sessData, stringify=false) {
         } else if(!isEdit) {
           if(field.type === 'collection') {
             let change = cleanCid(_.get(sessData, currPath));
-            attrChanged(currPath, change);
+            attrChanged(currPath, change, true);
           } else {
-            attrChanged(currPath);
+            attrChanged(currPath, null , true);
           }
         }
       }
@@ -566,10 +569,10 @@ function SchemaPropertiesView({
       _visible = (field.mode.indexOf(viewHelperProps.mode) > -1);
     }
     if(_visible && visible) {
-      _visible = evalFunc(visible, origData);
+      _visible = evalFunc(schema, visible, origData);
     }
 
-    disabled = evalFunc(disabled, origData);
+    disabled = evalFunc(schema, disabled, origData);
     readonly = true;
     if(_visible && verInLimit) {
       if(!tabs[group]) tabs[group] = [];
diff --git a/web/pgadmin/static/js/Theme/index.jsx b/web/pgadmin/static/js/Theme/index.jsx
index 57bf72964..6a6e1fc29 100644
--- a/web/pgadmin/static/js/Theme/index.jsx
+++ b/web/pgadmin/static/js/Theme/index.jsx
@@ -251,17 +251,17 @@ function getFinalTheme(baseTheme) {
           fontSize: baseTheme.typography.fontSize,
           height: 'unset',
           backgroundColor: baseTheme.palette.background.default,
-          '&[readonly]': {
-            backgroundColor: baseTheme.palette.inputDisabledBg,
-          }
+          '&[readonly], &.Mui-disabled': {
+            backgroundColor: baseTheme.otherVars.inputDisabledBg,
+          },
         },
         input: {
           fontSize: baseTheme.typography.fontSize,
           height: 'unset',
           backgroundColor: baseTheme.palette.background.default,
-          '&[readonly]': {
+          '&[readonly], &.Mui-disabled': {
             backgroundColor: baseTheme.otherVars.inputDisabledBg,
-          }
+          },
         }
       },
       MuiIconButton: {
diff --git a/web/pgadmin/static/js/components/FormComponents.jsx b/web/pgadmin/static/js/components/FormComponents.jsx
index 660366851..f5dd5f98b 100644
--- a/web/pgadmin/static/js/components/FormComponents.jsx
+++ b/web/pgadmin/static/js/components/FormComponents.jsx
@@ -535,7 +535,7 @@ function getRealValue(options, value, creatable) {
 }
 
 export function InputSelect({
-  cid, onChange, options, readonly=false, value, controlProps={}, optionsLoaded, disabled, ...props}) {
+    cid, onChange, options, readonly=false, value, controlProps={}, optionsLoaded, disabled, ...props}) {
   const [[finalOptions, isLoading], setFinalOptions] = useState([[], true]);
   const theme = useTheme();
 
@@ -563,7 +563,9 @@ export function InputSelect({
     }
   }, [onChange]);
 
-  const realValue = getRealValue(finalOptions, value, controlProps.creatable);
+  /* Apply filter if any */
+  const filteredOptions = (controlProps.filter && controlProps.filter(finalOptions)) || finalOptions;
+  const realValue = getRealValue(filteredOptions, value, controlProps.creatable);
   const otherProps = {
     isSearchable: !readonly,
     isClearable: !readonly && (!_.isUndefined(controlProps.allowClear) ? controlProps.allowClear : true),
@@ -581,7 +583,7 @@ export function InputSelect({
     openMenuOnClick: !readonly,
     onChange: onChangeOption,
     isLoading: isLoading,
-    options: finalOptions,
+    options: filteredOptions,
     value: realValue,
     menuPortalTarget: document.body,
     styles: styles,
diff --git a/web/pgadmin/static/js/utils.js b/web/pgadmin/static/js/utils.js
index 81a3b0fe8..3eaa55283 100644
--- a/web/pgadmin/static/js/utils.js
+++ b/web/pgadmin/static/js/utils.js
@@ -410,9 +410,9 @@ function checkBinaryPathExists(binaryPathArray, selectedServerVersion) {
 }
 
 /* If a function, then evaluate */
-export function evalFunc(func, param) {
+export function evalFunc(obj, func, param) {
   if(_.isFunction(func)) {
-    return func.apply(null, [param]);
+    return func.apply(obj, [param]);
   }
   return func;
 }


view thread (7+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected]
  Subject: Re: [pgAdmin][RM6130] React based framework for properties dialog and port Server Group, Server and Database dialogs
  In-Reply-To: <CAM9w-_=UjoitLEooheh5yF3vvZHdoSv4hMpD0z3Ge9g0ri1cwQ@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

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