Hi Hackers,

Please find the attached patch for RM-6672:
<https://redmine.postgresql.org/issues/6672> [React] Port Triggers node to
react.
Also, resolved the issue in the trigger function node, the schema is not
getting selected in the edit mode.


-- 
*Thanks & Regards,*
*Nikhil Mohite*
*Software Engineer.*
*EDB Postgres* <https://www.enterprisedb.com/>
*Mob.No: +91-7798364578.*
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
index 154a17bb8..c4b023eea 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py
@@ -1480,8 +1480,7 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
         parallel_dict = {'u': 'UNSAFE', 's': 'SAFE', 'r': 'RESTRICTED'}
 
         # Get Schema Name from its OID.
-        if self.node_type != 'trigger_function':
-            self._get_schema_name_from_oid(data)
+        self._get_schema_name_from_oid(data)
 
         if fnid is not None:
             # Edit Mode
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/trigger_function.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/trigger_function.js
index 83ed9c6e3..84e1b03aa 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/trigger_function.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/static/js/trigger_function.js
@@ -7,7 +7,7 @@
 //
 //////////////////////////////////////////////////////////////
 import TriggerFunctionSchema from './trigger_function.ui';
-import { getNodeListByName, getNodeAjaxOptions } from '../../../../../../../static/js/node_ajax';
+import { getNodeListByName, getNodeListById, getNodeAjaxOptions } from '../../../../../../../static/js/node_ajax';
 import { getNodeVariableSchema } from '../../../../../static/js/variable.ui';
 import { getNodePrivilegeRoleSchema } from '../../../../../static/js/privilege.ui';
 
