diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/__init__.py b/web/pgadmin/browser/server_groups/servers/resourcegroups/__init__.py
new file mode 100644
index 0000000..cc8bbc7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/__init__.py
@@ -0,0 +1,476 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import NodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+
+
+class ResourceGroupModule(CollectionNodeModule):
+    NODE_TYPE = 'resourcegroup'
+    COLLECTION_LABEL = gettext("Resource Groups")
+
+    def __init__(self, *args, **kwargs):
+        self.min_ver = None
+        self.max_ver = None
+
+        super(ResourceGroupModule, self).__init__(*args, **kwargs)
+
+    def BackendSupported(self, manager, **kwargs):
+        """
+        BackendSupported(self, manager, **kwargs)
+
+        This function is used to check the database server type and version.
+        Resource Group only supported in PPAS 9.4 and above.
+
+        Parameters:
+            manager:
+            - Object of the server manager class
+        """
+        if super(ResourceGroupModule, self).BackendSupported(manager, **kwargs):
+            conn = manager.connection()
+            # If DB is not connected then return error to browser
+            if not conn.connected():
+                return precondition_required(gettext("Connection to the server has been lost!"))
+        if manager.server_type == 'ppas' and manager.version >= 90400:
+            return True
+        else:
+            return False
+
+    def get_nodes(self, gid, sid):
+        """
+        get_nodes(self, gid, sid)
+
+        This function is used to get the collection node
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+        """
+        yield self.generate_browser_collection_node(sid)
+
+    @property
+    def node_inode(self):
+        """
+        node_inode
+
+        Override this property to make the node as leaf node.
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        script_load()
+
+        Load the module script for server, when any of the resource group node is
+        initialized.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = ResourceGroupModule(__name__)
+
+
+class ResourceGroupView(NodeView):
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'rg_id'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}]
+    })
+
+    def __init__(self, **kwargs):
+        self.conn = None
+        self.template_path = None
+
+        super(ResourceGroupView, self).__init__(**kwargs)
+
+    def module_js(self):
+        """
+        module_js
+
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "resourcegroups/js/resourcegroup.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        check_precondition(f)
+
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+        Parameters:
+            f
+            -
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.driver = get_driver(PG_DEFAULT_DRIVER)
+            self.manager = self.driver.connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection()
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.template_path = 'resourcegroups/sql'
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid):
+        sql = render_template("/".join([self.template_path, 'properties.sql']))
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid):
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']))
+        status, result = self.conn.execute_2darray(sql)
+        if not status:
+            return internal_server_error(errormsg=result)
+
+        for row in result['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['oid'],
+                        sid,
+                        row['name'],
+                        icon="icon-resourcegroup"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    @check_precondition
+    def properties(self, gid, sid, rg_id):
+        sql = render_template("/".join([self.template_path, 'properties.sql']), rgid=rg_id)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid):
+        """
+        This function will creates new the resource group object
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+        """
+        required_args = [
+            'name'
+        ]
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+        try:
+            # Below logic will create new resource group
+            sql = render_template("/".join([self.template_path, 'create.sql']), rgname=data['name'], conn=self.conn)
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+            # Below logic will update the cpu_rate_limit and dirty_rate_limit for resource group
+            # we need to add this logic because in resource group you can't run multiple commands in one transaction.
+            sql = render_template("/".join([self.template_path, 'update.sql']), data=data, conn=self.conn)
+            # Checking if we are not executing empty query
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+            # Below logic is used to fetch the oid of the newly created resource group
+            sql = render_template("/".join([self.template_path, 'getoid.sql']), rgname=data['name'])
+            # Checking if we are not executing empty query
+            rg_id = 0
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, rg_id = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=rg_id)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    rg_id,
+                    data['name'],
+                    icon="icon-resourcegroup"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, rg_id):
+        """
+        This function will update resource group object
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+            rg_id
+            - Resource Group Id
+        """
+        required_args = [
+            'name', 'cpu_rate_limit', 'dirty_rate_limit'
+        ]
+        data = request.form if request.form else json.loads(request.data.decode())
+
+        try:
+            sql = render_template("/".join([self.template_path, 'properties.sql']), rgid=rg_id)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                    return internal_server_error(errormsg=res)
+            old_data = res['rows'][0]
+            for arg in required_args:
+                if arg not in data:
+                    data[arg] = old_data[arg]
+
+            if data['name'] != old_data['name']:
+                sql = render_template("/".join([self.template_path, 'update.sql']),
+                                      oldname=old_data['name'], newname=data['name'], conn=self.conn)
+                if sql and sql.strip('\n') and sql.strip(' '):
+                    status, res = self.conn.execute_scalar(sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+            # Below logic will update the cpu_rate_limit and dirty_rate_limit for resource group
+            # we need to add this logic because in resource group you can't run multiple commands
+            # in one transaction.
+            if (data['cpu_rate_limit'] != old_data['cpu_rate_limit']) \
+                    or (data['dirty_rate_limit'] != old_data['dirty_rate_limit']):
+                sql = render_template("/".join([self.template_path, 'update.sql']), data=data, conn=self.conn)
+                if sql and sql.strip('\n') and sql.strip(' '):
+                    status, res = self.conn.execute_scalar(sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info="Resource Group updated",
+                data={
+                    'id': rg_id,
+                    'sid': sid,
+                    'gid': gid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, rg_id):
+        """
+        This function will drop the resource group object
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+            rg_id
+            - Resource Group Id
+        """
+        try:
+            # Get name for resource group from rg_id
+            sql = render_template("/".join([self.template_path, 'delete.sql']), rgid=rg_id, conn=self.conn)
+            status, rgname = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=rgname)
+            # drop resource group
+            sql = render_template("/".join([self.template_path, 'delete.sql']), rgname=rgname, conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Resource Group dropped"),
+                data={
+                    'id': rg_id,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, rg_id=None):
+        """
+        This function to return modified sql
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+            rg_id
+            - Resource Group Id
+        """
+        data = request.args.copy()
+        sql = self.get_sql(gid, sid, data, rg_id)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data='-- Modified SQL --',
+                    status=200
+                    )
+
+    def get_sql(self, gid, sid, data, rg_id=None):
+        """
+        This function will generate sql from model data
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+            data
+            - Contains the value of name, cpu_rate_limit, dirty_rate_limit
+            rg_id
+            - Resource Group Id
+        """
+        required_args = [
+            'name', 'cpu_rate_limit', 'dirty_rate_limit'
+        ]
+        try:
+            if rg_id is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), rgid=rg_id)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+                old_data = res['rows'][0]
+                for arg in required_args:
+                    if arg not in data:
+                        data[arg] = old_data[arg]
+
+                sql = ''
+                name_changed = False
+                if data['name'] != old_data['name']:
+                    name_changed = True
+                    sql = render_template("/".join([self.template_path, 'update.sql']),
+                                          oldname=old_data['name'], newname=data['name'], conn=self.conn)
+                if (data['cpu_rate_limit'] != old_data['cpu_rate_limit'])\
+                        or data['dirty_rate_limit'] != old_data['dirty_rate_limit']:
+                    if name_changed:
+                        sql += "\n-- Following query will be executed in a separate transaction\n"
+                    sql += render_template("/".join([self.template_path, 'update.sql']), data=data, conn=self.conn)
+            else:
+                sql = render_template("/".join([self.template_path, 'create.sql']), rgname=data['name'], conn=self.conn)
+                if (data['cpu_rate_limit'] and int(data['cpu_rate_limit']) > 0) \
+                        or (data['dirty_rate_limit'] and int(data['dirty_rate_limit']) > 0):
+                    sql += "\n-- Following query will be executed in a separate transaction\n"
+                    sql += render_template("/".join([self.template_path, 'update.sql']), data=data, conn=self.conn)
+
+            return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, rg_id):
+        """
+        This function will generate sql for sql panel
+
+        Parameters:
+            gid
+            - Group Id
+            sid
+            - Server Id
+            rg_id
+            - Resource Group Id
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), rgid=rg_id)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        # Making copy of output for future use
+        old_data = dict(res['rows'][0])
+
+        sql = render_template("/".join([self.template_path, 'create.sql']), display_comments=True,
+                              rgname=old_data['name'], conn=self.conn)
+        sql += "\n"
+        sql += render_template("/".join([self.template_path, 'update.sql']), data=old_data, conn=self.conn)
+
+        return ajax_response(response=sql)
+
+ResourceGroupView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/static/img/coll-resourcegroup.png b/web/pgadmin/browser/server_groups/servers/resourcegroups/static/img/coll-resourcegroup.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ea2387bac58697bbf0bab29912818f66d11c1a5
GIT binary patch
literal 1173
zcmY*X3rv$&6uwZ90d|5QWrC5(z(S$4wNNOt3bX@O>7*13F=4z_2t!7ZYN8S<uM&!4
zsijKDc&H5J;dl&YC<6uzH+7@7iNPW;X4;HU_Ol<Wzuf&K%d*|vbH1GK<h%Fg+^^=i
zAeQK~*9ibXjF00Aadg>^_Xv0<2k%P4!R}O4LKFaf_0Cv^Jzo1{#R(GtxZnpsnG66c
z#L)ym2@L>qIsj}n0Hnf(&wuy?0NZ27kBN9k8s{N|F^%Iw^~Lke#CX+hQfi)iY6&~V
zk)E>e{p505^1hq5^9Hp_t_Bl#tclxEVH=E8LQ1uX)qtI7hxm?ZoJ?$m^lE+RH7j4G
z;i#ZMU57J#Rr85<3_rHC*;U-J8d^8SyasuiwZlrY|D`cO3of_vG-#B1k#%j=@A6z=
z)rzQfmZzTOHDes*FKhvbY#0hvOw((1K~)CdOGa*!nSFirh;lNZY=lw!ic+)QtHZQL
zt6~D;d{3_3LK$J=tfRkdMQenI8zH3@+gmhUmtxzKPiW1y|4{lkryCxuSUakQNo`g^
z%OX#+!mMAU$@TOaV?Z_PSvZ^6iuLNyu?4eY!WyYuc#!5{xM(|C<lrwepX$Lv>ej^_
zP;10=W~5S!1<B0=c{`xO`}xJ4`=y4a8OT;z@qt_#K}&~Lyd_UPznHizv@c6?s1(`x
zNFJ)DvG4{gstIG%qX9C#N5K?LfgM(^#WcO*C|9WR`4G85K91z~nF6YjULAfBs+dG0
zt|Q%9u1}?&!+F$$vc=0I>y%oU@D(~b4|OJM#VA6Nqy71|u!^ob@9iU<>(irG9<EX3
zNNh89VHkf5lG%ljD@>hf&OMpL&XaEYOQ!I@^D8%nC?Kc7NWJoiS~1B{W0hK1)Q@pg
zSjix!nMKtz=IEQ4&IBv9R!YsPVq#fmLdF)Cd-T?EBPJVN^Dkehn=p(Uk-_KNE(+mn
zQgIJ*BtpTqH~+JiEEdbVt*s3U(em!?PRnk@-a@e1cx_$6*$uq8`PyRH+Hl(3!rr|>
z*DXr}E@{2E+$NJB%e8^F!A87rJR6r<3;@-4J8YyKN6z8on|N-N$a601<ub{|{lPaR
zkBoFX!j43T*n_7?VpggD-7<C6of|{-JuTYsL)@bWd}!qGkC;IpM+-mI*pq$SKG?I*
z&5P7>Rjmwi-hGuHpTK`I^V96(AAi2?;7I<B<nFQOhEmli7BK<?`xs<#vO%YR#$twr
zg?9D#f6chtnSXk4pwzDPT*>AJ`qyXa>DgJN;#=Wo{#16(-F~8u$PXj<I^5CU8b*E(
zN%{8ldPBz}mCXCz{kE>5%wK26lDiD|o>jdrt1Wu*1|xd03XGY+^=0n7X0+g~qWQaX
zUeR_^&pPyv7ejFD`<N*gn>4qiL&eT~O1{@gFmxb+a6h+Sici5$!b_24XGn6`SzqSh
z02nknGnmE-riF^=huAbGn;uHRGmS>g*v0vuprA1OOz!!A1YyC92oashW-|U2L`sU{
PZ~=(t3Ao+S>E(X|QTi=u

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/static/img/resourcegroup.png b/web/pgadmin/browser/server_groups/servers/resourcegroups/static/img/resourcegroup.png
new file mode 100644
index 0000000000000000000000000000000000000000..668089e80e8e05001aa5130a4578736fa97fbd2e
GIT binary patch
literal 966
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F
z14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yv9FfgtP@CkAK|Np<+g3sQ|
zetRzmqQ9Ptf4I$m=RWs=>#RG@GwyiIyyiFOtiz1w`puV=iw~(6?Nlq;;lA**X60e`
zg<oCgfAU)L%XZ>fv-X1~&0D>ed^2rc<-O>(+x(~cjb{v6&KWdc)UG?DS$)!R)*GNL
zCLLD|n$PJqUeIqisa>&U=IQ_IuKrzj_5a!{|L2|kpS=0M>-5XFLilb)Gd_srydS}R
zH&FP>%m24t|G)J7|H2FZeOCOp?K|@*iT!__%-=5Ezpa`N;#h9H`tLIDqeaJwXKC#J
z8|D7Dsr>EIyC2W8_`-juIqytbPd|$1{9mH*zg6RJt-*sh);VYX*B|(AJN21q`?;H8
z3U@-p9z;ppi4eRL&f>A?n_2H&!?tTi?KccsF1yS;=P>1(LG@0Z;`Lg^Tl6co0X^$5
z^R?5gXI@KwM6UZEu<AcB+*V%xzwz4NwO9Vmzwjn(^;2LNPCNB~^_9P?ul&FI^8b~W
zf0teS<viy#FsxQy{(Irs->WZwUwZy)-L-GGUjH@gy<<1+`NnI%=bZU#+<wt|^5f-~
z{;$9GapSfB(@y<0?YLw!<?+TFpXOb71dJvhAEoWU7}hKa@(X5o{~Z@Vk$HdQiP;9A
zCdMRhcNc~ZR#^`qhqJ&VvY3HEPZ@+6E0)@q0R<m<x;TbNTux3nz|iA!Mn^|yP0kyc
zIWc#792nJnb#rB7ZEKmGm6L_#7BF=8t(>{Db?MZty=&*%>U%hxK6B;Zp^GPP9=&>Y
zF2Blx+;<7D9=?3~_VMfI=lO*$T)D!_!NbMJ$;;g@z`(`f=H`0b<@m9q>MClg+>ER(
z!8XCcwwEs%8wGFDadn7d+EiTh`4cx+_m*y37sa+|Q>IM~4+#ssex-|%b;j1$Ua~r`
zq)TMH&PW|~WU^XXy3F^i?%HRiOLK)B7(IR09{bjJPOp2;yIXRa3mUfcteLZ?Y0;!j
zU8`p8Vq5l{ai*Eko>+r<5<uUombgZgq$HN4S|t~y0x1R~149#C19M#i(-1>rD+3cN
z19NQ<X;2y>*NLJbH$NpatrDuiOxMUV#L&db#K_9f6r#bpq!1Ly44$rjF6*2UngA`s
B)usRd

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/js/resourcegroup.js b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/js/resourcegroup.js
new file mode 100644
index 0000000..860cdc1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/js/resourcegroup.js
@@ -0,0 +1,95 @@
+define(
+  ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+  function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+  if (!pgBrowser.Nodes['coll-resourcegroup']) {
+    var resourcegroups = pgAdmin.Browser.Nodes['coll-resourcegroup'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'resourcegroup',
+        label: '{{ _('Resource Groups') }}',
+        type: 'coll-resourcegroup',
+        columns: ['name']
+    });
+  };
+
+  if (!pgBrowser.Nodes['resourcegroup']) {
+    pgAdmin.Browser.Nodes['resourcegroup'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'server',
+      type: 'resourcegroup',
+      label: '{{ _('resourcegroup') }}',
+      hasSQL:  true,
+      canDrop: true,
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+          return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'create_resourcegroup_on_coll', node: 'coll-resourcegroup', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Resource Group...') }}',
+          icon: 'wcTabIcon pg-icon-resourcegroup', data: {action: 'create'}
+        },{
+          name: 'create_resourcegroup', node: 'resourcegroup', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Resource Group...') }}',
+          icon: 'wcTabIcon pg-icon-resourcegroup', data: {action: 'create'}
+        }
+        ]);
+      },
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          cpu_rate_limit: 0,
+          dirty_rate_limit: 0
+        },
+        schema: [{
+          id: 'name', label: '{{ _('Group Name') }}', cell: 'string',
+          type: 'text',
+        },{
+          id: 'cpu_rate_limit', label:'{{ _('CPU Rate Limit') }}', cell: 'string',
+          type: 'int'
+        },{
+          id: 'dirty_rate_limit', label:'{{ _('Dirty Rate Limit') }}', cell: 'string',
+          type: 'int'
+        }],
+        validate: function(keys) {
+          var name = this.get('name');
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Group Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+
+          var cpu_rate_limit = this.get('cpu_rate_limit');
+          if (_.isUndefined(cpu_rate_limit) || _.isNull(cpu_rate_limit) ||
+            String(cpu_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('CPU Rate Limit can not be empty!') }}';
+            this.errorModel.set('cpu_rate_limit', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('cpu_rate_limit');
+          }
+
+          var dirty_rate_limit = this.get('dirty_rate_limit');
+          if (_.isUndefined(dirty_rate_limit) || _.isNull(dirty_rate_limit) ||
+            String(dirty_rate_limit).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Dirty Rate Limit can not be empty!') }}';
+            this.errorModel.set('dirty_rate_limit', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('dirty_rate_limit');
+          }
+          return null;
+        }
+      })
+    })
+  }
+
+  return pgBrowser.Nodes['coll-resourcegroup'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/create.sql b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/create.sql
new file mode 100644
index 0000000..8054b84
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/create.sql
@@ -0,0 +1,14 @@
+{% if display_comments %}
+-- RESOURCE GROUP: {{rgname}}
+
+-- DROP RESOURCE GROUP {{ conn|qtIdent(rgname) }}
+
+{% endif %}
+{# ============= Create the resource group============= #}
+{% if rgname %}
+CREATE RESOURCE GROUP {{ conn|qtIdent(rgname) }};
+{% endif %}
+{# ============= Get the resource group oid ============= #}
+{% if getoid %}
+SELECT oid FROM edb_resource_group WHERE rgrpname = {{ rgname|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/delete.sql b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/delete.sql
new file mode 100644
index 0000000..9d9a00d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/delete.sql
@@ -0,0 +1,8 @@
+{# ============= Below SQL will get the resource group name using oid ============= #}
+{% if rgid %}
+SELECT rgrpname FROM edb_resource_group WHERE oid = {{rgid}}::int;
+{% endif %}
+{# ============= Below SQL will drop the resource group ============= #}
+{% if rgname %}
+DROP RESOURCE GROUP {{ conn|qtIdent(rgname) }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/getoid.sql b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/getoid.sql
new file mode 100644
index 0000000..ec44b42
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/getoid.sql
@@ -0,0 +1,4 @@
+{# ============= Get the resource group oid ============= #}
+{% if rgname %}
+SELECT oid FROM edb_resource_group WHERE rgrpname = {{ rgname|qtLiteral }};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/properties.sql
new file mode 100644
index 0000000..b0c068b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/properties.sql
@@ -0,0 +1,6 @@
+SELECT oid, rgrpname AS name, rgrpcpuratelimit AS cpu_rate_limit, rgrpdirtyratelimit AS dirty_rate_limit
+FROM edb_resource_group
+{% if rgid %}
+WHERE oid={{rgid}}::int
+{% endif %}
+ORDER BY rgrpname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/update.sql b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/update.sql
new file mode 100644
index 0000000..2b19e10
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/resourcegroups/templates/resourcegroups/sql/update.sql
@@ -0,0 +1,9 @@
+{# ============= Update resource group name ============= #}
+{% if newname %}
+ALTER RESOURCE GROUP {{ conn|qtIdent(oldname) }} RENAME TO {{ conn|qtIdent(newname) }};
+{% endif %}
+{# ============= Update resource group cpu_rate_limit and dirty_rate_limit ============= #}
+{% if data %}
+ALTER RESOURCE GROUP {{ conn|qtIdent(data.name) }}
+    SET cpu_rate_limit = {{data.cpu_rate_limit|default(0)}}, dirty_rate_limit = {{data.dirty_rate_limit|default(0)}};
+{% endif %}
\ No newline at end of file