@@ -91,7 +91,9 @@ define('pgadmin.node.trigger_function', [
           ()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, false, false),
           {
             role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
-            schema: ()=>getNodeListByName('schema', treeNodeInfo, itemNodeData, {cacheLevel: 'database'}),
+            schema: ()=>getNodeListById(pgBrowser.Nodes['schema'], treeNodeInfo, itemNodeData, {
+              cacheLevel: 'database'
+            }),
             language: ()=>getNodeAjaxOptions('get_languages', this, treeNodeInfo, itemNodeData, {noCache: true}, (res) => {
               return _.reject(res, function(o) {
                 return o.label == 'sql' || o.label == 'edbspl';
@@ -101,7 +103,7 @@ define('pgadmin.node.trigger_function', [
           },
           {
             funcowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
-            pronamespace: treeNodeInfo.schema ? treeNodeInfo.schema.label : ''
+            pronamespace: treeNodeInfo.schema ? treeNodeInfo.schema._id : null
           }
         );
       },
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js
index 22e20fa92..2b9904e0d 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.js
@@ -6,6 +6,8 @@
 // This software is released under the PostgreSQL Licence
 //
 //////////////////////////////////////////////////////////////
+import { getNodeListByName, getNodeAjaxOptions } from '../../../../../../../../static/js/node_ajax';
+import TriggerSchema from './trigger.ui';
 
 define('pgadmin.node.trigger', [
   'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
@@ -173,6 +175,19 @@ define('pgadmin.node.trigger', [
       },
       canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
       canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
+      getSchema: function(treeNodeInfo, itemNodeData) {
+        return new TriggerSchema(
+          {
+            triggerFunction: ()=>getNodeAjaxOptions('get_triggerfunctions', this, treeNodeInfo, itemNodeData, {cacheLevel: 'trigger_function'}, (data) => {
+              return _.reject(data, function(option) {
+                return option.label == '';
+              });
+            }),
+            columns: ()=> getNodeListByName('column', treeNodeInfo, itemNodeData, { cacheLevel: 'column'}),
+            nodeInfo: treeNodeInfo
+          },
+        );
+      },
       model: pgAdmin.Browser.Node.Model.extend({
         idAttribute: 'oid',
         defaults: {
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.ui.js
new file mode 100644
index 000000000..974142f7e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.ui.js
@@ -0,0 +1,492 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2021, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import gettext from 'sources/gettext';
+import BaseUISchema from 'sources/SchemaView/base_schema.ui';
+import { isEmptyString } from 'sources/validators';
+
+export class EventSchema extends BaseUISchema {
+  constructor(fieldOptions={}, initValues) {
+    super({
+      evnt_update: false,
+      evnt_insert: false,
+      evnt_delete: false,
+      evnt_truncate: false,
+      is_row_trigger: false,
+      is_constraint_trigger: false,
+      ...initValues,
+    });
+
+    this.fieldOptions = {
+      nodeInfo: null,
+      ...fieldOptions,
+    };
+
+    this.nodeInfo = this.fieldOptions.nodeInfo;
+
+  }
+
+  get idAttribute() {
+    return 'oid';
+  }
+
+  inSchemaWithModelCheck(state) {
+    // Check if we are under schema node & in 'create' mode
+    if(this.nodeInfo && 'schema' in this.nodeInfo) {
+      // We will disable control if it's in 'edit' mode
+      return !this.isNew(state);
+    }
+    return true;
+  }
+
+  get baseFields() {
+    let obj = this;
+    return [{
+      id: 'evnt_insert', label: gettext('INSERT'),
+      type: 'switch', mode: ['create','edit', 'properties'],
+      group: gettext('Events'),
+      disabled: (state) => {
+        var evn_insert = state.evnt_insert;
+        if (!_.isUndefined(evn_insert) && obj.nodeInfo && obj.nodeInfo.server.server_type == 'ppas' && obj.isNew(state))
+          return false;
+        return obj.inSchemaWithModelCheck(state);
+      },
+    },{
+      id: 'evnt_update', label: gettext('UPDATE'),
+      type: 'switch', mode: ['create','edit', 'properties'],
+      group: gettext('Events'),
+      disabled: (state) => {
+        var evn_update = state.evnt_update;
+        if (!_.isUndefined(evn_update) && obj.nodeInfo && obj.nodeInfo.server.server_type == 'ppas' && obj.isNew(state))
+          return false;
+        return obj.inSchemaWithModelCheck(state);
+      },
+    },{
+      id: 'evnt_delete', label: gettext('DELETE'),
+      type: 'switch', mode: ['create','edit', 'properties'],
+      group: gettext('Events'),
+      disabled: (state) => {
+        var evn_delete = state.evnt_delete;
+        if (!_.isUndefined(evn_delete) && obj.nodeInfo && obj.nodeInfo.server.server_type == 'ppas' && obj.isNew(state))
+          return false;
+        return obj.inSchemaWithModelCheck(state);
+      },
+    },{
+      id: 'evnt_truncate', label: gettext('TRUNCATE'),
+      type: 'switch', group: gettext('Events'), deps: ['is_row_trigger', 'is_constraint_trigger'],
+      disabled: (state) => {
+        var is_constraint_trigger = state.is_constraint_trigger,
+          is_row_trigger = state.is_row_trigger,
+          server_type = obj.nodeInfo ? obj.nodeInfo.server.server_type: null;
+        if (is_row_trigger == true){
+          state.evnt_truncate = false;
+          return true;
+        }
+
+        if (server_type === 'ppas' && !_.isUndefined(is_constraint_trigger) &&
+        !_.isUndefined(is_row_trigger) &&
+        is_constraint_trigger === false && obj.isNew(state))
+          return false;
+
+        return obj.inSchemaWithModelCheck(state);
+      },
+    }];
+  }
+
+  validate(state, setError) {
+
+    if (isEmptyString(state.service)) {
+      let errmsg = null;
+      /* events validation*/
+      if (state.tfunction && !state.evnt_truncate && !state.evnt_delete && !state.evnt_update && !state.evnt_insert) {
+        errmsg = gettext('Specify at least one event.');
+        //setError('evnt_truncate', errmsg);
+        //setError('evnt_delete', errmsg);
+        //setError('evnt_update', errmsg);
+        setError('evnt_insert', errmsg);
+        //setError('evnt_update', errmsg);
+        return true;
+      } else {
+        errmsg = null;
+        //setError('evnt_truncate', errmsg);
+        //setError('evnt_delete', errmsg);
+        //setError('evnt_update', errmsg);
+        setError('evnt_insert', errmsg);
+      }
+    }
+  }
+
+}
+
+
+export default class TriggerSchema extends BaseUISchema {
+  constructor(fieldOptions={}, initValues) {
+    super({
+      name: undefined,
+      is_row_trigger: true,
+      fires: 'BEFORE',
+      ...initValues
+    });
+
+    this.fieldOptions = {
+      triggerFunction: [],
+      //columns: [],
+      ...fieldOptions,
+    };
+    this.nodeInfo = this.fieldOptions.nodeInfo;
+
+  }
+
+  get idAttribute() {
+    return 'oid';
+  }
+
+  inSchema() {
+    // Check if under schema node & in 'create' mode
+    if('catalog' in this.nodeInfo) {
+      return true;
+    }
+    return false;
+  }
+
+  inSchemaWithModelCheck(state) {
+    // Check if we are under schema node & in 'create' mode
+    if('schema' in this.nodeInfo) {
+      // We will disable control if it's in 'edit' mode
+      return !this.isNew(state);
+    }
+    return true;
+  }
+
+  disableTransition(state) {
+    if (!this.isNew())
+      return true;
+    var flag = false,
+      evnt = null,
+      name = state.name,
+      evnt_count = 0;
+
+    // Disable transition tables for view trigger and PG version < 100000
+    if(_.indexOf(Object.keys(this.nodeInfo), 'table') == -1 ||
+      this.nodeInfo.server.version < 100000) return true;
+
+    if (name == 'tgoldtable') evnt = 'evnt_delete';
+    else if (name == 'tgnewtable') evnt = 'evnt_insert';
+
+    if(state.evnt_insert) evnt_count++;
+    if(state.evnt_update) evnt_count++;
+    if(state.evnt_delete) evnt_count++;
+
+
+    // Disable transition tables if
+    //  - It is a constraint trigger
+    //  - Fires other than AFTER
+    //  - More than one events enabled
+    //  - Update event with the column list
+
+    // Disable Old transition table if both UPDATE and DELETE events are disabled
+    // Disable New transition table if both UPDATE and INSERT events are disabled
+    if(!state.is_constraint_trigger && state.fires == 'AFTER' &&
+      (state.evnt_update || state[evnt]) && evnt_count == 1) {
+      flag = (state.evnt_update && (_.size(state.columns) >= 1 && state.columns[0] != ''));
+    }
+
+    if(flag && state.name) {
+      state.name = null;
+    }
+
+    return flag;
+  }
+
+  get baseFields() {
+    let obj = this;
+    return [{
+      id: 'name', label: gettext('Name'), cell: 'text',
+      type: 'text', disabled: obj.inSchema, noEmpty: true
+    },{
+      id: 'oid', label: gettext('OID'), cell: 'text',
+      type: 'int', mode: ['properties'],
+    },{
+      id: 'is_enable_trigger', label: gettext('Trigger enabled?'),
+      mode: ['edit', 'properties'], group: gettext('Definition'),
+      type: 'select',
+      disabled: () => {
+        if('catalog' in obj.nodeInfo || 'view' in obj.nodeInfo) {
+          return true;
+        }
+        return false;
+      },
+      options: [
+        {label: gettext('Enable'), value: 'O'},
+        {label: gettext('Enable Replica'), value: 'R'},
+        {label: gettext('Enable Always'), value: 'A'},
+        {label: gettext('Disable'), value: 'D'},
+      ],
+      controlProps: { allowClear: false },
+    },{
+      id: 'is_row_trigger', label: gettext('Row trigger?'),
+      type: 'switch', group: gettext('Definition'),
+      mode: ['create','edit', 'properties'],
+      deps: ['is_constraint_trigger'],
+      disabled: (state) => {
+        // Disabled if table is a partitioned table.
+        if (!obj.isNew())
+          return true;
+
+        if (obj.nodeInfo.table.is_partitioned && obj.nodeInfo.server.version < 110000)
+        {
+          state.is_row_trigger = false;
+          return true;
+        }
+
+        // If constraint trigger is set to True then row trigger will
+        // automatically set to True and becomes disable
+        var is_constraint_trigger = state.is_constraint_trigger;
+        if(!obj.inSchemaWithModelCheck(state)) {
+          if(!_.isUndefined(is_constraint_trigger) &&
+            is_constraint_trigger === true) {
+            // change it's model value
+            state.is_row_trigger = true;
+            return true;
+          } else {
+            return false;
+          }
+        } else {
+          // Check if it is row trigger then enabled it.
+          var is_row_trigger = state.is_row_trigger;
+          if (!_.isUndefined(is_row_trigger) && obj.nodeInfo.server.server_type == 'ppas') {
+            return false;
+          }
+          // Disable it
+          return true;
+        }
+      },
+    },{
+      id: 'is_constraint_trigger', label: gettext('Constraint trigger?'),
+      type: 'switch',
+      mode: ['create','edit', 'properties'],
+      group: gettext('Definition'),
+      deps: ['tfunction'],
+      disabled: (state) => {
+        // Disabled if table is a partitioned table.
+        var tfunction = state.tfunction;
+        if (( _.has(obj.nodeInfo, 'table') && _.has(obj.nodeInfo.table, 'is_partitioned') &&
+         obj.nodeInfo.table.is_partitioned) || ( _.has(obj.nodeInfo, 'view')) ||
+         (obj.nodeInfo.server.server_type === 'ppas' && !_.isUndefined(tfunction) &&
+         tfunction === 'Inline EDB-SPL')) {
+          state.is_constraint_trigger = false;
+          return true;
+        }
+        return obj.inSchemaWithModelCheck(state);
+      },
+    },{
+      id: 'tgdeferrable', label: gettext('Deferrable?'),
+      type: 'switch', group: gettext('Definition'),
+      mode: ['create','edit', 'properties'],
+      deps: ['is_constraint_trigger'],
+      disabled: (state) => {
+        // If constraint trigger is set to True then only enable it
+        var is_constraint_trigger = state.is_constraint_trigger;
+        if(!obj.inSchemaWithModelCheck(state)) {
+          if(!_.isUndefined(is_constraint_trigger) &&
+            is_constraint_trigger === true) {
+            return false;
+          } else {
+            // If value is already set then reset it to false
+            if(state.tgdeferrable) {
+              state.tgdeferrable =  false;
+            }
+            return true;
+          }
+        } else {
+          // Disable it
+          return true;
+        }
+      },
+    },{
+      id: 'tginitdeferred', label: gettext('Deferred?'),
+      type: 'switch', group: gettext('Definition'),
+      mode: ['create','edit', 'properties'],
+      deps: ['tgdeferrable', 'is_constraint_trigger'],
+      disabled: (state) => {
+        // If Deferrable is set to True then only enable it
+        var tgdeferrable = state.tgdeferrable;
+        if(!obj.inSchemaWithModelCheck(state)) {
+          if(!_.isUndefined(tgdeferrable) && tgdeferrable) {
+            return false;
+          } else {
+            // If value is already set then reset it to false
+            if(obj.tginitdeferred) {
+              state.tginitdeferred = false;
+            }
+            // If constraint trigger is set then do not disable
+            return state.is_constraint_trigger ? false : true;
+          }
+        } else {
+          // Disable it
+          return true;
+        }
+      },
+    },{
+      id: 'tfunction', label: gettext('Trigger function'),
+      type: 'select', disabled: obj.inSchemaWithModelCheck,
+      mode: ['create','edit', 'properties'], group: gettext('Definition'),
+      control: 'node-ajax-options', url: 'get_triggerfunctions', url_jump_after_node: 'schema',
+      options: obj.fieldOptions.triggerFunction,
+      cache_node: 'trigger_function',
+    },{
+      id: 'tgargs', label: gettext('Arguments'), cell: 'text',
+      group: gettext('Definition'),
+      type: 'text',mode: ['create','edit', 'properties'], deps: ['tfunction'],
+      disabled: (state) => {
+        // We will disable it when EDB PPAS and trigger function is
+        // set to Inline EDB-SPL
+        var tfunction = state.tfunction,
+          server_type = obj.nodeInfo.server.server_type;
+        if(!obj.inSchemaWithModelCheck(state)) {
+          if(server_type === 'ppas' &&
+            !_.isUndefined(tfunction) &&
+              tfunction === 'Inline EDB-SPL') {
+            // Disable and clear its value
+            state.tgargs = undefined;
+            return true;
+          } else {
+            return false;
+          }
+        } else {
+          // Disable it
+          return true;
+        }
+      },
+    },{
+      id: 'fires', label: gettext('Fires'), deps: ['is_constraint_trigger'],
+      mode: ['create','edit', 'properties'], group: gettext('Events'),
+      options: () => {
+        var table_options = [
+            {label: 'BEFORE', value: 'BEFORE'},
+            {label: 'AFTER', value: 'AFTER'}],
+          view_options = [
+            {label: 'BEFORE', value: 'BEFORE'},
+            {label: 'AFTER', value: 'AFTER'},
+            {label: 'INSTEAD OF', value: 'INSTEAD OF'}];
+        // If we are under table then show table specific options
+        if(_.indexOf(Object.keys(obj.nodeInfo), 'table') != -1) {
+          return table_options;
+        } else {
+          return view_options;
+        }
+      },
+      type: 'select', controlProps: { allowClear: false },
+      disabled: (state) => {
+        if (!obj.isNew())
+          return true;
+        // If contraint trigger is set to True then only enable it
+        var is_constraint_trigger = obj.is_constraint_trigger;
+        if(!obj.inSchemaWithModelCheck(state)) {
+          if(!_.isUndefined(is_constraint_trigger) &&
+            is_constraint_trigger === true) {
+            state.fires = 'AFTER';
+            return true;
+          } else {
+            return false;
+          }
+        } else {
+          // Check if it is row trigger then enabled it.
+          var fires_ = state.fires;
+          if (!_.isUndefined(fires_) && obj.nodeInfo.server.server_type == 'ppas') {
+            return false;
+          }
+          // Disable it
+          return true;
+        }
+      },
+    },{
+      type: 'nested-fieldset', mode: ['create','edit', 'properties'],
+      label: gettext('Events'), group: gettext('Events'),
+      schema: new EventSchema({nodeInfo: obj.nodeInfo}),
+    },{
+      id: 'whenclause', label: gettext('When'),
+      type: 'sql',
+      readonly: obj.inSchemaWithModelCheck,
+      mode: ['create', 'edit', 'properties'], visible: true,
+      group: gettext('Events'),
+    },{
+      id: 'columns', label: gettext('Columns'),
+      type: 'select', controlProps: { multiple: true },
+      deps: ['evnt_update'], group: gettext('Events'),
+      options: obj.fieldOptions.columns,
+      disabled: (state) => {
+        if(obj.nodeInfo &&  'catalog' in obj.nodeInfo) {
+          return true;
+        }
+        //Disable in edit mode
+        if (!obj.isNew()) {
+          return true;
+        }
+        // Enable column only if update event is set true
+        var isUpdate = state.evnt_update;
+        if(!_.isUndefined(isUpdate) && isUpdate) {
+          return false;
+        }
+        return true;
+      },
+    },{
+      id: 'tgoldtable', label: gettext('Old table'),
+      type: 'text', group: gettext('Transition'),
+      cell: 'text', mode: ['create', 'edit', 'properties'],
+      deps: ['fires', 'is_constraint_trigger', 'evnt_insert', 'evnt_update', 'evnt_delete', 'columns'],
+      disabled: obj.disableTransition,
+    },{
+      id: 'tgnewtable', label: gettext('New table'),
+      type: 'text', group: gettext('Transition'),
+      cell: 'string', mode: ['create', 'edit', 'properties'],
+      deps: ['fires', 'is_constraint_trigger', 'evnt_insert', 'evnt_update', 'evnt_delete', 'columns'],
+      disabled: obj.disableTransition,
+    },{
+      id: 'prosrc', label: gettext('Code'), group: gettext('Code'),
+      type: 'sql', mode: ['create', 'edit'], deps: ['tfunction'],
+      isFullTab: true,
+      visible: true,
+      readonly: (state) => {
+        // We will enable it only when EDB PPAS and trigger function is
+        // set to Inline EDB-SPL
+        var tfunction = state.tfunction,
+          server_type = obj.nodeInfo.server.server_type;
+
+        return (server_type !== 'ppas' ||
+        _.isUndefined(tfunction) ||
+          tfunction !== 'Inline EDB-SPL');
+      },
+    },{
+      id: 'is_sys_trigger', label: gettext('System trigger?'), cell: 'text',
+      type: 'switch', disabled: obj.inSchemaWithModelCheck, mode: ['properties'],
+    },{
+      id: 'description', label: gettext('Comment'), cell: 'string',
+      type: 'multiline', mode: ['properties', 'create', 'edit'],
+      disabled: obj.inSchema,
+    }];
+  }
+
+  validate(state, setError) {
+    let errmsg = null;
+
+    if (isEmptyString(state.service)) {
+
+      /* trigger function validation*/
+      if (isEmptyString(state.tfunction)) {
+        errmsg = gettext('Trigger function cannot be empty.');
+        setError('tfunction', errmsg);
+        return true;
+      } else {
+        errmsg = null;
+        setError('tfunction', errmsg);
+      }
+    }
+  }
+}
diff --git a/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.ui.js b/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.ui.js
index 16bb02201..7320238d1 100644
--- a/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.ui.js
+++ b/web/pgadmin/browser/server_groups/servers/pgagent/schedules/static/js/pga_schedule.ui.js
@@ -405,6 +405,7 @@ export default class PgaJobScheduleSchema extends BaseUISchema {
       }
     ];
   }
+
   validate(state, setError) {
     if (isEmptyString(state.jscstart)) {
       setError('jscstart', gettext('Please enter the start time.'));
diff --git a/web/pgadmin/static/js/SchemaView/FormView.jsx b/web/pgadmin/static/js/SchemaView/FormView.jsx
index d00ac6240..9b8bb05aa 100644
--- a/web/pgadmin/static/js/SchemaView/FormView.jsx
+++ b/web/pgadmin/static/js/SchemaView/FormView.jsx
@@ -63,6 +63,7 @@ function SQLTab({active, getSQLValue}) {
       readOnly: true,
     }}
     isAsync={true}
+    readonly={true}
   />;
 }
 
diff --git a/web/pgadmin/static/js/components/CodeMirror.jsx b/web/pgadmin/static/js/components/CodeMirror.jsx
index cb03ab18f..4745fda9f 100644
--- a/web/pgadmin/static/js/components/CodeMirror.jsx
+++ b/web/pgadmin/static/js/components/CodeMirror.jsx
@@ -13,7 +13,7 @@ import {useOnScreen} from 'sources/custom_hooks';
 import PropTypes from 'prop-types';
 
 /* React wrapper for CodeMirror */
-export default function CodeMirror({name, value, options, events, ...props}) {
+export default function CodeMirror({currObj, name, value, options, events, ...props}) {
   const taRef = useRef();
   const cmObj = useRef();
   const cmWrapper = useRef();
@@ -24,6 +24,8 @@ export default function CodeMirror({name, value, options, events, ...props}) {
     cmObj.current = new OrigCodeMirror.fromTextArea(
       taRef.current, options);
 
+    currObj && currObj(cmObj.current);
+
     if(cmObj.current) {
       try {
         cmWrapper.current = cmObj.current.getWrapperElement();
@@ -65,6 +67,7 @@ export default function CodeMirror({name, value, options, events, ...props}) {
 }
 
 CodeMirror.propTypes = {
+  currObj: PropTypes.func,
   name: PropTypes.string,
   value: PropTypes.string,
   options: PropTypes.object,
diff --git a/web/pgadmin/static/js/components/FormComponents.jsx b/web/pgadmin/static/js/components/FormComponents.jsx
index 43a80bef5..7505ad044 100644
--- a/web/pgadmin/static/js/components/FormComponents.jsx
+++ b/web/pgadmin/static/js/components/FormComponents.jsx
@@ -137,11 +137,19 @@ FormInput.propTypes = {
   testcid: PropTypes.any,
 };
 
-export function InputSQL({value, options, onChange, ...props}) {
+export function InputSQL({value, options, onChange, readonly, ...props}) {
   const classes = useStyles();
+  const cmObj = useRef();
+
+  useEffect(()=>{
+    if(cmObj.current) {
+      cmObj.current.setOption('readOnly', readonly);
+    }
+  }, [readonly]);
 
   return (
     <CodeMirror
+      currObj={(obj)=>cmObj.current=obj}
       value={value||''}
       options={{
         lineNumbers: true,
@@ -161,8 +169,8 @@ export function InputSQL({value, options, onChange, ...props}) {
 InputSQL.propTypes = {
   value: PropTypes.string,
   options: PropTypes.object,
-  onChange: PropTypes.func
-
+  onChange: PropTypes.func,
+  readonly: PropTypes.bool
 };
 
 export function FormInputSQL({hasError, required, label, className, helpMessage, testcid, value, controlProps, noLabel, ...props}) {
diff --git a/web/regression/javascript/schema_ui_files/trigger.ui.spec.js b/web/regression/javascript/schema_ui_files/trigger.ui.spec.js
new file mode 100644
index 000000000..c437b33ff
--- /dev/null
+++ b/web/regression/javascript/schema_ui_files/trigger.ui.spec.js
@@ -0,0 +1,378 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2021, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import jasmineEnzyme from 'jasmine-enzyme';
+import React from 'react';
+import '../helper/enzyme.helper';
+import { createMount } from '@material-ui/core/test-utils';
+import pgAdmin from 'sources/pgadmin';
+import {messages} from '../fake_messages';
+import SchemaView from '../../../pgadmin/static/js/SchemaView';
+//import BaseUISchema from 'sources/SchemaView/base_schema.ui';
+import TriggerSchema, { EventSchema } from '../../../pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/static/js/trigger.ui';
+
+describe('TriggerSchema', ()=>{
+  let mount;
+  let schemaObj = new TriggerSchema(
+    {
+      triggerFunction: [],
+      columns: [],
+      nodeInfo: {
+        schema: {},
+        server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 90400},
+        table: {is_partitioned: false}
+      }
+    }
+  );
+  let getInitData = ()=>Promise.resolve({});
+
+  /* Use createMount so that material ui components gets the required context */
+  /* https://material-ui.com/guides/testing/#api */
+  beforeAll(()=>{
+    mount = createMount();
+  });
+
+  afterAll(() => {
+    mount.cleanUp();
+  });
+
+  beforeEach(()=>{
+    jasmineEnzyme();
+    /* messages used by validators */
+    pgAdmin.Browser = pgAdmin.Browser || {};
+    pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
+    pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
+  });
+
+  it('create', ()=>{
+    mount(<SchemaView
+      formType='dialog'
+      schema={schemaObj}
+      viewHelperProps={{
+        mode: 'create',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('edit', ()=>{
+    mount(<SchemaView
+      formType='dialog'
+      schema={schemaObj}
+      getInitData={getInitData}
+      viewHelperProps={{
+        mode: 'edit',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('properties', ()=>{
+    mount(<SchemaView
+      formType='tab'
+      schema={schemaObj}
+      getInitData={getInitData}
+      viewHelperProps={{
+        mode: 'properties',
+      }}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+    />);
+  });
+
+  it('validate', ()=>{
+    let state = {};
+    let setError = jasmine.createSpy('setError');
+
+    state.tfunction = null;
+    schemaObj.validate(state, setError);
+    expect(setError).toHaveBeenCalledWith('tfunction', 'Trigger function cannot be empty.');
+
+    state.tfunction = 'public';
+    schemaObj.validate(state, setError);
+    expect(setError).toHaveBeenCalledWith('tfunction', null);
+  });
+
+  it('catalog create', ()=>{
+    let catalogSchemaObj = new TriggerSchema(
+      {
+        triggerFunction: [],
+        columns: [],
+        nodeInfo: {
+          catalog: {},
+          server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 90400},
+          table: {is_partitioned: false}
+        }
+      }
+    );
+
+    mount(<SchemaView
+      formType='dialog'
+      schema={catalogSchemaObj}
+      viewHelperProps={{
+        mode: 'create',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('catalog properties', ()=>{
+    let catalogPropertiesSchemaObj = new TriggerSchema(
+      {
+        triggerFunction: [],
+        columns: [],
+        nodeInfo: {
+          catalog: {},
+          server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 90400},
+          table: {is_partitioned: false}
+        }
+      }
+    );
+
+    mount(<SchemaView
+      formType='tab'
+      schema={catalogPropertiesSchemaObj}
+      getInitData={getInitData}
+      viewHelperProps={{
+        mode: 'properties',
+      }}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+    />);
+  });
+
+  it('edit disableTransition', ()=>{
+    let editSchemaObj = new TriggerSchema(
+      {
+        triggerFunction: [],
+        columns: [],
+        nodeInfo: {
+          catalog: {},
+          server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 100000},
+          table: {is_partitioned: false}
+        }
+      }
+    );
+
+    let initData = ()=>Promise.resolve({
+      tgoldtable: 'tgoldtable',
+      evnt_insert: true,
+      evnt_update: true,
+      evnt_delete: true,
+      is_constraint_trigger: true,
+      name: 'tgoldtable',
+      fires: 'AFTER'
+    });
+
+    mount(<SchemaView
+      formType='dialog'
+      schema={editSchemaObj}
+      getInitData={initData}
+      viewHelperProps={{
+        mode: 'edit',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('edit disableTransition tgnewtable', ()=>{
+    let editSchemaObj = new TriggerSchema(
+      {
+        triggerFunction: [],
+        columns: [],
+        nodeInfo: {
+          catalog: {},
+          server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 100000},
+          table: {is_partitioned: false}
+        }
+      }
+    );
+
+    let initData = ()=>Promise.resolve({
+      tgoldtable: 'tgnewtable',
+      evnt_insert: true,
+      evnt_update: true,
+      evnt_delete: true,
+      is_constraint_trigger: false,
+      name: 'tgnewtable',
+      fires: 'AFTER'
+    });
+
+    mount(<SchemaView
+      formType='dialog'
+      schema={editSchemaObj}
+      getInitData={initData}
+      viewHelperProps={{
+        mode: 'edit',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+});
+
+
+describe('TriggerEventsSchema', ()=>{
+  let mount;
+  let schemaObj = new EventSchema(
+    {
+      nodeInfo: {
+        server: {user: {name:'postgres', id:0}, server_type: 'pg', version: 90400},
+        table: {is_partitioned: false}
+      }
+    }
+  );
+  let getInitData = ()=>Promise.resolve({});
+
+  /* Use createMount so that material ui components gets the required context */
+  /* https://material-ui.com/guides/testing/#api */
+  beforeAll(()=>{
+    mount = createMount();
+  });
+
+  afterAll(() => {
+    mount.cleanUp();
+  });
+
+  beforeEach(()=>{
+    jasmineEnzyme();
+    /* messages used by validators */
+    pgAdmin.Browser = pgAdmin.Browser || {};
+    pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
+    pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
+  });
+
+  it('create', ()=>{
+    mount(<SchemaView
+      formType='dialog'
+      schema={schemaObj}
+      viewHelperProps={{
+        mode: 'create',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('properties', ()=>{
+    mount(<SchemaView
+      formType='tab'
+      schema={schemaObj}
+      getInitData={getInitData}
+      viewHelperProps={{
+        mode: 'properties',
+      }}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+    />);
+  });
+
+  it('edit', ()=>{
+    mount(<SchemaView
+      formType='dialog'
+      schema={schemaObj}
+      getInitData={getInitData}
+      viewHelperProps={{
+        mode: 'edit',
+      }}
+      onSave={()=>{}}
+      onClose={()=>{}}
+      onHelp={()=>{}}
+      onEdit={()=>{}}
+      onDataChange={()=>{}}
+      confirmOnCloseReset={false}
+      hasSQL={false}
+      disableSqlHelp={false}
+    />);
+  });
+
+  it('validate', ()=>{
+    let state = {};
+    let setError = jasmine.createSpy('setError');
+
+
+    state.tfunction = 'public';
+    state.evnt_truncate = false;
+    state.evnt_delete = false;
+    state.evnt_update = false;
+    state.evnt_insert = false;
+    schemaObj.validate(state, setError);
+    expect(setError).toHaveBeenCalledWith('evnt_insert', 'Specify at least one event.');
+
+    state.tfunction = 'public';
+    state.evnt_insert = true;
+    schemaObj.validate(state, setError);
+    expect(setError).toHaveBeenCalledWith('evnt_insert', null);
+  });
+
+  //spyOn(schemaObj, 'isNew’).and.returnValue(true);
+
+  /*it('evnt_insert disabled', ()=>{
+    let disabled = _.find(schemaObj.fields, (f)=>f.id=='evnt_insert').disabled;
+    disabled({evnt_insert : true});
+  });
+
+  it('evnt_update disabled', ()=>{
+    let disabled = _.find(schemaObj.fields, (f)=>f.id=='evnt_update').disabled;
+    disabled({evnt_update : true});
+  });
+
+  it('evnt_delete disabled', ()=>{
+    let disabled = _.find(schemaObj.fields, (f)=>f.id=='evnt_delete').disabled;
+    disabled({evnt_delete : true});
+  });
+
+  it('evnt_truncate disabled', ()=>{
+    getInitData = ()=>Promise.resolve({is_constraint_trigger: true});
+    let disabled = _.find(schemaObj.fields, (f)=>f.id=='evnt_truncate').disabled;
+    disabled({evnt_truncate : true});
+  });*/
+
+});

Reply via email to