diff --git a/docs/en_US/backup_dialog.rst b/docs/en_US/backup_dialog.rst
index df80a942a..ed9c43a65 100644
--- a/docs/en_US/backup_dialog.rst
+++ b/docs/en_US/backup_dialog.rst
@@ -203,21 +203,6 @@ command:
 
 * Click the *Cancel* button to exit without saving work.
 
-.. image:: images/backup_messages.png
-    :alt: Backup success notification popup
-    :align: center
-
-Use the **Stop Process** button to stop the Backup process.
-
-If the backup is successful, a popup window will confirm success. Click *More details* on the popup window to launch the *Process Watcher*. The *Process Watcher* logs all the activity associated with the backup and provides additional information for troubleshooting.
-
-.. image:: images/backup_process_watcher.png
-    :alt:  Backup process watcher
-    :align: center
-
-If the backup is unsuccessful, you can review the error messages returned by the
-backup command on the *Process Watcher*.
-
-.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
-
-.. |sm_icon| image:: images/sm_icon.png
+pgAdmin will run the backup process in background. You can view all the background
+process with there running status and logs on the :ref:`Processes <processes>`
+tab
\ No newline at end of file
diff --git a/docs/en_US/backup_globals_dialog.rst b/docs/en_US/backup_globals_dialog.rst
index 32c8310fc..0c2e9cc78 100644
--- a/docs/en_US/backup_globals_dialog.rst
+++ b/docs/en_US/backup_globals_dialog.rst
@@ -34,24 +34,6 @@ statements that should be included in the backup.
 Click the *Backup* button to build and execute a command based on your
 selections; click the *Cancel* button to exit without saving work.
 
-.. image:: images/backup_globals_messages.png
-    :alt: Backup globals success notification popup
-    :align: center
-
-Use the **Stop Process** button to stop the Backup process.
-
-If the backup is successful, a popup window will confirm success. Click *Click
-here for details* on the popup window to launch the *Process Watcher*. The
-*Process Watcher* logs all the activity associated with the backup and provides
-additional information for troubleshooting.
-
-.. image:: images/backup_globals_process_watcher.png
-    :alt:  Backup globals process watcher
-    :align: center
-
-If the backup is unsuccessful, review the error message returned by the
-*Process Watcher* to resolve any issue.
-
-.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
-
-.. |sm_icon| image:: images/sm_icon.png
+pgAdmin will run the backup process in background. You can view all the background
+process with there running status and logs on the :ref:`Processes <processes>`
+tab
\ No newline at end of file
diff --git a/docs/en_US/backup_server_dialog.rst b/docs/en_US/backup_server_dialog.rst
index cc5234aa2..7761d8886 100644
--- a/docs/en_US/backup_server_dialog.rst
+++ b/docs/en_US/backup_server_dialog.rst
@@ -122,24 +122,6 @@ tab to provide options related to data or pgAdmin objects that correspond to *pg
 Click the *Backup* button to build and execute a command based on your
 selections; click the *Cancel* button to exit without saving work.
 
-.. image:: images/backup_server_messages.png
-    :alt: Backup server success notification popup
-    :align: center
-
-Use the **Stop Process** button to stop the Backup process.
-
-If the backup is successful, a popup window will confirm success. Click *Click
-here for details* on the popup window to launch the *Process Watcher*. The
-*Process Watcher* logs all the activity associated with the backup and provides
-additional information for troubleshooting.
-
-.. image:: images/backup_server_process_watcher.png
-    :alt:  Backup server process watcher
-    :align: center
-
-If the backup is unsuccessful, review the error message returned by the
-*Process Watcher* to resolve any issue.
-
-.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
-
-.. |sm_icon| image:: images/sm_icon.png
+pgAdmin will run the backup process in background. You can view all the background
+process with there running status and logs on the :ref:`Processes <processes>`
+tab
\ No newline at end of file
diff --git a/docs/en_US/cloud_aws_rds.rst b/docs/en_US/cloud_aws_rds.rst
index 3c32022ef..3f00c7159 100644
--- a/docs/en_US/cloud_aws_rds.rst
+++ b/docs/en_US/cloud_aws_rds.rst
@@ -89,5 +89,8 @@ button to deploy the instance on Amazon RDS.
 
 Once you click on the finish, one background process will start which will
 deploy the instance in the cloud and monitor the progress of the deployment.
+You can view all the background process with there running status and logs
+on the :ref:`Processes <processes>` tab
+
 The Server will be added to the tree with the cloud deployment icon. Once the
 deployment is done, the server details will be updated.
diff --git a/docs/en_US/cloud_azure_postgresql.rst b/docs/en_US/cloud_azure_postgresql.rst
index f90594308..ed734e667 100644
--- a/docs/en_US/cloud_azure_postgresql.rst
+++ b/docs/en_US/cloud_azure_postgresql.rst
@@ -107,6 +107,8 @@ button to deploy the instance on Azure PostgreSQL.
 
 Once you click on the finish, one background process will start which will
 deploy the instance in the cloud and monitor the progress of the deployment.
+You can view all the background process with there running status and logs
+on the :ref:`Processes <processes>` tab
 
 .. image:: images/cloud_azure_bg_process_watcher.png
     :alt: Cloud Deployment
diff --git a/docs/en_US/cloud_edb_biganimal.rst b/docs/en_US/cloud_edb_biganimal.rst
index 7103d4e61..ac79e57a1 100644
--- a/docs/en_US/cloud_edb_biganimal.rst
+++ b/docs/en_US/cloud_edb_biganimal.rst
@@ -87,5 +87,8 @@ button to deploy the instance on EDB BigAnimal.
 
 Once you click on the finish, one background process will start which will
 deploy the instance in the cloud and monitor the progress of the deployment.
+You can view all the background process with there running status and logs
+on the :ref:`Processes <processes>` tab
+
 The Server will be added to the tree with the cloud deployment icon. Once the
 deployment is done, the server details will be updated.
diff --git a/docs/en_US/images/backup_globals_messages.png b/docs/en_US/images/backup_globals_messages.png
deleted file mode 100644
index c56440e61f4e4053d4d1359ca52ebde6dfad48c5..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/backup_globals_process_watcher.png b/docs/en_US/images/backup_globals_process_watcher.png
deleted file mode 100644
index a5617a0ae35d7b1857f33eada85cc307de8baf87..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/backup_messages.png b/docs/en_US/images/backup_messages.png
deleted file mode 100644
index db85032f13ef0725418c0b9681291969f2ba34bd..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/backup_server_messages.png b/docs/en_US/images/backup_server_messages.png
deleted file mode 100644
index 0c8dcc6c2f5c833d731d32ab4335e44ae0f989d5..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/backup_server_process_watcher.png b/docs/en_US/images/backup_server_process_watcher.png
deleted file mode 100644
index 725a0062ef7d745b92f1a85390d6cfa0004d454b..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/maintenance_complete.png b/docs/en_US/images/maintenance_complete.png
deleted file mode 100644
index df32ee1eb5fd835771272db7bcaded4573f31198..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/maintenance_pw.png b/docs/en_US/images/maintenance_pw.png
deleted file mode 100644
index e487409548421ca7b8c9e44b93be5e2c950a8dba..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/processes_details.png b/docs/en_US/images/processes_details.png
new file mode 100644
index 0000000000000000000000000000000000000000..48ffc73e932ac8cd547f2cdb887609259e3e675b
GIT binary patch
diff --git a/docs/en_US/images/processes_main.png b/docs/en_US/images/processes_main.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d4ba2eed05f046eb9adf78f4b2b58593f62399f
GIT binary patch
diff --git a/docs/en_US/images/restore_messages.png b/docs/en_US/images/restore_messages.png
deleted file mode 100644
index fc98133756607398c58b01b502894e2ff2726795..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/restore_process_watcher.png b/docs/en_US/images/restore_process_watcher.png
deleted file mode 100644
index 95358cf591675c82199e844bacdcfbb7eddd5a47..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/sm_icon.png b/docs/en_US/images/sm_icon.png
index 13522104e7abefcb0da49be64bfac05dbe296721..9640d9dc6b129690258cb9bd8566920db4f9e6b5 100644
GIT binary patch
diff --git a/docs/en_US/index.rst b/docs/en_US/index.rst
index c43ab5b85..0bc680f0d 100644
--- a/docs/en_US/index.rst
+++ b/docs/en_US/index.rst
@@ -23,6 +23,7 @@ of database objects.
    management_basics
    backup_and_restore
    developer_tools
+   processes
    pgagent
    contributions
    release_notes
diff --git a/docs/en_US/maintenance_dialog.rst b/docs/en_US/maintenance_dialog.rst
index 1f7ddc2b4..de446d128 100644
--- a/docs/en_US/maintenance_dialog.rst
+++ b/docs/en_US/maintenance_dialog.rst
@@ -45,18 +45,6 @@ switch to the *No* position; by default, status messages are included.
 When you've completed the dialog, click *OK* to start the background process;
 to exit the dialog without performing maintenance operations, click *Cancel*.
 
-pgAdmin will inform you when the background process completes:
-
-.. image:: images/maintenance_complete.png
-    :alt: Maintenance completion notification
-    :align: center
-
-Use the **Stop Process** button to stop the Maintenance process.
-
-Use the *Click here for details* link on the notification to open the *Process
-Watcher* and review detailed information about the execution of the command that
-performed the import or export:
-
-.. image:: images/maintenance_pw.png
-    :alt: Maintenance process watcher
-    :align: center
+pgAdmin will run the maintenance process in background. You can view all the background
+process with there running status and logs on the :ref:`Processes <processes>`
+tab
\ No newline at end of file
diff --git a/docs/en_US/processes.rst b/docs/en_US/processes.rst
new file mode 100644
index 000000000..8baf5925a
--- /dev/null
+++ b/docs/en_US/processes.rst
@@ -0,0 +1,49 @@
+.. _processes:
+
+***********************
+`Processes`:index:
+***********************
+
+There are certain tasks which pgAdmin runs in the background. The processes
+running in the background can be viewed in the processes tab. It shows the
+process details of Backup, Restore, Maintenance, Import/Export and Cloud instance
+creation.
+
+.. image:: images/processes_main.png
+    :alt: Processes Tab
+    :align: center
+
+The columns of the processes table shows:
+
+* The *PID* of the forked OS process.
+* The *Type* of the task being performed.
+* The *Server* name for which the task is.
+* The *Object* can be a database, table, mview or anything which gives more info.
+* The *Start Time* of the process, sorted descending by default.
+* The current *Status* of the process. It can be Running, Finished, Failed, Terminated.
+* The *Time Taken* to complete. It will keep updating if it is running.
+
+There are two action buttons on each row:
+
+* The *Stop Process* button allows you to kill a running process.
+* The *More details* button allows you to open the process watcher which shows the
+  process logs and other details.
+
+You can also select the checkboxes and click on *Delete and Acknowledge* button
+on the top to clear the process info and logs.
+
+Process Watcher
+*********************
+
+.. image:: images/processes_details.png
+    :alt: Process Watcher
+    :align: center
+
+
+The Process Watcher logs all the activity associated with the process/task and provides
+additional information for troubleshooting
+Use the **Stop Process** button to stop the Backup process.
+
+.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
+
+.. |sm_icon| image:: images/sm_icon.png
\ No newline at end of file
diff --git a/docs/en_US/restore_dialog.rst b/docs/en_US/restore_dialog.rst
index 02468a082..c2f72c23e 100644
--- a/docs/en_US/restore_dialog.rst
+++ b/docs/en_US/restore_dialog.rst
@@ -143,17 +143,6 @@ command, click the *Restore* button to start the process, or click the *Cancel*
 button to exit without saving your work. A popup will confirm if the restore is
 successful.
 
-.. image:: images/restore_messages.png
-    :alt: Restore dialog notifications
-    :align: center
-
-Use the **Stop Process** button to stop the Restore process.
-
-Click *Click here for details* on the popup to launch the *Process Watcher*. The
-*Process Watcher* logs all the activity associated with the restore, and
-provides additional information for troubleshooting should the restore command
-encounter problems.
-
-.. image:: images/restore_process_watcher.png
-    :alt: Restore dialog process watcher
-    :align: center
+pgAdmin will run the restore process in background. You can view all the background
+process with there running status and logs on the :ref:`Processes <processes>`
+tab
\ No newline at end of file
diff --git a/web/pgadmin/browser/register_browser_preferences.py b/web/pgadmin/browser/register_browser_preferences.py
index 169f506ba..86eae07b1 100644
--- a/web/pgadmin/browser/register_browser_preferences.py
+++ b/web/pgadmin/browser/register_browser_preferences.py
@@ -130,6 +130,16 @@ def register_browser_preferences(self):
         )
     )
 
+    self.table_row_count_threshold = self.preference.register(
+        'processes', 'process_retain_days',
+        gettext("Process details/logs retention days"), 'integer', 5,
+        category_label=gettext('Processes'),
+        help_str=gettext(
+            'After this many days, the process info and logs '
+            'will be automatically cleared.'
+        )
+    )
+
     fields = [
         {'name': 'key', 'type': 'keyCode', 'label': gettext('Key')},
         {'name': 'shift', 'type': 'checkbox', 'label': gettext('Shift')},
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
index 7fd1a660b..7bb2ee411 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py
@@ -29,7 +29,7 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
 from pgadmin.utils.driver import get_driver
 from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
 from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
-from pgadmin.utils import html, does_utility_exist
+from pgadmin.utils import html, does_utility_exist, get_server
 from pgadmin.model import Server
 from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
 
@@ -158,23 +158,7 @@ class Message(IProcessDesc):
 
     @property
     def message(self):
-        res = gettext("Refresh Materialized View")
-        opts = []
-        if not self.data['is_with_data']:
-            opts.append(gettext("With no data"))
-        else:
-            opts.append(gettext("With data"))
-        if self.data['is_concurrent']:
-            opts.append(gettext("Concurrently"))
-
-        return res + " ({0})".format(', '.join(str(x) for x in opts))
-
-    @property
-    def type_desc(self):
-        return gettext("Refresh Materialized View")
-
-    def details(self, cmd, args):
-        res = gettext("Refresh Materialized View ({0})")
+        msg = gettext("Refresh Materialized View ({0})")
         opts = []
         if not self.data['is_with_data']:
             opts.append(gettext("WITH NO DATA"))
@@ -184,17 +168,30 @@ class Message(IProcessDesc):
         if self.data['is_concurrent']:
             opts.append(gettext("CONCURRENTLY"))
 
-        res = res.format(', '.join(str(x) for x in opts))
+        msg = msg.format(', '.join(str(x) for x in opts))
+        return msg
+
+    @property
+    def type_desc(self):
+        return gettext("Refresh Materialized View")
 
-        res = '<div>' + html.safe_str(res)
+    def get_server_name(self):
+        # Fetch the server details like hostname, port, roles etc
+        s = get_server(self.sid)
 
-        res += '</div><div class="py-1">'
-        res += gettext("Running Query:")
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(self.query)
-        res += '</div></div>'
+        if s is None:
+            return gettext("Not available")
+        return html.safe_str("{0} ({1}:{2})".format(s.name, s.host, s.port))
 
-        return res
+    def details(self, cmd, args):
+        return {
+            "message": self.message,
+            "query": self.query,
+            "server": self.get_server_name(),
+            "object": "{0}/{1}".format(
+                self.data['database'], self.data.get('object', 'Unknown')),
+            "type": gettext("Refresh MView")
+        }
 
 
 class MViewModule(ViewModule):
@@ -2193,6 +2190,8 @@ class MViewNode(ViewNode, VacuumSettings):
                 is_concurrent=is_concurrent,
                 with_data=with_data
             )
+            data['object'] = "{0}.{1}".format(res['rows'][0]['schema'],
+                                              res['rows'][0]['name'])
 
             # Fetch the server details like hostname, port, roles etc
             server = Server.query.filter_by(
@@ -2273,6 +2272,7 @@ class MViewNode(ViewNode, VacuumSettings):
             return make_json_response(
                 data={
                     'job_id': jid,
+                    'desc': p.desc.message,
                     'status': True,
                     'info': gettext(
                         'Materialized view refresh job created.')
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js
index b9a86008d..b598d58b0 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.js
@@ -203,9 +203,8 @@ define('pgadmin.node.mview', [
           })
             .done(function(refreshed_res) {
               if (refreshed_res.data && refreshed_res.data.status) {
-              //Do nothing as we are creating the job and exiting from the main dialog
-                Notify.success(refreshed_res.data.info);
-                pgBrowser.Events.trigger('pgadmin-bgprocess:created');
+                //Do nothing as we are creating the job and exiting from the main dialog
+                pgBrowser.BgProcessManager.startProcess(refreshed_res.data.job_id, refreshed_res.data.desc);
               } else {
                 Notify.alert(
                   gettext('Failed to create materialized view refresh job.'),
diff --git a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js
index f405c170d..0cb80fe18 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/static/js/database.js
@@ -240,7 +240,7 @@ define('pgadmin.node.database', [
                       if(res.data.info_prefix) {
                         res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`;
                       }
-                      Notify.success(_.unescape(res.info));
+                      Notify.success(res.info);
                       t.removeIcon(i);
                       data.connected = false;
                       data.icon = data.isTemplate ? 'icon-database-template-not-connected':'icon-database-not-connected';
@@ -437,7 +437,7 @@ define('pgadmin.node.database', [
                 res.info = gettext('Database already connected.');
               }
               if(res.data.info_prefix) {
-                res.info = `${res.data.info_prefix} - ${res.info}`;
+                res.info = `${_.escape(res.data.info_prefix)} - ${res.info}`;
               }
               if(res.data.already_connected) {
                 Notify.info(res.info);
diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js
index 21ad46732..f733d26a5 100644
--- a/web/pgadmin/browser/server_groups/servers/static/js/server.js
+++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js
@@ -629,7 +629,7 @@ define('pgadmin.node.server', [
 
     var connect_to_server = function(obj, data, tree, item, reconnect) {
     // Open properties dialog in edit mode
-      var server_url = obj.generate_url(item, 'obj', data, true);
+      let server_url = obj.generate_url(item, 'obj', data, true);
       // Fetch the updated data
       $.get(server_url)
         .done(function(res) {
@@ -651,20 +651,7 @@ define('pgadmin.node.server', [
             }
           }
           else if (res.cloud_status == -1) {
-            $.ajax({
-              type: 'GET',
-              timeout: 30000,
-              url: url_for('cloud.update_cloud_process', {'sid': res.id}),
-              cache: false,
-              async: true,
-              contentType: 'application/json',
-            })
-              .done(function() {
-                pgAdmin.Browser.BackgroundProcessObsorver.update_process_list();
-              })
-              .fail(function() {
-                console.warn(arguments);
-              });
+            pgAdmin.Browser.BgProcessManager.recheckCloudServer(data._id);
           }
           return;
         }).always(function(){
diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js
index 4ab8b1b00..3c4207f2a 100644
--- a/web/pgadmin/browser/static/js/browser.js
+++ b/web/pgadmin/browser/static/js/browser.js
@@ -266,6 +266,19 @@ define('pgadmin.browser', [
         content: '<div class="negative-space p-2"><div role="status" class="pg-panel-message pg-panel-depends-message">' + select_object_msg + '</div><div class="pg-panel-dependents-container d-none"></div></div>',
         events: panelEvents,
       }),
+      // Background processes
+      'processes': new pgAdmin.Browser.Panel({
+        name: 'processes',
+        title: gettext('Processes'),
+        icon: '',
+        width: 500,
+        isCloseable: true,
+        isPrivate: false,
+        limit: 1,
+        canHide: true,
+        content: '<div class="negative-space p-2"><div class="pg-panel-processes-container d-none"></div></div>',
+        events: panelEvents,
+      }),
     },
     // We also support showing dashboards, HTML file, external URL
     frames: {},
diff --git a/web/pgadmin/browser/static/js/layout.js b/web/pgadmin/browser/static/js/layout.js
index 689028f3d..fff14e7ba 100644
--- a/web/pgadmin/browser/static/js/layout.js
+++ b/web/pgadmin/browser/static/js/layout.js
@@ -42,6 +42,8 @@ _.extend(pgBrowser, {
       'dependencies', wcDocker.DOCK.STACKED, dashboardPanel);
     docker.addPanel(
       'dependents', wcDocker.DOCK.STACKED, dashboardPanel);
+    docker.addPanel(
+      'processes', wcDocker.DOCK.STACKED, dashboardPanel);
   },
 
   save_current_layout: function(layout_id, docker) {
diff --git a/web/pgadmin/browser/static/js/panel.js b/web/pgadmin/browser/static/js/panel.js
index 8f1d1b7ab..8f49a6745 100644
--- a/web/pgadmin/browser/static/js/panel.js
+++ b/web/pgadmin/browser/static/js/panel.js
@@ -122,7 +122,7 @@ define(
                 that.resizedContainer.apply(myPanel);
               }
 
-              if (myPanel._type == 'dashboard') {
+              if (myPanel._type == 'dashboard' || myPanel._type == 'processes') {
                 getPanelView(
                   pgBrowser.tree,
                   $container[0],
@@ -263,8 +263,8 @@ define(
           .scene()
           .find('.pg-panel-content');
 
-        if (isPanelVisible && selectedPanel._type !== 'properties') {
-          if (eventName == 'panelVisibilityChanged' && selectedPanel._type !== 'properties') {
+        if (isPanelVisible && ['dashboard', 'statistics', 'dependencies', 'dependents', 'sql', 'processes'].includes(selectedPanel._type) ) {
+          if (eventName == 'panelVisibilityChanged') {
             getPanelView(
               pgBrowser.tree,
               $container[0],
diff --git a/web/pgadmin/browser/static/js/panel_view.jsx b/web/pgadmin/browser/static/js/panel_view.jsx
index 8302af60a..c1274b840 100644
--- a/web/pgadmin/browser/static/js/panel_view.jsx
+++ b/web/pgadmin/browser/static/js/panel_view.jsx
@@ -17,6 +17,7 @@ import SQL from '../../../misc/sql/static/js/SQL';
 import Dashboard from '../../../dashboard/static/js/Dashboard';
 import _ from 'lodash';
 import { CollectionNodeView } from '../../../misc/properties/CollectionNodeProperties';
+import Processes from '../../../misc/bgprocess/static/js/Processes';
 
 
 /* The entry point for rendering React based view in properties, called in node.js */
@@ -131,6 +132,14 @@ export function getPanelView(
       container
     );
   }
+  if (panelType == 'processes') {
+    ReactDOM.render(
+      <Theme>
+        <Processes />
+      </Theme>,
+      container
+    );
+  }
 }
 
 /* When switching from normal node to collection node, clean up the React mounted DOM */
diff --git a/web/pgadmin/dashboard/static/js/Dashboard.jsx b/web/pgadmin/dashboard/static/js/Dashboard.jsx
index 31f6cd0e0..c8f5b0f04 100644
--- a/web/pgadmin/dashboard/static/js/Dashboard.jsx
+++ b/web/pgadmin/dashboard/static/js/Dashboard.jsx
@@ -143,7 +143,7 @@ export default function Dashboard({
     {
       accessor: 'name',
       Header: gettext('Name'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -153,7 +153,7 @@ export default function Dashboard({
     {
       accessor: 'category',
       Header: gettext('Category'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -161,7 +161,7 @@ export default function Dashboard({
     {
       accessor: 'setting',
       Header: gettext('Value'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -170,7 +170,7 @@ export default function Dashboard({
     {
       accessor: 'unit',
       Header: gettext('Unit'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -179,7 +179,7 @@ export default function Dashboard({
     {
       accessor: 'short_desc',
       Header: gettext('Description'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
@@ -189,7 +189,7 @@ export default function Dashboard({
     {
       accessor: 'terminate_query',
       Header: () => null,
-      sortble: true,
+      sortable: true,
       resizable: false,
       disableGlobalFilter: false,
       width: 35,
@@ -261,7 +261,7 @@ export default function Dashboard({
     {
       accessor: 'cancel_Query',
       Header: () => null,
-      sortble: true,
+      sortable: true,
       resizable: false,
       disableGlobalFilter: false,
       width: 35,
@@ -330,7 +330,7 @@ export default function Dashboard({
     {
       accessor: 'view_active_query',
       Header: () => null,
-      sortble: true,
+      sortable: true,
       resizable: false,
       disableGlobalFilter: false,
       width: 35,
@@ -374,7 +374,7 @@ export default function Dashboard({
     {
       accessor: 'pid',
       Header: gettext('PID'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -383,7 +383,7 @@ export default function Dashboard({
     {
       accessor: 'datname',
       Header: gettext('Database'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -393,7 +393,7 @@ export default function Dashboard({
     {
       accessor: 'usename',
       Header: gettext('User'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -402,7 +402,7 @@ export default function Dashboard({
     {
       accessor: 'application_name',
       Header: gettext('Application'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -410,7 +410,7 @@ export default function Dashboard({
     {
       accessor: 'client_addr',
       Header: gettext('Client'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -418,7 +418,7 @@ export default function Dashboard({
     {
       accessor: 'backend_start',
       Header: gettext('Backend start'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 100,
@@ -426,7 +426,7 @@ export default function Dashboard({
     {
       accessor: 'xact_start',
       Header: gettext('Transaction start'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -434,7 +434,7 @@ export default function Dashboard({
     {
       accessor: 'state',
       Header: gettext('State'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -444,7 +444,7 @@ export default function Dashboard({
     {
       accessor: 'waiting',
       Header: gettext('Waiting'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       isVisible: treeNodeInfo?.server?.version < 90600
@@ -452,14 +452,14 @@ export default function Dashboard({
     {
       accessor: 'wait_event',
       Header: gettext('Wait event'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       accessor: 'blocking_pids',
       Header: gettext('Blocking PIDs'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
@@ -469,7 +469,7 @@ export default function Dashboard({
     {
       accessor: 'pid',
       Header: gettext('PID'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -478,7 +478,7 @@ export default function Dashboard({
     {
       accessor: 'datname',
       Header: gettext('Database'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -488,7 +488,7 @@ export default function Dashboard({
     {
       accessor: 'locktype',
       Header: gettext('Lock type'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -497,14 +497,14 @@ export default function Dashboard({
     {
       accessor: 'relation',
       Header: gettext('Target relation'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       accessor: 'page',
       Header: gettext('Page'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -513,7 +513,7 @@ export default function Dashboard({
     {
       accessor: 'tuple',
       Header: gettext('Tuple'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -521,7 +521,7 @@ export default function Dashboard({
     {
       accessor: 'virtualxid',
       Header: gettext('vXID (target)'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -530,7 +530,7 @@ export default function Dashboard({
     {
       accessor: 'transactionid',
       Header: gettext('XID (target)'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -539,7 +539,7 @@ export default function Dashboard({
     {
       accessor: 'classid',
       Header: gettext('Class'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -548,7 +548,7 @@ export default function Dashboard({
     {
       accessor: 'objid',
       Header: gettext('Object ID'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -558,7 +558,7 @@ export default function Dashboard({
     {
       accessor: 'virtualtransaction',
       Header: gettext('vXID (owner)'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 50,
@@ -566,7 +566,7 @@ export default function Dashboard({
     {
       accessor: 'mode',
       Header: gettext('Mode'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
@@ -574,7 +574,7 @@ export default function Dashboard({
       id: 'granted',
       accessor: 'granted',
       Header: gettext('Granted?'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 30,
@@ -587,14 +587,14 @@ export default function Dashboard({
     {
       accessor: 'git',
       Header: gettext('Name'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       accessor: 'datname',
       Header: gettext('Database'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 26,
@@ -604,21 +604,21 @@ export default function Dashboard({
     {
       accessor: 'Owner',
       Header: gettext('Owner'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       accessor: 'transaction',
       Header: gettext('XID'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       accessor: 'prepared',
       Header: gettext('Prepared at'),
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
diff --git a/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py b/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py
index 474645940..75800e277 100644
--- a/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py
+++ b/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py
@@ -61,7 +61,6 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
         if not db_id:
             self.assertTrue(False, "Database {} is not "
                                    "created".format(self.database_name))
-        test_gui_helper.close_bgprocess_popup(self)
         self.page.add_server(self.server)
 
         self.wait = WebDriverWait(self.page.driver, 20)
@@ -74,36 +73,23 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
         # Backup
         self.initiate_backup()
 
-        # Wait for the backup status alertfier
-        self.wait.until(EC.visibility_of_element_located(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.bcg_process_status_alertifier_css)))
-
-        status = test_utils.get_watcher_dialogue_status(self)
-
-        self.page.retry_click(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.status_alertifier_more_btn_css),
-            (By.XPATH,
-             NavMenuLocators.process_watcher_alertfier))
-        self.page.wait_for_element_to_disappear(
-            lambda driver: driver.find_element(
-                By.CSS_SELECTOR, ".loading-logs"), 15)
-
-        expected_backup_success_msg = "Successfully completed."
-        self.assertEqual(status, expected_backup_success_msg)
+        test_gui_helper.wait_for_process_start(self)
+        test_gui_helper.open_process_details(self)
 
         backup_file = None
         # Check for XSS in Backup details
         if self.is_xss_check:
             self._check_detailed_window_for_xss('Backup')
         else:
+            message = self.page.find_by_css_selector(
+                NavMenuLocators.process_watcher_detailed_message_css). \
+                text
             command = self.page.find_by_css_selector(
-                NavMenuLocators.process_watcher_detailed_command_canvas_css). \
+                NavMenuLocators.process_watcher_detailed_command_css). \
                 text
 
-            self.assertIn(self.server['name'], str(command))
-            self.assertIn("from database 'pg_utility_test_db'", str(command))
+            self.assertIn(self.server['name'], str(message))
+            self.assertIn("from database 'pg_utility_test_db'", str(message))
 
             # On windows a modified path may be shown so skip this test
             if os.name != 'nt':
@@ -120,32 +106,21 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
         # Restore
         self.initiate_restore()
 
-        # Wait for the backup status alertfier
-        self.wait.until(EC.visibility_of_element_located(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.bcg_process_status_alertifier_css)))
-
-        status = test_utils.get_watcher_dialogue_status(self)
-
-        self.page.retry_click(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.status_alertifier_more_btn_css),
-            (By.XPATH,
-             NavMenuLocators.process_watcher_alertfier))
-        self.page.wait_for_element_to_disappear(
-            lambda driver: driver.find_element(
-                By.CSS_SELECTOR, ".loading-logs"), 10)
-        self.assertEqual(status, expected_backup_success_msg)
+        test_gui_helper.wait_for_process_start(self)
+        test_gui_helper.open_process_details(self)
 
         # Check for XSS in Restore details
         if self.is_xss_check:
             self._check_detailed_window_for_xss('Restore')
         else:
+            message = self.page.find_by_css_selector(
+                NavMenuLocators.process_watcher_detailed_message_css). \
+                text
             command = self.page.find_by_css_selector(
-                NavMenuLocators.process_watcher_detailed_command_canvas_css). \
+                NavMenuLocators.process_watcher_detailed_command_css). \
                 text
 
-            self.assertIn(self.server['name'], str(command))
+            self.assertIn(self.server['name'], str(message))
             if os.name != 'nt':
                 self.assertIn("test_backup", str(command))
 
@@ -158,8 +133,6 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
 
     def after(self):
         try:
-            test_gui_helper.close_process_watcher(self)
-            test_gui_helper.close_bgprocess_popup(self)
             self.page.remove_server(self.server)
         except Exception:
             print("PGUtilitiesBackupFeatureTest - "
@@ -177,7 +150,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
 
     def _check_detailed_window_for_xss(self, tool_name):
         source_code = self.page.find_by_css_selector(
-            NavMenuLocators.process_watcher_detailed_command_canvas_css
+            NavMenuLocators.process_watcher_detailed_command_css
         ).get_attribute('innerHTML')
         self._check_escaped_characters(
             source_code,
diff --git a/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py b/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py
index 6f40fbc8a..ec3afa50d 100644
--- a/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py
+++ b/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py
@@ -9,6 +9,7 @@
 
 import random
 import os
+import time
 
 from selenium.webdriver.support.ui import WebDriverWait
 from selenium.webdriver.support import expected_conditions as EC
@@ -73,7 +74,6 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
         test_utils.create_database(self.server, self.database_name)
         test_utils.create_table(self.server, self.database_name,
                                 self.table_name)
-        test_gui_helper.close_bgprocess_popup(self)
         self.page.add_server(self.server)
         self.wait = WebDriverWait(self.page.driver, 20)
 
@@ -84,10 +84,8 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
             lambda driver: driver.find_element(
                 By.XPATH, NavMenuLocators.maintenance_operation), 10)
 
-        # Wait for the backup status alertfier
-        self.wait.until(EC.visibility_of_element_located(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.bcg_process_status_alertifier_css)))
+        # Wait for the backup started alert
+        test_gui_helper.wait_for_process_start()
         self.verify_command()
 
     def _open_maintenance_dialogue(self):
@@ -122,35 +120,24 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
             NavMenuLocators.maintenance_operation, 10)
 
     def verify_command(self):
-        status = test_utils.get_watcher_dialogue_status(self)
-        self.page.retry_click(
-            (By.CSS_SELECTOR,
-             NavMenuLocators.status_alertifier_more_btn_css),
-            (By.XPATH,
-             NavMenuLocators.process_watcher_alertfier))
-        self.page.wait_for_element_to_disappear(
-            lambda driver: driver.find_element(
-                By.CSS_SELECTOR, ".loading-logs"))
-
-        if status != "Successfully completed.":
-            self.assertEqual(status, "Successfully completed.")
+        test_gui_helper.open_process_details()
 
+        message = self.page.find_by_css_selector(
+            NavMenuLocators.process_watcher_detailed_message_css).text
         command = self.page.find_by_css_selector(
-            NavMenuLocators.
-            process_watcher_detailed_command_canvas_css).text
+            NavMenuLocators.process_watcher_detailed_command_css).text
 
         vacuum_details = \
             "VACUUM (VERBOSE) on database '{0}' of server " \
             "{1} ({2}:{3})".format(self.database_name, self.server['name'],
                                    self.server['host'], self.server['port'])
         if self.test_level == 'database':
-            self.assertEqual(
-                command, vacuum_details + "\nRunning Query:\nVACUUM VERBOSE;")
+            self.assertEqual(message, vacuum_details)
+            self.assertEqual(command, "VACUUM VERBOSE;")
         elif self.is_xss_check and self.test_level == 'table':
             # Check for XSS in the dialog
             source_code = self.page.find_by_css_selector(
-                NavMenuLocators.
-                process_watcher_detailed_command_canvas_css
+                NavMenuLocators.process_watcher_detailed_command_css
             ).get_attribute('innerHTML')
             self.check_escaped_characters(
                 source_code,
@@ -158,15 +145,14 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
                 'Maintenance detailed window'
             )
         else:
-            self.assertEqual(
-                command, vacuum_details + "\nRunning Query:\nVACUUM VERBOSE"
-                                          " public." + self.table_name + ";")
+            self.assertEqual(message, vacuum_details)
+            self.assertEqual(command, "VACUUM VERBOSE"
+                                      " public." + self.table_name + ";")
 
         test_gui_helper.close_process_watcher(self)
 
     def after(self):
         try:
-            test_gui_helper.close_bgprocess_popup(self)
             test_utils.delete_table(self.server, self.database_name,
                                     self.table_name)
             self.page.remove_server(self.server)
diff --git a/web/pgadmin/misc/bgprocess/__init__.py b/web/pgadmin/misc/bgprocess/__init__.py
index e3bd8cbf4..675d3fe55 100644
--- a/web/pgadmin/misc/bgprocess/__init__.py
+++ b/web/pgadmin/misc/bgprocess/__init__.py
@@ -39,7 +39,7 @@ class BGProcessModule(PgAdminModule):
         return [
             'bgprocess.status', 'bgprocess.detailed_status',
             'bgprocess.acknowledge', 'bgprocess.list',
-            'bgprocess.stop_process'
+            'bgprocess.stop_process', 'bgprocess.update_cloud_details',
         ]
 
 
@@ -88,6 +88,26 @@ def acknowledge(pid):
     """
     User has acknowledge the process
 
+    Args:
+        pid:  Process ID
+
+    Returns:
+        Positive status
+    """
+    try:
+        BatchProcess.acknowledge(pid)
+        return success_return()
+    except LookupError as lerr:
+        return gone(errormsg=str(lerr))
+
+
+@blueprint.route('/update_cloud_details/<pid>', methods=['PUT'],
+                 endpoint='update_cloud_details')
+@login_required
+def update_cloud_details(pid):
+    """
+    Update the cloud details and get instance details
+
     Args:
         pid:  Process ID
 
@@ -96,7 +116,7 @@ def acknowledge(pid):
     """
     try:
         process = BatchProcess(id=pid)
-        status, server = process.acknowledge(pid)
+        status, server = process.update_cloud_details()
         if status and len(server) > 0:
             return make_json_response(
                 success=1,
diff --git a/web/pgadmin/misc/bgprocess/processes.py b/web/pgadmin/misc/bgprocess/processes.py
index 2510cc29d..b5ad4680a 100644
--- a/web/pgadmin/misc/bgprocess/processes.py
+++ b/web/pgadmin/misc/bgprocess/processes.py
@@ -16,17 +16,19 @@ import os
 import sys
 import psutil
 from abc import ABCMeta, abstractproperty, abstractmethod
-from datetime import datetime
+from datetime import datetime, timedelta
 from pickle import dumps, loads
 from subprocess import Popen, PIPE
 import logging
 import json
+import shutil
 
 from pgadmin.utils import u_encode, file_quote, fs_encoding, \
     get_complete_file_path, get_storage_directory, IS_WIN
 from pgadmin.browser.server_groups.servers.utils import does_server_exists
 from pgadmin.utils.constants import KERBEROS
 from pgadmin.utils.locker import ConnectionLocker
+from pgadmin.utils.preferences import Preferences
 
 import pytz
 from dateutil import parser
@@ -463,8 +465,9 @@ class BatchProcess(object):
         idx = 0
         c = re.compile(r"(\d+),(.*$)")
 
+        # If file is not present then
         if not os.path.isfile(logfile):
-            return 0, False
+            return 0, True
 
         with open(logfile, 'rb') as f:
             eofs = os.fstat(f.fileno()).st_size
@@ -496,10 +499,20 @@ class BatchProcess(object):
 
         return pos, completed
 
-    def _get_cloud_instance_details(self, _process):
+    def update_cloud_details(self):
         """
         Parse the output to get the cloud instance details
         """
+        _server = {}
+        _pid = self.id
+
+        _process = Process.query.filter_by(
+            user_id=current_user.id, pid=_pid
+        ).first()
+
+        if _process is None:
+            raise LookupError(PROCESS_NOT_FOUND)
+
         ctime = get_current_time(format='%y%m%d%H%M%S%f')
         stdout = []
         stderr = []
@@ -507,7 +520,6 @@ class BatchProcess(object):
         err = 0
         cloud_server_id = 0
         cloud_instance = ''
-        pid = self.id
 
         enc = sys.getdefaultencoding()
         if enc == 'ascii':
@@ -527,20 +539,20 @@ class BatchProcess(object):
                     cloud_instance = json.loads(value[1])
                     cloud_server_id = _process.server_id
 
-                if type(cloud_instance) is dict and\
+                if type(cloud_instance) is dict and \
                         'instance' in cloud_instance:
                     cloud_instance['instance']['sid'] = cloud_server_id
                     cloud_instance['instance']['status'] = True
-                    cloud_instance['instance']['pid'] = pid
+                    cloud_instance['instance']['pid'] = _pid
                     return update_server(cloud_instance)
         elif err_completed and _process.exit_code > 0:
             cloud_instance = {'instance': {}}
             cloud_instance['instance']['sid'] = _process.server_id
             cloud_instance['instance']['status'] = False
-            cloud_instance['instance']['pid'] = pid
+            cloud_instance['instance']['pid'] = _pid
             return update_server(cloud_instance)
         else:
-            clear_cloud_session(pid)
+            clear_cloud_session(_pid)
         return True, {}
 
     def status(self, out=0, err=0):
@@ -695,8 +707,23 @@ class BatchProcess(object):
         processes = Process.query.filter_by(user_id=current_user.id)
         changed = False
 
+        browser_preference = Preferences.module('browser')
+        expiry_add = timedelta(
+            browser_preference.preference('process_retain_days').get() or 1
+        )
+
         res = []
-        for p in processes:
+        for p in [*processes]:
+            if p.start_time is not None:
+                # remove expired jobs
+                process_expiration_time = \
+                    parser.parse(p.start_time) + expiry_add
+                if datetime.now(process_expiration_time.tzinfo) >= \
+                        process_expiration_time:
+                    shutil.rmtree(p.logdir, True)
+                    db.session.delete(p)
+                    changed = True
+
             status, updated = BatchProcess.update_process_info(p)
             if not status:
                 continue
@@ -708,11 +735,6 @@ class BatchProcess(object):
             ):
                 continue
 
-            if BatchProcess._operate_orphan_process(p):
-                continue
-
-            execution_time = None
-
             stime = parser.parse(p.start_time)
             etime = parser.parse(p.end_time or get_current_time())
 
@@ -732,6 +754,8 @@ class BatchProcess(object):
                 'acknowledge': p.acknowledge,
                 'execution_time': execution_time,
                 'process_state': p.process_state,
+                'utility_pid': p.utility_pid,
+                'server_id': p.server_id,
                 'current_storage_dir': current_storage_dir,
             })
 
@@ -740,35 +764,12 @@ class BatchProcess(object):
 
         return res
 
-    @staticmethod
-    def _operate_orphan_process(p):
-
-        if p and p.desc:
-            desc = loads(p.desc)
-            if does_server_exists(desc.sid, current_user.id) is False:
-                current_app.logger.warning(
-                    _("Server with id '{0}' is either removed or does "
-                      "not exists for the background process "
-                      "'{1}'").format(desc.sid, p.pid)
-                )
-                try:
-                    process = BatchProcess(id=p.pid)
-                    process.acknowledge(p.pid)
-                except LookupError as lerr:
-                    current_app.logger.warning(
-                        _("Status for the background process '{0}' could "
-                          "not be loaded.").format(p.pid)
-                    )
-                    current_app.logger.exception(lerr)
-                return True
-
-        return False
-
     @staticmethod
     def total_seconds(dt):
         return round(dt.total_seconds(), 2)
 
-    def acknowledge(self, _pid):
+    @staticmethod
+    def acknowledge(_pid):
         """
         Acknowledge from the user, he/she has alredy watched the status.
 
@@ -776,9 +777,6 @@ class BatchProcess(object):
         And, delete the process information from the configuration, and the log
         files related to the process, if it has already been completed.
         """
-        status = True
-        _server = {}
-
         p = Process.query.filter_by(
             user_id=current_user.id, pid=_pid
         ).first()
@@ -787,16 +785,14 @@ class BatchProcess(object):
             raise LookupError(PROCESS_NOT_FOUND)
 
         if p.end_time is not None:
-            status, _server = self._get_cloud_instance_details(p)
             logdir = p.logdir
             db.session.delete(p)
             import shutil
             shutil.rmtree(logdir, True)
         else:
             p.acknowledge = get_current_time()
-        db.session.commit()
 
-        return status, _server
+        db.session.commit()
 
     def set_env_variables(self, server, **kwargs):
         """Set environment variables"""
@@ -834,13 +830,15 @@ class BatchProcess(object):
             process.terminate()
             # Update the process state to "Terminated"
             p.process_state = PROCESS_TERMINATED
-            db.session.commit()
+        except psutil.NoSuchProcess:
+            p.process_state = PROCESS_TERMINATED
         except psutil.Error as e:
             current_app.logger.warning(
                 _("Unable to kill the background process '{0}'").format(
                     p.utility_pid)
             )
             current_app.logger.exception(e)
+        db.session.commit()
 
     @staticmethod
     def update_server_id(_pid, _sid):
diff --git a/web/pgadmin/misc/bgprocess/static/css/bgprocess.css b/web/pgadmin/misc/bgprocess/static/css/bgprocess.css
deleted file mode 100644
index c5f431a35..000000000
--- a/web/pgadmin/misc/bgprocess/static/css/bgprocess.css
+++ /dev/null
@@ -1,59 +0,0 @@
-
-.ajs-bg-bgprocess .col-xs-12 {
-  padding-right: 5px;
-  padding-left: 5px;
-}
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess > .pg-bg-status {
-  padding: 2px;
-  margin: 0px 5px;
-  text-align: center;
-  border-radius: 2px;
-  -moz-border-radius: 2px;
-  -webkit-border-radius: 2px;
-}
-
-.pg-bg-process-logs {
-  width: 100%;
-  -webkit-user-select: text;
-  -moz-user-select: text;
-  -ms-user-select: text;
-  user-select: text;
-}
-
-ol.pg-bg-process-logs {
-  height: 100%;
-  overflow: auto;
-  width: 100%;
-}
-
-.pg-panel-content .bg-process-stats p{
-  display: inline;
-  padding-left: 5px;
-  margin-bottom: 0;
-  font-size: 13px;
-}
-
-.pg-panel-content .bg-process-footer p {
-  display: inline;
-  padding-left: 5px;
-  font-size: 13px;
-}
-
-.bg-process-footer .bg-process-status {
-  padding-left: 0;
-}
-
-.bg-process-footer .bg-process-exec-time {
-  padding-right: 0;
-}
-
-.pg-bg-bgprocess .ajs-commands {
-  right: -13px;
-  top: 2px;
-  opacity: 0.5;
-}
-
-.pg-bg-bgprocess:hover .bg-close {
-  opacity: 0.95;
-}
diff --git a/web/pgadmin/misc/bgprocess/static/js/BgProcessManager.js b/web/pgadmin/misc/bgprocess/static/js/BgProcessManager.js
new file mode 100644
index 000000000..13a4ef9c2
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/BgProcessManager.js
@@ -0,0 +1,243 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import getApiInstance, { parseApiError } from '../../../../static/js/api_instance';
+import url_for from 'sources/url_for';
+import Notifier from '../../../../static/js/helpers/Notifier';
+import EventBus from '../../../../static/js/helpers/EventBus';
+import * as BgProcessNotify from './BgProcessNotify';
+import showDetails from './showDetails';
+import gettext from 'sources/gettext';
+
+const WORKER_INTERVAL = 1000;
+
+export const BgProcessManagerEvents = {
+  LIST_UPDATED: 'LIST_UPDATED',
+};
+
+export const BgProcessManagerProcessState = {
+  PROCESS_NOT_STARTED: 0,
+  PROCESS_STARTED: 1,
+  PROCESS_FINISHED: 2,
+  PROCESS_TERMINATED: 3,
+  /* Supported by front end only */
+  PROCESS_TERMINATING: 10,
+  PROCESS_FAILED: 11,
+};
+
+
+export default class BgProcessManager {
+  static instance;
+
+  static getInstance(...args) {
+    if (!BgProcessManager.instance) {
+      BgProcessManager.instance = new BgProcessManager(...args);
+    }
+    return BgProcessManager.instance;
+  }
+
+  constructor(pgBrowser) {
+    this.api = getApiInstance();
+    this.pgBrowser = pgBrowser;
+    this._procList = [];
+    this._workerId = null;
+    this._pendingJobId = [];
+    this._eventManager = new EventBus();
+  }
+
+  init() {
+    if (this.initialized) {
+      return;
+    }
+    this.initialized = true;
+    this.startWorker();
+  }
+
+  get procList() {
+    return this._procList;
+  }
+
+  set procList(val) {
+    throw new Error('Property processList is readonly.', val);
+  }
+
+  async startWorker() {
+    let self = this;
+    await self.syncProcesses();
+    /* Fill the pending jobs initially */
+    self._pendingJobId = this.procList.filter((p)=>(p.process_state == BgProcessManagerProcessState.PROCESS_STARTED)).map((p)=>p.id);
+    this._workerId = setInterval(()=>{
+      if(self._pendingJobId.length > 0) {
+        self.syncProcesses();
+      }
+    }, WORKER_INTERVAL);
+  }
+
+  evaluateProcessState(p) {
+    let retState = p.process_state;
+    if((p.etime || p.exit_code !=null) && p.process_state == BgProcessManagerProcessState.PROCESS_STARTED) {
+      retState =  BgProcessManagerProcessState.PROCESS_FINISHED;
+    }
+    if(retState == BgProcessManagerProcessState.PROCESS_FINISHED && p.exit_code != 0) {
+      retState = BgProcessManagerProcessState.PROCESS_FAILED;
+    }
+    return retState;
+  }
+
+  async syncProcesses() {
+    try {
+      let {data: resData} = await this.api.get(url_for('bgprocess.list'));
+      this._procList = resData?.map((p)=>{
+        let processState = this.evaluateProcessState(p);
+        return {
+          ...p,
+          process_state: processState,
+          canDrop: ![BgProcessManagerProcessState.PROCESS_NOT_STARTED, BgProcessManagerProcessState.PROCESS_STARTED].includes(processState),
+        };
+      });
+      this._eventManager.fireEvent(BgProcessManagerEvents.LIST_UPDATED);
+      this.checkPending();
+    } catch (error) {
+      console.error(error);
+    }
+  }
+
+  checkPending() {
+    const completedProcIds = this.procList.filter((p)=>{
+      if(![
+        BgProcessManagerProcessState.PROCESS_NOT_STARTED,
+        BgProcessManagerProcessState.PROCESS_STARTED,
+        BgProcessManagerProcessState.PROCESS_TERMINATING].includes(p.process_state)) {
+        return true;
+      }
+    }).map((p)=>p.id);
+    this._pendingJobId = this._pendingJobId.filter((id)=>{
+      if(completedProcIds.includes(id)) {
+        let p = this.procList.find((p)=>p.id==id);
+        BgProcessNotify.processCompleted(p?.desc, p?.process_state, this.openProcessesPanel.bind(this));
+        if(p.server_id != null) {
+          this.updateCloudDetails(p.id);
+        }
+        return false;
+      }
+      return true;
+    });
+  }
+
+  startProcess(jobId, desc) {
+    if(jobId) {
+      this._pendingJobId.push(jobId);
+      BgProcessNotify.processStarted(desc, this.openProcessesPanel.bind(this));
+    }
+  }
+
+  stopProcess(jobId) {
+    this.procList.find((p)=>p.id == jobId).process_state = BgProcessManagerProcessState.PROCESS_TERMINATING;
+    this._eventManager.fireEvent(BgProcessManagerEvents.LIST_UPDATED);
+    this.api.put(url_for('bgprocess.stop_process', {
+      pid: jobId,
+    }))
+      .then(()=>{
+        this.procList.find((p)=>p.id == jobId).process_state = BgProcessManagerProcessState.PROCESS_TERMINATED;
+        this._eventManager.fireEvent(BgProcessManagerEvents.LIST_UPDATED);
+      })
+      .catch((err)=>{
+        Notifier.error(parseApiError(err));
+      });
+  }
+
+  acknowledge(jobIds) {
+    const removeJob = (jobId)=>{
+      this._procList = this.procList.filter((p)=>p.id!=jobId);
+      this._eventManager.fireEvent(BgProcessManagerEvents.LIST_UPDATED);
+    };
+    jobIds.forEach((jobId)=>{
+      this.api.put(url_for('bgprocess.acknowledge', {
+        pid: jobId,
+      }))
+        .then(()=>{
+          removeJob(jobId);
+        })
+        .catch((err)=>{
+          if(err.response?.status == 410) {
+          /* Object not available */
+            removeJob(jobId);
+          } else {
+            Notifier.error(parseApiError(err));
+          }
+        });
+    });
+  }
+
+  viewJobDetails(jobId) {
+    showDetails(this.procList.find((p)=>p.id==jobId));
+  }
+
+  updateCloudDetails(jobId) {
+    this.api.put(url_for('bgprocess.update_cloud_details', {
+      pid: jobId,
+    }))
+      .then((res)=>{
+        let _server = res.data?.data?.node;
+        if(!_server) {
+          Notifier.error(gettext('Cloud server information not available'));
+          return;
+        }
+        let  _server_path = '/browser/server_group_' + _server.gid + '/' + _server.id,
+          _tree = this.pgBrowser.tree,
+          _item = _tree.findNode(_server_path);
+
+        if (_item) {
+          if(_server.status) {
+            let _dom = _item.domNode;
+            _tree.addIcon(_dom, {icon: _server.icon});
+            let d = _tree.itemData(_dom);
+            d.cloud_status = _server.cloud_status;
+            _tree.update(_dom, d);
+          }
+          else {
+            _tree.remove(_item.domNode);
+            _tree.refresh(_item.domNode.parent);
+          }
+        }
+      })
+      .catch((err)=>{
+        if(err.response?.status != 410) {
+          Notifier.error(gettext('Failed Cloud Deployment.'));
+        }
+      });
+  }
+
+  recheckCloudServer(sid) {
+    let self = this;
+    let process = self.procList.find((p)=>p.server_id==sid);
+    if(process) {
+      this.updateCloudDetails(process.id);
+    }
+  }
+
+  openProcessesPanel() {
+    let processPanel = this.pgBrowser.docker.findPanels('processes');
+    if(processPanel.length > 0) {
+      processPanel = processPanel[0];
+    } else {
+      let propertiesPanel = this.pgBrowser.docker.findPanels('properties');
+      processPanel = this.pgBrowser.docker.addPanel('processes', window.wcDocker.DOCK.STACKED, propertiesPanel[0]);
+    }
+    processPanel.focus();
+  }
+
+  registerListener(event, callback) {
+    this._eventManager.registerListener(event, callback);
+  }
+
+  deregisterListener(event, callback) {
+    this._eventManager.deregisterListener(event, callback);
+  }
+}
diff --git a/web/pgadmin/misc/bgprocess/static/js/BgProcessNotify.jsx b/web/pgadmin/misc/bgprocess/static/js/BgProcessNotify.jsx
new file mode 100644
index 000000000..850d77c0e
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/BgProcessNotify.jsx
@@ -0,0 +1,98 @@
+import { Box, makeStyles } from '@material-ui/core';
+import React from 'react';
+import Notifier from '../../../../static/js/helpers/Notifier';
+import CloseIcon from '@material-ui/icons/CloseRounded';
+import { DefaultButton, PgIconButton } from '../../../../static/js/components/Buttons';
+import clsx from 'clsx';
+import DescriptionOutlinedIcon from '@material-ui/icons/DescriptionOutlined';
+import { BgProcessManagerProcessState } from './BgProcessManager';
+import PropTypes from 'prop-types';
+import gettext from 'sources/gettext';
+
+
+const useStyles = makeStyles((theme)=>({
+  container: {
+    borderRadius: theme.shape.borderRadius,
+    padding: '0.25rem 1rem 1rem',
+    minWidth: '325px',
+    ...theme.mixins.panelBorder.all,
+  },
+  containerHeader: {
+    height: '32px',
+    display: 'flex',
+    justifyContent: 'space-between',
+    fontWeight: 'bold',
+    alignItems: 'center',
+    borderTopLeftRadius: 'inherit',
+    borderTopRightRadius: 'inherit',
+  },
+  containerBody: {
+    marginTop: '1rem',
+  },
+  containerSuccess: {
+    borderColor: theme.palette.success.main,
+    backgroundColor: theme.palette.success.light,
+  },
+  iconSuccess: {
+    color: theme.palette.success.main,
+  },
+  containerError: {
+    borderColor: theme.palette.error.main,
+    backgroundColor: theme.palette.error.light,
+  },
+  iconError: {
+    color: theme.palette.error.main,
+  },
+}));
+
+function ProcessNotifyMessage({title, desc, onClose, onViewProcess, success=true, dataTestSuffix=""}) {
+  const classes = useStyles();
+  return (
+    <Box className={clsx(classes.container, (success ? classes.containerSuccess : classes.containerError))} data-test={"process-popup-" + dataTestSuffix}>
+      <Box display="flex" justifyContent="space-between" className={classes.containerHeader}>
+        <Box marginRight={'1rem'}>{title}</Box>
+        <PgIconButton size="xs" noBorder icon={<CloseIcon />} onClick={onClose} title={'Close'} className={success ? classes.iconSuccess : classes.iconError} />
+      </Box>
+      <Box className={classes.containerBody}>
+        <Box>{desc}</Box>
+        <Box marginTop={'1rem'} display="flex">
+          <DefaultButton startIcon={<DescriptionOutlinedIcon />} onClick={onViewProcess}>View Processes</DefaultButton>
+        </Box>
+      </Box>
+    </Box>
+  );
+}
+ProcessNotifyMessage.propTypes = {
+  title: PropTypes.string.isRequired,
+  desc: PropTypes.string.isRequired,
+  onClose: PropTypes.func,
+  onViewProcess: PropTypes.func,
+  success: PropTypes.bool,
+  dataTestSuffix: PropTypes.string,
+};
+
+
+export function processStarted(desc, onViewProcess) {
+  Notifier.notify(
+    <ProcessNotifyMessage title={gettext('Process started')} desc={desc} onViewProcess={onViewProcess} dataTestSuffix="start"/>,
+    null
+  );
+}
+
+export function processCompleted(desc, process_state, onViewProcess) {
+  let title = gettext('Process completed');
+  let success = true;
+  if(process_state == BgProcessManagerProcessState.PROCESS_TERMINATED) {
+    title = gettext('Process terminated');
+    success = false;
+  } else if(process_state == BgProcessManagerProcessState.PROCESS_FAILED) {
+    title = gettext('Process failed');
+    success = false;
+  }
+
+  Notifier.notify(
+    <ProcessNotifyMessage title={title} desc={desc} onViewProcess={onViewProcess} success={success} dataTestSuffix="end"/>,
+    null
+  );
+}
+
diff --git a/web/pgadmin/misc/bgprocess/static/js/ProcessDetails.jsx b/web/pgadmin/misc/bgprocess/static/js/ProcessDetails.jsx
new file mode 100644
index 000000000..d62777c08
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/ProcessDetails.jsx
@@ -0,0 +1,182 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import React, { useState, useMemo } from 'react';
+import gettext from 'sources/gettext';
+import url_for from 'sources/url_for';
+import { Box, makeStyles } from '@material-ui/core';
+import PropTypes from 'prop-types';
+import { MESSAGE_TYPE, NotifierMessage } from '../../../../static/js/components/FormComponents';
+import { BgProcessManagerProcessState } from './BgProcessManager';
+import { DefaultButton, PgIconButton } from '../../../../static/js/components/Buttons';
+import HighlightOffRoundedIcon from '@material-ui/icons/HighlightOffRounded';
+import AccessTimeRoundedIcon from '@material-ui/icons/AccessTimeRounded';
+import { useInterval } from '../../../../static/js/custom_hooks';
+import getApiInstance from '../../../../static/js/api_instance';
+import pgAdmin from 'sources/pgadmin';
+import FolderSharedRoundedIcon from '@material-ui/icons/FolderSharedRounded';
+
+
+const useStyles = makeStyles((theme)=>({
+  container: {
+    backgroundColor: theme.palette.background.default,
+    height: '100%',
+    display: 'flex',
+    flexDirection: 'column',
+    padding: '8px',
+    userSelect: 'text',
+  },
+  cmd: {
+    ...theme.mixins.panelBorder.all,
+    borderRadius: theme.shape.borderRadius,
+    backgroundColor: theme.otherVars.inputDisabledBg,
+    wordBreak: 'break-word',
+    margin: '8px 0px',
+    padding: '4px',
+  },
+  logs: {
+    flexGrow: 1,
+    borderRadius: theme.shape.borderRadius,
+    padding: '4px',
+    overflow: 'auto',
+    textOverflow: 'wrap-text',
+    margin: '8px 0px',
+    ...theme.mixins.panelBorder.all,
+  },
+  logErr: {
+    color: theme.palette.error.main,
+  },
+  terminateBtn: {
+    backgroundColor: theme.palette.error.main,
+    color: theme.palette.error.contrastText,
+    border: 0,
+    '&:hover': {
+      backgroundColor: theme.palette.error.dark,
+      color: theme.palette.error.contrastText,
+    },
+    '&.Mui-disabled': {
+      color: theme.palette.error.contrastText + ' !important',
+      border: 0,
+    }
+  }
+}));
+
+async function getDetailedStatus(api, jobId, out, err) {
+  let res = await api.get(url_for(
+    'bgprocess.detailed_status', {
+      'pid': jobId,
+      'out': out,
+      'err': err,
+    }
+  ));
+  return res.data;
+}
+
+export default function ProcessDetails({data}) {
+  const classes = useStyles();
+  const api = useMemo(()=>getApiInstance());
+  const [logs, setLogs] = useState(null);
+  const [completed, setCompleted] = useState(false);
+  const [[outPos, errPos], setOutErrPos] = useState([0, 0]);
+  const [exitCode, setExitCode] = useState(data.exit_code);
+  const [timeTaken, setTimeTaken] = useState(data.execution_time);
+
+  let notifyType = MESSAGE_TYPE.INFO;
+  let notifyText = gettext('Not started');
+
+  const process_state = pgAdmin.Browser.BgProcessManager.evaluateProcessState({
+    ...data,
+    exit_code: exitCode,
+  });
+
+  if(process_state == BgProcessManagerProcessState.PROCESS_STARTED) {
+    notifyText = gettext('Running...');
+  } else if(process_state == BgProcessManagerProcessState.PROCESS_FINISHED) {
+    notifyType = MESSAGE_TYPE.SUCCESS;
+    notifyText = gettext('Successfully completed.');
+  } else if(process_state == BgProcessManagerProcessState.PROCESS_FAILED) {
+    notifyType = MESSAGE_TYPE.ERROR;
+    notifyText = gettext('Failed (exit code: %s).', String(exitCode));
+  } else if(process_state == BgProcessManagerProcessState.PROCESS_TERMINATED) {
+    notifyType = MESSAGE_TYPE.ERROR;
+    notifyText = gettext('Terminated by user.');
+  } else if(process_state == BgProcessManagerProcessState.PROCESS_TERMINATING) {
+    notifyText = gettext('Terminating the process...');
+  }
+
+  useInterval(async ()=>{
+    const logsSortComp = (l1, l2)=>{
+      return l1[0].localeCompare(l2[0]);
+    };
+    let resData = await getDetailedStatus(api, data.id, outPos, errPos);
+    resData.out.lines.sort(logsSortComp);
+    resData.err.lines.sort(logsSortComp);
+    if(resData.out?.done && resData.err?.done && resData.exit_code != null) {
+      setExitCode(resData.exit_code);
+      setCompleted(true);
+    }
+    setTimeTaken(resData.execution_time);
+    setOutErrPos([resData.out.pos, resData.err.pos]);
+    setLogs((prevLogs)=>{
+      return [
+        ...(prevLogs || []),
+        ...resData.out.lines.map((l)=>l[1]),
+        ...resData.err.lines.map((l)=>l[1]),
+      ];
+    });
+
+  }, completed ? -1 : 1000);
+
+  const errRe = new RegExp(': (' + gettext('error') + '|' + gettext('fatal') + '):', 'i');
+  return (
+    <Box display="flex" flexDirection="column" className={classes.container} data-test="process-details">
+      <Box data-test="process-message">{data.details?.message}</Box>
+      {data.details?.cmd && <>
+        <Box>{gettext('Running command')}:</Box>
+        <Box data-test="process-cmd" className={classes.cmd}>{data.details.cmd}</Box>
+      </>}
+      {data.details?.query && <>
+        <Box>{gettext('Running query')}:</Box>
+        <Box data-test="process-cmd" className={classes.cmd}>{data.details.query}</Box>
+      </>}
+      <Box display="flex" justifyContent="space-between" alignItems="center" flexWrap="wrap">
+        <Box><span><AccessTimeRoundedIcon /> {gettext('Start time')}: {new Date(data.stime).toString()}</span></Box>
+        <Box>
+          {pgAdmin.server_mode == 'True' && data.current_storage_dir &&
+          <PgIconButton icon={<FolderSharedRoundedIcon />} title={gettext('Storage Manager')} onClick={()=>{
+            pgAdmin.Tools.FileManager.openStorageManager(data.current_storage_dir);
+          }} style={{marginRight: '4px'}} />}
+          <DefaultButton disabled={process_state != BgProcessManagerProcessState.PROCESS_STARTED || data.server_id != null}
+            startIcon={<HighlightOffRoundedIcon />} className={classes.terminateBtn}>Stop Process</DefaultButton></Box>
+      </Box>
+      <Box flexGrow={1} className={classes.logs}>
+        {logs == null && <span data-test="loading-logs">gettext('Loading process logs...')</span>}
+        {logs?.length == 0 && gettext('No logs available.')}
+        {logs?.map((log, i)=>{
+          return <div ref={(el)=>{
+            if(i==logs.length-1) {
+              el?.scrollIntoView();
+            }
+          }} key={i} className={errRe.test(log) ? classes.logErr : ''}>{log}</div>;
+        })}
+      </Box>
+      <Box display="flex" alignItems="center">
+        <NotifierMessage type={notifyType} message={notifyText} closable={false} textCenter={true} style={{flexGrow: 1, marginRight: '8px'}} />
+        <Box>{gettext('Execution time')}: {timeTaken} {gettext('seconds')}</Box>
+      </Box>
+    </Box>
+  );
+}
+
+ProcessDetails.propTypes = {
+  closeModal: PropTypes.func,
+  data: PropTypes.object,
+  onOK: PropTypes.func,
+  setHeight: PropTypes.func
+};
diff --git a/web/pgadmin/misc/bgprocess/static/js/Processes.jsx b/web/pgadmin/misc/bgprocess/static/js/Processes.jsx
new file mode 100644
index 000000000..65545ab4c
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/Processes.jsx
@@ -0,0 +1,290 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import React, { useEffect } from 'react';
+import PgTable from 'sources/components/PgTable';
+import gettext from 'sources/gettext';
+import PropTypes from 'prop-types';
+import { makeStyles } from '@material-ui/core/styles';
+import pgAdmin from 'sources/pgadmin';
+import { BgProcessManagerEvents, BgProcessManagerProcessState } from './BgProcessManager';
+import { PgIconButton } from '../../../../static/js/components/Buttons';
+import CancelIcon from '@material-ui/icons/Cancel';
+import DescriptionOutlinedIcon from '@material-ui/icons/DescriptionOutlined';
+import DeleteIcon from '@material-ui/icons/Delete';
+import HelpIcon from '@material-ui/icons/HelpRounded';
+import url_for from 'sources/url_for';
+import { Box } from '@material-ui/core';
+
+
+const useStyles = makeStyles((theme) => ({
+  stopButton: {
+    color: theme.palette.error.main
+  },
+  buttonClick: {
+    backgroundColor: theme.palette.grey[400]
+  },
+  emptyPanel: {
+    minHeight: '100%',
+    minWidth: '100%',
+    background: theme.otherVars.emptySpaceBg,
+    overflow: 'auto',
+    padding: '8px',
+    display: 'flex',
+  },
+  panelIcon: {
+    width: '80%',
+    margin: '0 auto',
+    marginTop: '25px !important',
+    position: 'relative',
+    textAlign: 'center',
+  },
+  panelMessage: {
+    marginLeft: '0.5rem',
+    fontSize: '0.875rem',
+  },
+  autoResizer: {
+    height: '100% !important',
+    width: '100% !important',
+    background: theme.palette.grey[400],
+    padding: '7.5px',
+    overflow: 'auto !important',
+    minHeight: '100%',
+    minWidth: '100%',
+  },
+  noPadding: {
+    padding: 0,
+  },
+  bgSucess: {
+    backgroundColor: theme.palette.success.light,
+    height: '100%',
+    padding: '4px',
+  },
+  bgFailed: {
+    backgroundColor: theme.palette.error.light,
+    height: '100%',
+    padding: '4px',
+  },
+  bgTerm: {
+    backgroundColor: theme.palette.warning.light,
+    height: '100%',
+    padding: '4px',
+  },
+  bgRunning: {
+    backgroundColor: theme.palette.primary.light,
+    height: '100%',
+    padding: '4px',
+  },
+}));
+
+
+const ProcessStateTextAndColor = {
+  [BgProcessManagerProcessState.PROCESS_NOT_STARTED]: [gettext('Not started'), 'bgRunning'],
+  [BgProcessManagerProcessState.PROCESS_STARTED]: [gettext('Running'), 'bgRunning'],
+  [BgProcessManagerProcessState.PROCESS_FINISHED]: [gettext('Finished'), 'bgSucess'],
+  [BgProcessManagerProcessState.PROCESS_TERMINATED]: [gettext('Terminated'), 'bgTerm'],
+  [BgProcessManagerProcessState.PROCESS_TERMINATING]: [gettext('Terminating...'), 'bgTerm'],
+  [BgProcessManagerProcessState.PROCESS_FAILED]: [gettext('Failed'), 'bgFailed'],
+};
+
+export default function Processes() {
+  const classes = useStyles();
+  const [tableData, setTableData] = React.useState([]);
+  const [selectedRows, setSelectedRows] = React.useState([]);
+
+  let columns = [
+    {
+      accessor: 'stop_process',
+      Header: () => null,
+      sortable: false,
+      resizable: false,
+      disableGlobalFilter: true,
+      width: 35,
+      maxWidth: 35,
+      minWidth: 35,
+      id: 'btn-stop',
+      // eslint-disable-next-line react/display-name
+      Cell: ({ row }) => {
+        return (
+          <PgIconButton
+            size="xs"
+            noBorder
+            icon={<CancelIcon />}
+            className={classes.stopButton}
+            disabled={row.original.process_state != BgProcessManagerProcessState.PROCESS_STARTED
+              || row.original.server_id != null}
+            onClick={(e) => {
+              e.preventDefault();
+              pgAdmin.Browser.BgProcessManager.stopProcess(row.original.id);
+            }}
+            aria-label="Stop Process"
+            title={gettext('Stop Process')}
+          ></PgIconButton>
+        );
+      },
+    },
+    {
+      accessor: 'view_details',
+      Header: () => null,
+      sortable: false,
+      resizable: false,
+      disableGlobalFilter: true,
+      width: 35,
+      maxWidth: 35,
+      minWidth: 35,
+      id: 'btn-logs',
+      // eslint-disable-next-line react/display-name
+      Cell: ({ row }) => {
+        return (
+          <PgIconButton
+            size="xs"
+            icon={<DescriptionOutlinedIcon />}
+            noBorder
+            onClick={(e) => {
+              e.preventDefault();
+              pgAdmin.Browser.BgProcessManager.viewJobDetails(row.original.id);
+            }}
+            aria-label="View details"
+            title={gettext('View details')}
+          />
+        );
+      },
+    },
+    {
+      Header: gettext('PID'),
+      accessor: 'utility_pid',
+      sortable: true,
+      resizable: false,
+      width: 70,
+      minWidth: 70,
+      disableGlobalFilter: false,
+    },
+    {
+      Header: gettext('Type'),
+      accessor: (row)=>row.details?.type,
+      sortable: true,
+      resizable: true,
+      width: 100,
+      minWidth: 70,
+      disableGlobalFilter: false,
+    },
+    {
+      Header: gettext('Server'),
+      accessor: (row)=>row.details?.server,
+      sortable: true,
+      resizable: true,
+      width: 200,
+      minWidth: 120,
+      disableGlobalFilter: false,
+    },
+    {
+      Header: gettext('Object'),
+      accessor: (row)=>row.details?.object,
+      sortable: true,
+      resizable: true,
+      width: 200,
+      minWidth: 120,
+      disableGlobalFilter: false,
+    },
+    {
+      id: 'stime',
+      Header: gettext('Start Time'),
+      sortable: true,
+      resizable: true,
+      disableGlobalFilter: true,
+      width: 150,
+      minWidth: 150,
+      accessor: (row)=>(new Date(row.stime)),
+      Cell: ({row})=>(new Date(row.original.stime).toLocaleString()),
+    },
+    {
+      Header: gettext('Status'),
+      sortable: true,
+      resizable: false,
+      disableGlobalFilter: false,
+      width: 120,
+      minWidth: 120,
+      accessor: (row)=>ProcessStateTextAndColor[row.process_state][0],
+      dataClassName: classes.noPadding,
+      Cell: ({row})=>{
+        const [text, bgcolor] = ProcessStateTextAndColor[row.original.process_state];
+        return <Box className={classes[bgcolor]}>{text}</Box>;
+      },
+    },
+    {
+      Header: gettext('Time Taken'),
+      accessor: 'execution_time',
+      sortable: true,
+      resizable: true,
+      disableGlobalFilter: true,
+    },
+  ];
+
+  const updateList = ()=>{
+    if(pgAdmin.Browser.BgProcessManager.procList) {
+      setTableData([...pgAdmin.Browser.BgProcessManager.procList]);
+    }
+  };
+
+  useEffect(() => {
+    updateList();
+    pgAdmin.Browser.BgProcessManager.registerListener(BgProcessManagerEvents.LIST_UPDATED, updateList);
+    return ()=>{
+      pgAdmin.Browser.BgProcessManager.deregisterListener(BgProcessManagerEvents.LIST_UPDATED, updateList);
+    };
+  }, []);
+
+  return (
+    <>
+      <PgTable
+        data-test="processes"
+        className={classes.autoResizer}
+        columns={columns}
+        data={tableData}
+        sortOptions={[{id: 'stime', desc: true}]}
+        getSelectedRows={(rows)=>{setSelectedRows(rows);}}
+        isSelectRow={true}
+        CustomHeader={()=>{
+          return (
+            <Box>
+              <PgIconButton
+                className={classes.dropButton}
+                icon={<DeleteIcon/>}
+                aria-label="Acknowledge and Remove"
+                title={gettext('Acknowledge and Remove')}
+                onClick={() => {
+                  pgAdmin.Browser.BgProcessManager.acknowledge(selectedRows.map((p)=>p.original.id));
+                }}
+                disabled={selectedRows.length <= 0}
+              ></PgIconButton>
+              <PgIconButton
+                icon={<HelpIcon/>}
+                aria-label="Help"
+                title={gettext('Help')}
+                style={{marginLeft: '8px'}}
+                onClick={() => {
+                  window.open(url_for('help.static', {'filename': 'processes.html'}));
+                }}
+              ></PgIconButton>
+            </Box>
+          );
+        }}
+      ></PgTable>
+    </>
+  );
+}
+
+Processes.propTypes = {
+  res: PropTypes.array,
+  nodeData: PropTypes.object,
+  treeNodeInfo: PropTypes.object,
+  node: PropTypes.func,
+  item: PropTypes.object,
+  row: PropTypes.object,
+};
diff --git a/web/pgadmin/misc/bgprocess/static/js/bgprocess.js b/web/pgadmin/misc/bgprocess/static/js/bgprocess.js
deleted file mode 100644
index ddc965e7a..000000000
--- a/web/pgadmin/misc/bgprocess/static/js/bgprocess.js
+++ /dev/null
@@ -1,764 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-define('misc.bgprocess', [
-  'sources/pgadmin', 'sources/gettext', 'sources/url_for', 'underscore',
-  'jquery', 'pgadmin.browser', 'alertify', 'pgadmin.tools.file_manager',
-], function(
-  pgAdmin, gettext, url_for, _, $, pgBrowser, Alertify
-) {
-
-  pgBrowser.BackgroundProcessObsorver = pgBrowser.BackgroundProcessObsorver || {};
-
-  if (pgBrowser.BackgroundProcessObsorver.initialized) {
-    return pgBrowser.BackgroundProcessObsorver;
-  }
-
-  var isServerMode = (function() { return pgAdmin.server_mode == 'True'; })();
-
-  var wcDocker = window.wcDocker;
-
-  var BGProcess = function(info, notify) {
-    var self = this;
-    setTimeout(
-      function() {
-        self.initialize.apply(self, [info, notify]);
-      }, 1
-    );
-  };
-
-  _.extend(
-    BGProcess.prototype, {
-      success_status_tpl: _.template(`
-      <div class="d-flex px-2 py-1 bg-success-light border border-success rounded">
-        <div class="pr-2">
-          <i class="fa fa-check text-success pg-bg-status-icon" aria-hidden="true" role="img"></i>
-        </div>
-        <div class="mx-auto pg-bg-status-text alert-text-body"><%-status_text%></div>
-      </div>`),
-      failed_status_tpl: _.template(`
-      <div class="d-flex px-2 py-1 bg-danger-lighter border border-danger rounded">
-        <div class="pr-2">
-          <i class="fa fa-times fa-lg text-danger pg-bg-status-icon" aria-hidden="true" role="img"></i>
-        </div>
-        <div class="mx-auto pg-bg-status-text alert-text-body"><%-status_text%></div>
-      </div>`),
-      other_status_tpl: _.template(`
-      <div class="d-flex px-2 py-1 bg-primary-light border border-primary rounded">
-        <div class="pr-2">
-          <i class="fa fa-info fa-lg text-primary pg-bg-status-icon" aria-hidden="true" role="img"></i>
-        </div>
-        <div class="mx-auto pg-bg-status-text alert-text-body"><%-status_text%></div>
-      </div>`),
-      initialize: function(info, notify) {
-        _.extend(this, {
-          details: false,
-          notify: (_.isUndefined(notify) || notify),
-          curr_status: null,
-          state: 0, // 0: NOT Started, 1: Started, 2: Finished, 3: Terminated
-          completed: false,
-          current_storage_dir: null,
-
-          id: info['id'],
-          type_desc: null,
-          desc: null,
-          detailed_desc: null,
-          stime: null,
-          exit_code: null,
-          acknowledge: info['acknowledge'],
-          execution_time: null,
-          out: -1,
-          err: -1,
-          lot_more: false,
-
-          notifier: null,
-          container: null,
-          panel: null,
-          logs: $('<ol></ol>', {
-            class: 'pg-bg-process-logs',
-          }),
-        });
-
-        if (this.notify) {
-          pgBrowser.Events && pgBrowser.Events.on(
-            'pgadmin-bgprocess:started:' + this.id,
-            function(process) {
-              if (!process.notifier)
-                process.show.apply(process);
-            }
-          );
-          pgBrowser.Events && pgBrowser.Events.on(
-            'pgadmin-bgprocess:finished:' + this.id,
-            function(process) {
-              if (!process.notifier) {
-                if (process.cloud_process == 1) process.update_cloud_server.apply(process);
-                process.show.apply(process);
-              }
-            }
-          );
-        }
-        var self = this;
-
-        setTimeout(
-          function() {
-            self.update.apply(self, [info]);
-          }, 1
-        );
-      },
-
-      bgprocess_url: function(type) {
-        switch (type) {
-        case 'status':
-          if (this.details && this.out != -1 && this.err != -1) {
-            return url_for(
-              'bgprocess.detailed_status', {
-                'pid': this.id,
-                'out': this.out,
-                'err': this.err,
-              }
-            );
-          }
-          return url_for('bgprocess.status', {
-            'pid': this.id,
-          });
-        case 'acknowledge':
-          return url_for('bgprocess.acknowledge', {
-            'pid': this.id,
-          });
-        case 'stop_process':
-          return url_for('bgprocess.stop_process', {
-            'pid': this.id,
-          });
-        default:
-          return url_for('bgprocess.list');
-        }
-      },
-
-      update: function(data) {
-        var self = this,
-          out = [],
-          err = [];
-
-        if ('stime' in data)
-          self.stime = new Date(data.stime);
-
-        if ('execution_time' in data)
-          self.execution_time = parseFloat(data.execution_time);
-
-        if ('type_desc' in data)
-          self.type_desc = data.type_desc;
-
-        if ('desc' in data)
-          self.desc = data.desc;
-
-        if ('details' in data)
-          self.detailed_desc = data.details;
-
-        if ('exit_code' in data)
-          self.exit_code = data.exit_code;
-
-        if ('process_state' in data)
-          self.state = data.process_state;
-
-        if ('current_storage_dir' in data)
-          self.current_storage_dir = data.current_storage_dir;
-
-        if ('out' in data) {
-          self.out = data.out && data.out.pos;
-
-          if (data.out && data.out.lines) {
-            out = data.out.lines;
-          }
-        }
-
-        if ('cloud_process' in data && data.cloud_process == 1) {
-          self.cloud_process = data.cloud_process;
-          self.cloud_instance = data.cloud_instance;
-          self.cloud_server_id = data.cloud_server_id;
-        }
-
-        if ('err' in data) {
-          self.err = data.err && data.err.pos;
-
-          if (data.err && data.err.lines) {
-            err = data.err.lines;
-          }
-        }
-        self.completed = self.completed || (
-          'err' in data && 'out' in data && data.err.done && data.out.done
-        ) || (!self.details && !_.isNull(self.exit_code));
-
-        var io = 0,
-          ie = 0,
-          res = [],
-          escapeEl = document.createElement('textarea'),
-          escapeHTML = function(html) {
-            escapeEl.textContent = html;
-            return escapeEl.innerHTML;
-          };
-
-        while (io < out.length && ie < err.length) {
-          if (pgAdmin.natural_sort(out[io][0], err[ie][0]) <= 0) {
-            res.push('<li class="pg-bg-res-out">' + escapeHTML(out[io++][1]) + '</li>');
-          } else {
-            let log_msg = escapeHTML(err[ie++][1]);
-            let regex_obj = new RegExp(': (' + gettext('error') + '|' + gettext('fatal') + '):', 'i');
-            if (regex_obj.test(log_msg)) {
-              res.push('<li class="pg-bg-res-err">' + log_msg + '</li>');
-            } else {
-              res.push('<li class="pg-bg-res-out">' + log_msg + '</li>');
-            }
-          }
-        }
-
-        while (io < out.length) {
-          res.push('<li class="pg-bg-res-out">' + escapeHTML(out[io++][1]) + '</li>');
-        }
-
-        while (ie < err.length) {
-          let log_msg = escapeHTML(err[ie++][1]);
-          let regex_obj = new RegExp(': (' + gettext('error') + '|' + gettext('fatal') + '):', 'i');
-          if (regex_obj.test(log_msg)) {
-            res.push('<li class="pg-bg-res-err">' + log_msg + '</li>');
-          } else {
-            res.push('<li class="pg-bg-res-out">' + log_msg + '</li>');
-          }
-        }
-
-        if (res.length) {
-          self.logs.append(res.join(''));
-          setTimeout(function() {
-            self.logs[0].scrollTop = self.logs[0].scrollHeight;
-          });
-        }
-
-        if(self.logs_loading) {
-          self.logs_loading.remove();
-          self.logs_loading = null;
-        }
-
-        if (self.stime) {
-          self.curr_status = self.other_status_tpl({status_text:gettext('Started')});
-
-          if (self.execution_time >= 2) {
-            self.curr_status = self.other_status_tpl({status_text:gettext('Running...')});
-          }
-
-          if (!_.isNull(self.exit_code)) {
-            if (self.state === 3) {
-              self.curr_status = self.failed_status_tpl({status_text:gettext('Terminated by user.')});
-            } else if (self.exit_code == 0) {
-              self.curr_status = self.success_status_tpl({status_text:gettext('Successfully completed.')});
-            } else {
-              self.curr_status = self.failed_status_tpl(
-                {status_text:gettext('Failed (exit code: %s).', String(self.exit_code))}
-              );
-            }
-          } else if (_.isNull(self.exit_code) && self.state === 3) {
-            self.curr_status = self.other_status_tpl({status_text:gettext('Terminating the process...')});
-          }
-
-          if (self.state == 0 && self.stime) {
-            self.state = 1;
-            pgBrowser.Events && pgBrowser.Events.trigger(
-              'pgadmin-bgprocess:started:' + self.id, self, self
-            );
-          }
-
-          if (self.state == 1 && !_.isNull(self.exit_code)) {
-            self.state = 2;
-            pgBrowser.Events && pgBrowser.Events.trigger(
-              'pgadmin-bgprocess:finished:' + self.id, self, self
-            );
-          }
-
-          setTimeout(function() {
-            self.show.apply(self);
-          }, 10);
-        }
-
-        if (!self.completed) {
-          setTimeout(
-            function() {
-              self.status.apply(self);
-            }, 1000
-          );
-        }
-      },
-
-      status: function() {
-        var self = this;
-
-        $.ajax({
-          typs: 'GET',
-          timeout: 30000,
-          url: self.bgprocess_url('status'),
-          cache: false,
-          async: true,
-          contentType: 'application/json',
-        })
-          .done(function(res) {
-            setTimeout(function() {
-              self.update(res);
-            }, 10);
-          })
-          .fail(function(res) {
-          // Try after some time only if job id present
-            if (res.status != 410)
-              setTimeout(function() {
-                self.update(res);
-              }, 10000);
-          });
-      },
-
-      update_cloud_server: function() {
-        var self = this,
-          _url = url_for('cloud.update_cloud_server'),
-          _data = {},
-          cloud_instance = self.cloud_instance;
-        if (cloud_instance != '') {
-          _data = JSON.parse(cloud_instance);
-        }
-
-        _data['instance']['sid'] = self.cloud_server_id;
-
-        $.ajax({
-          type: 'POST',
-          url: _url,
-          async: true,
-          data: JSON.stringify(_data),
-          contentType: 'application/json',
-        })
-          .done(function(res) {
-            setTimeout(function() {
-              let _server = res.data.node,
-                _server_path = '/browser/server_group_' + _server.gid + '/' + _server.id,
-                _tree = pgBrowser.tree,
-                _item = _tree.findNode(_server_path);
-
-              if (_item) {
-                _tree.addIcon(_item.domNode, {icon: _server.icon});
-                let d = _tree.itemData(_item);
-                d.cloud_status = 1;
-                _tree.update(_item, d);
-              }
-            }, 10);
-          })
-          .fail(function(res) {
-          // Try after some time only if job id present
-            if (res.status != 410)
-              console.warn('Failed Cloud Deployment.');
-          });
-      },
-
-      show: function() {
-        var self = this;
-
-        if (self.notify && !self.details) {
-          if (!self.notifier) {
-            let content = $(`
-            <div class="card">
-              <div class="card-header bg-primary d-flex">
-                <div>${self.type_desc}</div>
-                <div class="ml-auto">
-                  <button class="btn btn-sm-sq btn-primary pg-bg-close" aria-label='close'><i class="fa fa-lg fa-times" role="img"></i></button>
-                </div>
-              </div>
-              <div class="card-body px-2">
-                <div class="py-1">${self.desc}</div>
-                <div class="py-1">${self.stime.toString()}</div>
-                <div class="d-flex py-1">
-                  <div class="my-auto mr-2">
-                    <span class="fa fa-clock fa-lg" role="img"></span>
-                  </div>
-                  <div class="pg-bg-etime my-auto mr-2"></div>
-                  <div class="ml-auto">
-                    <button class="btn btn-secondary pg-bg-more-details" title="More Details"><span class="fa fa-info-circle" role="img"></span>&nbsp;` + gettext('More details...') + `</button>
-                    <button class="btn btn-danger bg-process-stop" disabled><span class="fa fa-times-circle" role="img" title="Stop the operation"></span>&nbsp;` + gettext('Stop Process') + `</button>
-                  </div>
-                </div>
-                <div class="pg-bg-status py-1">
-                </div>
-              </div>
-            </div>
-            `);
-
-            let for_details = content.find('.pg-bg-more-details');
-            let close_me = content.find('.pg-bg-close');
-
-            self.container = content;
-            self.notifier = Alertify.notify(
-              content.get(0), 'bg-bgprocess', 0, null
-            );
-
-            for_details.on('click', function(ev) {
-              ev = ev || window.event;
-              ev.cancelBubble = true;
-              ev.stopPropagation();
-
-              this.notifier.dismiss();
-              this.notifier = null;
-              this.completed = false;
-
-              this.show_detailed_view.apply(this);
-            }.bind(self));
-
-            close_me.on('click', function() {
-              this.notifier.dismiss();
-              this.notifier = null;
-              this.acknowledge_server.apply(this);
-            }.bind(this));
-
-            // Do not close the notifier, when clicked on the container, which
-            // is a default behaviour.
-            self.container.on('click', function(ev) {
-              ev = ev || window.event;
-              ev.cancelBubble = true;
-              ev.stopPropagation();
-            });
-
-            // On Click event to stop the process.
-            content.find('.bg-process-stop').off('click').on('click', self.stop_process.bind(this));
-          }
-
-          // TODO:: Formatted execution time
-          self.container.find('.pg-bg-etime').empty().append(
-            $('<span></span>').text(
-              String(self.execution_time)
-            )
-          ).append(
-            $('<span></span>').text(' ' + gettext('seconds'))
-          );
-
-          var $status_bar = $(self.container.find('.pg-bg-status'));
-          $status_bar.html(self.curr_status);
-          var $btn_stop_process = $(self.container.find('.bg-process-stop'));
-
-          // Enable Stop Process button only when process is running
-          if (parseInt(self.state) === 1) {
-            $btn_stop_process.attr('disabled', false);
-          } else {
-            $btn_stop_process.attr('disabled', true);
-          }
-        } else {
-          self.show_detailed_view.apply(self);
-        }
-      },
-
-      show_detailed_view: function() {
-        var self = this,
-          panel = this.panel,
-          is_new = false;
-
-        if (!self.panel) {
-          is_new = true;
-          panel = this.panel =
-            pgBrowser.BackgroundProcessObsorver.create_panel();
-          panel.title(gettext('Process Watcher - %s', self.type_desc));
-          panel.focus();
-        }
-
-        var container = panel.$container,
-          $logs = container.find('.bg-process-watcher'),
-          $header = container.find('.bg-process-details'),
-          $footer = container.find('.bg-process-footer'),
-          $btn_stop_process = container.find('.bg-process-stop'),
-          $btn_storage_manager = container.find('.bg-process-storage-manager');
-
-        if(self.current_storage_dir && isServerMode) { //for backup & exports with server mode, operate over storage manager
-
-          if($btn_storage_manager.length == 0) {
-            var str_storage_manager_btn = '<button id="bg-process-storage-manager" class="btn btn-secondary bg-process-storage-manager" title="Click to open file location" aria-label="Storage Manager" tabindex="0" disabled><span class="pg-font-icon icon-storage_manager" role="img"></span></button>&nbsp;';
-            container.find('.bg-process-details .bg-btn-section').prepend(str_storage_manager_btn);
-            $btn_storage_manager = container.find('.bg-process-storage-manager');
-          }
-
-          // Disable storage manager button only when process is running
-          if (parseInt(self.state) === 1) {
-            $btn_storage_manager.attr('disabled', true);
-          }
-          else {
-            $btn_storage_manager.attr('disabled', false);
-          }
-          // On Click event for storage manager button.
-          $btn_storage_manager.off('click').on('click', self.storage_manager.bind(this));
-        }
-
-        // Enable Stop Process button only when process is running
-        if (parseInt(self.state) === 1) {
-          $btn_stop_process.attr('disabled', false);
-        } else {
-          $btn_stop_process.attr('disabled', true);
-        }
-
-        // On Click event to stop the process.
-        $btn_stop_process.off('click').on('click', self.stop_process.bind(this));
-
-        if (is_new) {
-          // set logs
-          $logs.html(self.logs);
-          setTimeout(function() {
-            self.logs[0].scrollTop = self.logs[0].scrollHeight;
-          });
-          self.logs_loading = $('<li class="pg-bg-res-out loading-logs">' + gettext('Loading process logs...') + '</li>');
-          self.logs.append(self.logs_loading);
-          // set bgprocess detailed description
-          $header.find('.bg-detailed-desc').html(self.detailed_desc);
-        }
-
-        // set bgprocess start time
-        $header.find('.bg-process-stats .bgprocess-start-time').html(
-          self.stime
-        );
-
-        // set status
-        $footer.find('.bg-process-status').html(self.curr_status);
-
-        // set bgprocess execution time
-        $footer.find('.bg-process-exec-time p').empty().append(
-          $('<span></span>').text(
-            String(self.execution_time)
-          )
-        ).append(
-          $('<span></span>').text(' ' + gettext('seconds'))
-        );
-
-        if (is_new) {
-          self.details = true;
-          self.err = 0;
-          self.out = 0;
-          setTimeout(
-            function() {
-              self.status.apply(self);
-            }, 1000
-          );
-
-          var resize_log_container = function(logs, header, footer) {
-            var h = header.outerHeight() + footer.outerHeight();
-            logs.css('padding-bottom', h);
-          }.bind(panel, $logs, $header, $footer);
-
-          panel.on(wcDocker.EVENT.RESIZED, resize_log_container);
-          panel.on(wcDocker.EVENT.ATTACHED, resize_log_container);
-          panel.on(wcDocker.EVENT.DETACHED, resize_log_container);
-
-          resize_log_container();
-
-          panel.on(wcDocker.EVENT.CLOSED, function(process) {
-            process.panel = null;
-
-            process.details = false;
-            if (process.exit_code != null) {
-              process.acknowledge_server.apply(process);
-            }
-          }.bind(panel, this));
-        }
-      },
-
-      acknowledge_server: function() {
-        var self = this;
-        $.ajax({
-          type: 'PUT',
-          timeout: 30000,
-          url: self.bgprocess_url('acknowledge'),
-          cache: false,
-          async: true,
-          contentType: 'application/json',
-        })
-          .done(function(res) {
-            if (res.data && res.data.node) {
-              setTimeout(function() {
-                let _server = res.data.node,
-                  _server_path = '/browser/server_group_' + _server.gid + '/' + _server.id,
-                  _tree = pgBrowser.tree,
-                  _item = _tree.findNode(_server_path);
-
-                if (_item) {
-                  if(_server.status == true) {
-                    let _dom = _item.domNode;
-                    _tree.addIcon(_dom, {icon: _server.icon});
-                    let d = _tree.itemData(_dom);
-                    d.cloud_status = _server.cloud_status;
-                    _tree.update(_dom, d);
-                  }
-                  else {
-                    _tree.remove(_item.domNode);
-                    _tree.refresh(_item.domNode.parent);
-                  }
-                }
-
-              }, 10);
-            } else return;
-          })
-          .fail(function() {
-            console.warn(arguments);
-          });
-      },
-
-      stop_process: function() {
-        var self = this;
-        // Set the state to terminated.
-        self.state = 3;
-        $.ajax({
-          type: 'PUT',
-          timeout: 30000,
-          url: self.bgprocess_url('stop_process'),
-          cache: false,
-          async: true,
-          contentType: 'application/json',
-        })
-          .done(function() {
-            return;
-          })
-          .fail(function() {
-            console.warn(arguments);
-          });
-      },
-
-      storage_manager: function() {
-
-        var self = this;
-        if(self.current_storage_dir) {
-          pgAdmin.Tools.FileManager.openStorageManager(self.current_storage_dir);
-        }
-      },
-    });
-
-  _.extend(
-    pgBrowser.BackgroundProcessObsorver, {
-      bgprocesses: {},
-      init: function() {
-        var self = this;
-
-        if (self.initialized) {
-          return;
-        }
-        self.initialized = true;
-
-        setTimeout(
-          function() {
-            self.update_process_list.apply(self);
-          }, 1000
-        );
-
-        pgBrowser.Events.on(
-          'pgadmin-bgprocess:created',
-          function() {
-            setTimeout(
-              function() {
-                pgBrowser.BackgroundProcessObsorver.update_process_list(true);
-              }, 1000
-            );
-          }
-        );
-      },
-
-      update_process_list: function(recheck) {
-        var observer = this;
-
-        $.ajax({
-          type: 'GET',
-          timeout: 30000,
-          url: url_for('bgprocess.list'),
-          cache: false,
-          async: true,
-          contentType: 'application/json',
-        })
-          .done(function(res) {
-            if (!res || !_.isArray(res)) {
-              return;
-            }
-            for (var idx in res) {
-              var process = res[idx];
-              if ('id' in process) {
-                if (!(process.id in observer.bgprocesses)) {
-                  observer.bgprocesses[process.id] = new BGProcess(process);
-                }
-              }
-            }
-            if (recheck && res.length == 0) {
-            // Recheck after some more time
-              setTimeout(
-                function() {
-                  observer.update_process_list(false);
-                }, 3000
-              );
-            }
-          })
-          .fail(function() {
-          // FIXME:: What to do now?
-            console.warn(arguments);
-          });
-      },
-
-      create_panel: function() {
-        this.register_panel();
-
-        return pgBrowser.docker.addPanel(
-          'bg_process_watcher',
-          wcDocker.DOCK.FLOAT,
-          null, {
-            w: (screen.width < 700 ?
-              screen.width * 0.95 : screen.width * 0.5),
-            h: (screen.height < 500 ?
-              screen.height * 0.95 : screen.height * 0.5),
-            x: (screen.width < 700 ? '2%' : '25%'),
-            y: (screen.height < 500 ? '2%' : '25%'),
-          });
-      },
-
-      register_panel: function() {
-        var w = pgBrowser.docker,
-          panels = w.findPanels('bg_process_watcher');
-
-        if (panels && panels.length >= 1)
-          return;
-
-        var p = new pgBrowser.Panel({
-          name: 'bg_process_watcher',
-          showTitle: true,
-          isCloseable: true,
-          isPrivate: true,
-          isLayoutMember: false,
-          content: '<div class="bg-process-details">' +
-              '<div class="bg-detailed-desc"></div>' +
-              '<div class="bg-process-stats d-flex py-1">' +
-                '<div class="my-auto mr-2">' +
-                  '<span class="fa fa-clock fa-lg" role="img"></span>' +
-                '</div>' +
-                '<div class="pg-bg-etime my-auto mr-2">'+
-                  '<span>' + gettext('Start time') + ': <span class="bgprocess-start-time"></span>' +
-                  '</span>'+
-                '</div>' +
-                '<div class="ml-auto bg-btn-section">' +
-                  '<button type="button" class="btn btn-danger bg-process-stop" disabled><span class="fa fa-times-circle" role="img"></span>&nbsp;' + gettext('Stop Process') + '</button>' +
-                '</div>' +
-              '</div>' +
-            '</div>' +
-            '<div class="bg-process-watcher">' +
-            '</div>' +
-            '<div class="bg-process-footer p-2 d-flex">' +
-              '<div class="bg-process-status flex-grow-1">' +
-              '</div>' +
-              '<div class="bg-process-exec-time ml-4 my-auto">' +
-                '<div class="exec-div">' +
-                  '<span>' + gettext('Execution time') + ':</span><p></p>' +
-                '</div>' +
-              '</div>' +
-            '</div>',
-          onCreate: function(myPanel, $container) {
-            $container.addClass('pg-no-overflow p-2');
-          },
-        });
-        p.load(pgBrowser.docker);
-      },
-    });
-
-  return pgBrowser.BackgroundProcessObsorver;
-});
diff --git a/web/pgadmin/misc/bgprocess/static/js/index.js b/web/pgadmin/misc/bgprocess/static/js/index.js
new file mode 100644
index 000000000..b1dd50475
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/index.js
@@ -0,0 +1,22 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+import pgAdmin from 'sources/pgadmin';
+import pgBrowser from 'top/browser/static/js/browser';
+import BgProcessManager from './BgProcessManager';
+
+if (!pgAdmin.Browser) {
+  pgAdmin.Browser = {};
+}
+
+pgAdmin.Browser.BgProcessManager = BgProcessManager.getInstance(pgBrowser);
+
+module.exports = {
+  BgProcessManager: BgProcessManager,
+};
+
diff --git a/web/pgadmin/misc/bgprocess/static/js/showDetails.jsx b/web/pgadmin/misc/bgprocess/static/js/showDetails.jsx
new file mode 100644
index 000000000..5d2af220e
--- /dev/null
+++ b/web/pgadmin/misc/bgprocess/static/js/showDetails.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import pgAdmin from 'sources/pgadmin';
+import Theme from '../../../../static/js/Theme';
+import ProcessDetails from './ProcessDetails';
+import gettext from 'sources/gettext';
+
+export default function showDetails(p) {
+  let pgBrowser = pgAdmin.Browser;
+
+  // Register dialog panel
+  pgBrowser.Node.registerUtilityPanel();
+  let panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md),
+    j = panel.$container.find('.obj_properties').first();
+  panel.title(gettext('Process Watcher - %s', p.type_desc));
+  panel.focus();
+
+  panel.on(window.wcDocker.EVENT.CLOSED, ()=>{
+    ReactDOM.unmountComponentAtNode(j[0]);
+  });
+
+  ReactDOM.render(
+    <Theme>
+      <ProcessDetails
+        data={p}
+        closeModal={()=>{
+          panel.close();
+        }}
+      />
+    </Theme>, j[0]);
+}
diff --git a/web/pgadmin/misc/bgprocess/static/scss/_bgprocess.scss b/web/pgadmin/misc/bgprocess/static/scss/_bgprocess.scss
deleted file mode 100644
index 016e44842..000000000
--- a/web/pgadmin/misc/bgprocess/static/scss/_bgprocess.scss
+++ /dev/null
@@ -1,127 +0,0 @@
-$bgproc-container-pad: 2px;
-
-
-.ajs-bg-bgprocess.ajs-visible {
-  border: none;
-  padding: 0px !important;
-  text-align: left;
-  color: $color-fg;
-  min-width: 500px;
-  max-width: 500px;
-  .card {
-    border:none;
-    & .card-header {
-      border: $border-width solid $color-primary;
-      background: $color-primary;
-      color: $color-primary-fg;
-    }
-
-    & .card-body {
-      padding: 5px;
-      border: $border-width solid $card-border-color;
-      border-bottom-left-radius: $card-border-radius;
-      border-bottom-right-radius: $card-border-radius;
-    }
-  }
-}
-
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess {
-  background-color: $color-primary;
-  color: $color-primary-fg;
-  padding: $bgproc-container-pad;
-  text-align: left;
-  font-size: 0.9em;
-}
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess > .pg-bg-notify-header {
-  background-color:  $color-gray-dark;
-  margin: (-$bgproc-container-pad) (-$bgproc-container-pad) 5px;
-  padding: 5px;
-  padding-right: 20px;
-  white-space: pre-wrap;
-  text-align: center;
-  border-top-left-radius: 5px;
-  border-top-right-radius: 5px;
-}
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess > .pg-bg-notify-body {
-  font-family: $font-family-editor;
-  white-space: nowrap;
-  padding: 5px 0px;
-}
-
-.pg-bg-click {
-  color: $color-gray-lighter;
-  text-decoration: underline;
-  cursor: pointer;
-  padding: 5px 0px;
-}
-
-.pg-bg-click:hover {
-  color:  $color-gray-dark;
-}
-
-.pg-bg-res-out, .pg-bg-res-err {
-  white-space: pre-wrap;
-}
-
-.pg-bg-res-err {
-  color: $color-danger;
-}
-
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess > .pg-bg-status.bg-success,
-.bg-process-status .bg-bgprocess-success {
-  color: $color-success-light;
-  font-weight: bold;
-}
-
-.bg-process-status .bg-bgprocess-failed {
-  color: $color-danger;
-  font-weight: bold;
-}
-
-.ajs-bg-bgprocess > .pg-bg-bgprocess > .pg-bg-status.bg-failed {
-  color: $color-fg;
-  background-color: $color-danger-lighter;
-}
-
-.pg-panel-content div.bg-process-watcher {
-  height: 100%;
-  padding: 0px 0px 0px 0px;
-}
-
-.pg-bg-process-logs {
-  border: $border-width solid $input-border-color;
-  border-radius: $input-border-radius;
-  padding-inline-start: 1rem;
-}
-
-.pg-bg-cmd {
-  border: $border-width solid $input-border-color;
-  border-radius: $input-border-radius;
-  background: $input-disabled-bg;
-  word-break: break-word;
-}
-
-.pg-panel-content .bg-process-footer {
-  position: absolute;
-  bottom: 0;
-  right: 0px;
-  left: 0px;
-}
-
-.pg-bg-bgprocess .bg-close {
-  display: inline-block;
-  position: relative;
-  height: 25px;
-  width: 25px;
-  right: -12px;
-  padding: 2px;
-  border: 2px solid $color-primary;
-  border-radius: 4px;
-  opacity: 0.5;
-  background-color: $color-bg;
-  color: $color-danger;
-}
diff --git a/web/pgadmin/misc/cloud/__init__.py b/web/pgadmin/misc/cloud/__init__.py
index 83ec4d89e..1884dc055 100644
--- a/web/pgadmin/misc/cloud/__init__.py
+++ b/web/pgadmin/misc/cloud/__init__.py
@@ -130,11 +130,11 @@ def deploy_on_cloud():
 
     data = json.loads(request.data, encoding='utf-8')
     if data['cloud'] == 'rds':
-        status, resp = deploy_on_rds(data)
+        status, p, resp = deploy_on_rds(data)
     elif data['cloud'] == 'biganimal':
-        status, resp = deploy_on_biganimal(data)
+        status, p, resp = deploy_on_biganimal(data)
     elif data['cloud'] == 'azure':
-        status, resp = deploy_on_azure(data)
+        status, p, resp = deploy_on_azure(data)
     else:
         status = False
         resp = gettext('No cloud implementation.')
@@ -149,19 +149,22 @@ def deploy_on_cloud():
     # Return response
     return make_json_response(
         success=1,
-        data={'job_id': 1, 'node': {
-            '_id': resp['sid'],
-            '_pid': data['db_details']['gid'],
-            'connected': False,
-            '_type': 'server',
-            'icon': 'icon-server-cloud-deploy',
-            'id': 'server_{}'.format(resp['sid']),
-            'inode': True,
-            'label': resp['label'],
-            'server_type': 'pg',
-            'module': 'pgadmin.node.server',
-            'cloud_status': -1
-        }}
+        data={
+            'job_id': p.id,
+            'desc': p.desc.message,
+            'node': {
+                '_id': resp['sid'],
+                '_pid': data['db_details']['gid'],
+                'connected': False,
+                '_type': 'server',
+                'icon': 'icon-server-cloud-deploy',
+                'id': 'server_{}'.format(resp['sid']),
+                'inode': True,
+                'label': resp['label'],
+                'server_type': 'pg',
+                'module': 'pgadmin.node.server',
+                'cloud_status': -1
+            }}
     )
 
 
diff --git a/web/pgadmin/misc/cloud/azure/__init__.py b/web/pgadmin/misc/cloud/azure/__init__.py
index f60f96a8a..5d75cdb3a 100644
--- a/web/pgadmin/misc/cloud/azure/__init__.py
+++ b/web/pgadmin/misc/cloud/azure/__init__.py
@@ -721,10 +721,10 @@ def deploy_on_azure(data):
         else:
             session['azure_cache_files_list'] = {p.id: azure.azure_cache_name}
 
-        return True, {'label': _label, 'sid': sid}
+        return True, p, {'label': _label, 'sid': sid}
     except Exception as e:
         current_app.logger.exception(e)
-        return False, str(e)
+        return False, None, str(e)
     finally:
         del session['azure']['azure_obj']
 
diff --git a/web/pgadmin/misc/cloud/biganimal/__init__.py b/web/pgadmin/misc/cloud/biganimal/__init__.py
index b8a6a3f3b..a8a9ae3da 100644
--- a/web/pgadmin/misc/cloud/biganimal/__init__.py
+++ b/web/pgadmin/misc/cloud/biganimal/__init__.py
@@ -429,8 +429,8 @@ def deploy_on_biganimal(data):
         p.update_server_id(p.id, sid)
         p.start()
 
-        return True, {'label': _label, 'sid': sid}
+        return True, p, {'label': _label, 'sid': sid}
 
     except Exception as e:
         current_app.logger.exception(e)
-        return False, str(e)
+        return False, None, str(e)
diff --git a/web/pgadmin/misc/cloud/rds/__init__.py b/web/pgadmin/misc/cloud/rds/__init__.py
index fd618f8aa..5ce44ffe6 100644
--- a/web/pgadmin/misc/cloud/rds/__init__.py
+++ b/web/pgadmin/misc/cloud/rds/__init__.py
@@ -324,7 +324,7 @@ def deploy_on_rds(data):
         p.update_server_id(p.id, sid)
         p.start()
 
-        return True, {'label': _label, 'sid': sid}
+        return True, p, {'label': _label, 'sid': sid}
     except Exception as e:
         current_app.logger.exception(e)
-        return False, str(e)
+        return False, None, str(e)
diff --git a/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx b/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx
index 2255d6afc..eba8ef3e2 100644
--- a/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx
+++ b/web/pgadmin/misc/cloud/static/js/CloudWizard.jsx
@@ -153,7 +153,7 @@ export default function CloudWizard({ nodeInfo, nodeData, onClose}) {
     axiosApi.post(_url, post_data)
       .then((res) => {
         pgAdmin.Browser.Events.trigger('pgadmin:browser:tree:add', res.data.data.node, {'server_group': nodeInfo['server_group']});
-        pgAdmin.Browser.Events.trigger('pgadmin-bgprocess:created');
+        pgAdmin.Browser.BgProcessManager.startProcess(res.data.data.job_id, res.data.data.desc);
         onClose();
       })
       .catch((error) => {
diff --git a/web/pgadmin/misc/cloud/utils/__init__.py b/web/pgadmin/misc/cloud/utils/__init__.py
index 6d91ad8c3..ecf39c996 100644
--- a/web/pgadmin/misc/cloud/utils/__init__.py
+++ b/web/pgadmin/misc/cloud/utils/__init__.py
@@ -14,6 +14,7 @@ from pgadmin.misc.bgprocess.processes import IProcessDesc
 from pgadmin.utils import html
 from pgadmin.model import db, Server
 from flask_babel import gettext
+from pgadmin.utils import get_server
 
 
 def get_my_ip():
@@ -79,13 +80,15 @@ class CloudProcessDesc(IProcessDesc):
             self.provider, self.instance_name))
 
     def details(self, cmd, args):
-        res = '<div>' + self.message
-        res += '</div><div class="py-1">'
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(self.cmd)
-        res += '</div></div>'
-
-        return res
+        server = getattr(get_server(self.sid), 'name', "Not available")
+
+        return {
+            "message": self.message,
+            "cmd": cmd,
+            "server": server,
+            "object": self.instance_name,
+            "type": self.provider,
+        }
 
     @property
     def type_desc(self):
diff --git a/web/pgadmin/misc/dependencies/static/js/Dependencies.jsx b/web/pgadmin/misc/dependencies/static/js/Dependencies.jsx
index b4e0f0b19..7a23b0eca 100644
--- a/web/pgadmin/misc/dependencies/static/js/Dependencies.jsx
+++ b/web/pgadmin/misc/dependencies/static/js/Dependencies.jsx
@@ -80,21 +80,21 @@ export default function Dependencies({ nodeData, item, node, ...props }) {
     {
       Header: 'Type',
       accessor: 'type',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'Name',
       accessor: 'name',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'Restriction',
       accessor: 'field',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 280,
diff --git a/web/pgadmin/misc/dependents/static/js/Dependents.jsx b/web/pgadmin/misc/dependents/static/js/Dependents.jsx
index ef43ce79a..0c54c36cf 100644
--- a/web/pgadmin/misc/dependents/static/js/Dependents.jsx
+++ b/web/pgadmin/misc/dependents/static/js/Dependents.jsx
@@ -81,21 +81,21 @@ export default function Dependents({ nodeData, item, node, ...props }) {
     {
       Header: 'Type',
       accessor: 'type',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'Name',
       accessor: 'name',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'Restriction',
       accessor: 'field',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 280,
diff --git a/web/pgadmin/misc/properties/CollectionNodeProperties.jsx b/web/pgadmin/misc/properties/CollectionNodeProperties.jsx
index c4550ee7e..71a9b64dc 100644
--- a/web/pgadmin/misc/properties/CollectionNodeProperties.jsx
+++ b/web/pgadmin/misc/properties/CollectionNodeProperties.jsx
@@ -65,7 +65,7 @@ const useStyles = makeStyles((theme) => ({
     overflowX: 'auto !important'
   },
   dropButton: {
-    marginRight: '5px !important'
+    marginRight: '8px !important'
   },
   readOnlySwitch: {
     opacity: 0.75,
@@ -99,14 +99,14 @@ export function CollectionNodeView({
     {
       Header: 'properties',
       accessor: 'Properties',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'value',
       accessor: 'value',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
@@ -209,7 +209,7 @@ export function CollectionNodeView({
               column = {
                 Header: field.label,
                 accessor: field.id,
-                sortble: true,
+                sortable: true,
                 resizable: true,
                 disableGlobalFilter: false,
                 minWidth: 0,
@@ -222,7 +222,7 @@ export function CollectionNodeView({
               column = {
                 Header: field.label,
                 accessor: field.id,
-                sortble: true,
+                sortable: true,
                 resizable: true,
                 disableGlobalFilter: false,
                 minWidth: 0,
@@ -236,7 +236,7 @@ export function CollectionNodeView({
           column = {
             Header: field,
             accessor: field,
-            sortble: true,
+            sortable: true,
             resizable: true,
             disableGlobalFilter: false,
             minWidth: 0,
@@ -267,7 +267,7 @@ export function CollectionNodeView({
     }
   }, [itemNodeData, node, item, reload]);
 
-  const customHeader = () => {
+  const CustomHeader = () => {
     return (
       <Box >
         <PgIconButton
@@ -308,7 +308,7 @@ export function CollectionNodeView({
           (
             <PgTable
               isSelectRow={!('catalog' in treeNodeInfo) && (itemNodeData.label !== 'Catalogs') && _.isUndefined(node?.canSelect)}
-              customHeader={customHeader}
+              CustomHeader={CustomHeader}
               className={classes.autoResizer}
               columns={pgTableColumns}
               data={data}
diff --git a/web/pgadmin/misc/statistics/static/js/Statistics.jsx b/web/pgadmin/misc/statistics/static/js/Statistics.jsx
index 4da011dda..077edf258 100644
--- a/web/pgadmin/misc/statistics/static/js/Statistics.jsx
+++ b/web/pgadmin/misc/statistics/static/js/Statistics.jsx
@@ -61,7 +61,7 @@ function getColumn(data, singleLineStatistics) {
           column = {
             Header: row.name,
             accessor: row.name,
-            sortble: true,
+            sortable: true,
             resizable: true,
             disableGlobalFilter: false,
             sortType: ((rowA, rowB, id) => {
@@ -72,7 +72,7 @@ function getColumn(data, singleLineStatistics) {
           column = {
             Header: row.name,
             accessor: row.name,
-            sortble: true,
+            sortable: true,
             resizable: true,
             disableGlobalFilter: false,
           };
@@ -87,14 +87,14 @@ function getColumn(data, singleLineStatistics) {
       {
         Header: gettext('Statistics'),
         accessor: 'name',
-        sortble: true,
+        sortable: true,
         resizable: true,
         disableGlobalFilter: false,
       },
       {
         Header: 'Value',
         accessor: 'value',
-        sortble: true,
+        sortable: true,
         resizable: true,
         disableGlobalFilter: false,
       },
@@ -165,14 +165,14 @@ export default function Statistics({ nodeData, item, node, ...props }) {
     {
       Header: 'Statictics',
       accessor: 'name',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
     {
       Header: 'Value',
       accessor: 'value',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
     },
diff --git a/web/pgadmin/static/js/api_instance.js b/web/pgadmin/static/js/api_instance.js
index 4a4c65467..fdeb108bb 100644
--- a/web/pgadmin/static/js/api_instance.js
+++ b/web/pgadmin/static/js/api_instance.js
@@ -14,14 +14,13 @@ import axios from 'axios';
 /* Get the axios instance to call back end APIs.
 Do not import axios directly, instead use this */
 export default function getApiInstance(headers={}) {
-  const api = axios.create({
+  return axios.create({
     headers: {
       'Content-type': 'application/json',
       [pgAdmin.csrf_token_header]: pgAdmin.csrf_token,
       ...headers,
     }
   });
-  return api;
 }
 
 export function parseApiError(error) {
diff --git a/web/pgadmin/static/js/components/Buttons.jsx b/web/pgadmin/static/js/components/Buttons.jsx
index c446926c5..27dabf998 100644
--- a/web/pgadmin/static/js/components/Buttons.jsx
+++ b/web/pgadmin/static/js/components/Buttons.jsx
@@ -81,6 +81,17 @@ const useStyles = makeStyles((theme)=>({
   },
   noBorder: {
     border: 0,
+    color: 'inherit',
+    backgroundColor: 'transparent',
+    '&:hover': {
+      border: 0,
+      color: 'inherit',
+      backgroundColor: 'inherit',
+      filter: 'brightness(85%)',
+    },
+    '&.Mui-disabled': {
+      border: 0,
+    },
   }
 }));
 
diff --git a/web/pgadmin/static/js/components/FormComponents.jsx b/web/pgadmin/static/js/components/FormComponents.jsx
index 6b72869df..3265c767e 100644
--- a/web/pgadmin/static/js/components/FormComponents.jsx
+++ b/web/pgadmin/static/js/components/FormComponents.jsx
@@ -371,7 +371,8 @@ export const InputText = forwardRef(({
         maxLength: controlProps?.multiline ? null : maxlength,
         'aria-describedby': helpid,
         ...(type ? { pattern: !_.isUndefined(controlProps) && !_.isUndefined(controlProps.pattern) ? controlProps.pattern : patterns[type] } : {}),
-        style: inputStyle || {}
+        style: inputStyle || {},
+        autoComplete: 'new-password',
       }}
       readOnly={Boolean(readonly)}
       disabled={Boolean(disabled)}
@@ -1167,6 +1168,7 @@ const useStylesFormFooter = makeStyles((theme) => ({
     padding: theme.spacing(0.5),
     display: 'flex',
     alignItems: 'center',
+    minHeight: '36px',
   },
   containerSuccess: {
     borderColor: theme.palette.success.main,
@@ -1290,11 +1292,13 @@ FormInputSelectThemes.propTypes = {
 };
 
 
-export function NotifierMessage({ type = MESSAGE_TYPE.SUCCESS, message, closable = true, showIcon=true, textCenter=false, onClose = () => {/*This is intentional (SonarQube)*/ } }) {
+export function NotifierMessage({
+  type = MESSAGE_TYPE.SUCCESS, message, style, closable = true, showIcon=true, textCenter=false,
+  onClose = () => {/*This is intentional (SonarQube)*/ }}) {
   const classes = useStylesFormFooter();
 
   return (
-    <Box className={clsx(classes.container, classes[`container${type}`])}>
+    <Box className={clsx(classes.container, classes[`container${type}`])} style={style}>
       {showIcon && <FormIcon type={type} className={classes[`icon${type}`]} />}
       <Box className={textCenter ? classes.messageCenter : classes.message}>{HTMLReactParse(message || '')}</Box>
       {closable && <IconButton className={clsx(classes.closeButton, classes[`icon${type}`])} onClick={onClose}>
@@ -1311,6 +1315,7 @@ NotifierMessage.propTypes = {
   showIcon: PropTypes.bool,
   textCenter: PropTypes.bool,
   onClose: PropTypes.func,
+  style: PropTypes.object,
 };
 
 
diff --git a/web/pgadmin/static/js/components/PgTable.jsx b/web/pgadmin/static/js/components/PgTable.jsx
index dca323fcc..881e8ee3d 100644
--- a/web/pgadmin/static/js/components/PgTable.jsx
+++ b/web/pgadmin/static/js/components/PgTable.jsx
@@ -28,6 +28,8 @@ import _ from 'lodash';
 import gettext from 'sources/gettext';
 import SchemaView from '../SchemaView';
 import EmptyPanelMessage from './EmptyPanelMessage';
+import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
+import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
 
 /* eslint-disable react/display-name */
 const useStyles = makeStyles((theme) => ({
@@ -50,31 +52,18 @@ const useStyles = makeStyles((theme) => ({
     overflowX: 'hidden !important',
     overflow: 'overlay !important',
   },
-  customHeader:{
+  CustomHeader:{
     marginTop: '8px',
     marginLeft: '4px'
   },
-  searchBox: {
-    display: 'flex',
-    background: theme.palette.background.default
-  },
   warning: {
     backgroundColor: theme.palette.warning.main + '!important'
   },
   alert: {
     backgroundColor: theme.palette.error.main + '!important'
   },
-  searchPadding: {
-    flex: 2.5
-  },
   searchInput: {
-    flex: 1,
-    marginTop: 8,
-    borderLeft: 'none',
-    paddingLeft: 5,
-    marginRight: 8,
-    marginBottom: 8,
-
+    minWidth: '300px'
   },
   tableContainer: {
     overflowX: 'auto',
@@ -93,14 +82,18 @@ const useStyles = makeStyles((theme) => ({
     flexDirection: 'column',
     height: '100%',
   },
-  pgTableHeadar: {
+  pgTableContainer: {
     display: 'flex',
     flexGrow: 1,
-    overflow: 'hidden !important',
-    height: '100% !important',
-    flexDirection: 'column'
+    overflow: 'hidden',
+    flexDirection: 'column',
+    height: '100%',
+  },
+  pgTableHeader: {
+    display: 'flex',
+    background: theme.palette.background.default,
+    padding: '8px',
   },
-
   tableRowContent:{
     display: 'flex',
     flexDirection: 'column',
@@ -134,10 +127,9 @@ const useStyles = makeStyles((theme) => ({
     fontWeight: theme.typography.fontWeightBold,
     padding: theme.spacing(1, 0.5),
     textAlign: 'left',
-    overflowY: 'auto',
-    overflowX: 'hidden',
     alignContent: 'center',
     backgroundColor: theme.otherVars.tableBg,
+    overflow: 'hidden',
     ...theme.mixins.panelBorder.bottom,
     ...theme.mixins.panelBorder.right,
     ...theme.mixins.panelBorder.top,
@@ -221,7 +213,7 @@ IndeterminateCheckbox.propTypes = {
 };
 
 const ROW_HEIGHT = 35;
-export default function PgTable({ columns, data, isSelectRow, caveTable=true, ...props }) {
+export default function PgTable({ columns, data, isSelectRow, caveTable=true, schema, ExpandedComponent, sortOptions, ...props }) {
   // Use the state and functions returned from useTable to build your UI
   const classes = useStyles();
   const [searchVal, setSearchVal] = React.useState('');
@@ -277,6 +269,9 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
       defaultColumn,
       isSelectRow,
       autoResetSortBy: false,
+      initialState: {
+        sortBy: sortOptions || [],
+      }
     },
     useGlobalFilter,
     useSortBy,
@@ -333,7 +328,7 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
                   />
                 </div>
               ),
-              sortble: false,
+              sortable: false,
               width: 35,
               maxWidth: 35,
               minWidth: 0
@@ -403,7 +398,7 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
       }, [expandComplete]);
 
       return (
-        <div style={style} key={row.id} ref={rowRef}>
+        <div style={style} key={row.id} ref={rowRef} data-test="row-container">
           <div className={classes.tableRowContent}>
             <div {...row.getRowProps()} className={classes.tr}>
               {row.cells.map((cell) => {
@@ -421,7 +416,7 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
                   classNames.push(classes.alert);
                 }
                 return (
-                  <div key={cell.column.id} {...cell.getCellProps()} className={clsx(classNames, row.original.icon && row.original.icon[cell.column.id], row.original.icon[cell.column.id] && classes.cellIcon)}
+                  <div key={cell.column.id} {...cell.getCellProps()} className={clsx(classNames, cell.column?.dataClassName, row.original.icon?.[cell.column.id], row.original.icon?.[cell.column.id] && classes.cellIcon)}
                     title={_.isUndefined(cell.value) || _.isNull(cell.value) ? '': String(cell.value)}>
                     {cell.render('Cell')}
                   </div>
@@ -430,13 +425,14 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
             </div>
             {!_.isUndefined(row) && row.isExpanded && (
               <Box key={row.id} className={classes.expandedForm}>
-                <SchemaView
+                {schema && <SchemaView
                   getInitData={()=>Promise.resolve({})}
                   viewHelperProps={{ mode: 'properties' }}
-                  schema={props.schema[row.id]}
+                  schema={schema[row.id]}
                   showFooter={false}
                   onDataChange={()=>{setExpandComplete(true);}}
-                />
+                />}
+                {ExpandedComponent && <ExpandedComponent row={row} onExpandComplete={()=>setExpandComplete(true)}/>}
               </Box>
             )}
           </div>
@@ -447,24 +443,30 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
   );
   // Render the UI for your table
   return (
-    <Box className={classes.pgTableHeadar}>
-      <Box className={classes.searchBox}>
-        {props.customHeader && (<Box className={classes.customHeader}> <props.customHeader /></Box>)}
-        <Box className={classes.searchPadding}></Box>
-        <InputText
-          placeholder={'Search'}
-          className={classes.searchInput}
-          value={searchVal}
-          onChange={(val) => {
-            setSearchVal(val);
-          }}
-        />
+    <Box className={classes.pgTableContainer} data-test={props['data-test']}>
+      <Box className={classes.pgTableHeader}>
+        {props.CustomHeader && (<Box className={classes.customHeader}> <props.CustomHeader /></Box>)}
+        <Box marginLeft="auto">
+          <InputText
+            placeholder={'Search'}
+            className={classes.searchInput}
+            value={searchVal}
+            onChange={(val) => {
+              setSearchVal(val);
+            }}
+          />
+        </Box>
       </Box>
       <div className={classes.tableContainer}>
         <div {...getTableProps({style:{minWidth: totalColumnsWidth}})} className={clsx(classes.table, caveTable ? classes.caveTable : '')}>
           <div>
             {headerGroups.map((headerGroup) => (
-              <div key={''} {...headerGroup.getHeaderGroupProps()}>
+              <div key={''} {...headerGroup.getHeaderGroupProps((column)=>({
+                style: {
+                  ...column.style,
+                  height: '40px',
+                }
+              }))}>
                 {headerGroup.headers.map((column) => (
                   <div
                     key={column.id}
@@ -472,14 +474,14 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
                     className={clsx(classes.tableCellHeader, column.className)}
                   >
                     <div
-                      {...(column.sortble ? column.getSortByToggleProps() : {})}
+                      {...(column.sortable ? column.getSortByToggleProps() : {})}
                     >
                       {column.render('Header')}
                       <span>
                         {column.isSorted
                           ? column.isSortedDesc
-                            ? ' 🔽'
-                            : ' 🔼'
+                            ? <KeyboardArrowDownIcon style={{fontSize: '1.2rem'}} />
+                            : <KeyboardArrowUpIcon style={{fontSize: '1.2rem'}} />
                           : ''}
                       </span>
                     </div>
@@ -507,14 +509,13 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
                       height={height}
                       itemCount={rows.length}
                       itemSize={getRowHeight}
-                      sorted={props?.sortOptions}
                     >
                       {RenderRow}
                     </VariableSizeList>)}
                 </AutoSizer>
               </div>
             ) : (
-              <EmptyPanelMessage text={gettext('No record found')}/>
+              <EmptyPanelMessage text={gettext('No rows found')}/>
             )
           }
         </div>
@@ -526,7 +527,7 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, ..
 PgTable.propTypes = {
   stepId: PropTypes.number,
   height: PropTypes.number,
-  customHeader: PropTypes.func,
+  CustomHeader: PropTypes.func,
   className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
   caveTable: PropTypes.bool,
   fixedSizeList: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
@@ -544,8 +545,8 @@ PgTable.propTypes = {
   setSelectedRows: PropTypes.func,
   getSelectedRows: PropTypes.func,
   searchText: PropTypes.string,
-  type: PropTypes.string,
   sortOptions: PropTypes.array,
   schema: PropTypes.object,
-  rows: PropTypes.object
+  rows: PropTypes.object,
+  ExpandedComponent: PropTypes.node,
 };
diff --git a/web/pgadmin/static/js/custom_hooks.js b/web/pgadmin/static/js/custom_hooks.js
index a38088851..b77df8d70 100644
--- a/web/pgadmin/static/js/custom_hooks.js
+++ b/web/pgadmin/static/js/custom_hooks.js
@@ -13,6 +13,7 @@ export function useInterval(callback, delay) {
     }
 
     if(delay > -1) {
+      tick();
       let id = setInterval(tick, delay);
       return () => clearInterval(id);
     }
diff --git a/web/pgadmin/static/js/helpers/Notifier.jsx b/web/pgadmin/static/js/helpers/Notifier.jsx
index 95d837e8e..702c780ec 100644
--- a/web/pgadmin/static/js/helpers/Notifier.jsx
+++ b/web/pgadmin/static/js/helpers/Notifier.jsx
@@ -92,7 +92,7 @@ const useModalStyles = makeStyles((theme)=>({
   },
   margin: {
     marginLeft: '0.25rem',
-  }
+  },
 }));
 function AlertContent({text, confirm, okLabel=gettext('OK'), cancelLabel=gettext('Cancel'), onOkClick, onCancelClick}) {
   const classes = useModalStyles();
@@ -144,11 +144,10 @@ var Notifier = {
     }
   },
   _callNotify(msg, type, autoHideDuration) {
-    if (!_.isNull(autoHideDuration)) {
-      this.notify(<NotifierMessage type={type} message={msg} closable={false} />, autoHideDuration);
-    } else {
-      this.notify(<NotifierMessage type={type} message={msg}/>, null);
-    }
+    this.notify(
+      <NotifierMessage style={{maxWidth: '50vw'}} type={type} message={msg} closable={_.isNull(autoHideDuration) ? true : false} />,
+      autoHideDuration
+    );
   },
 
   pgRespErrorNotify(xhr, error, prefixMsg='') {
diff --git a/web/pgadmin/tools/backup/__init__.py b/web/pgadmin/tools/backup/__init__.py
index 0742e5882..8eebaa505 100644
--- a/web/pgadmin/tools/backup/__init__.py
+++ b/web/pgadmin/tools/backup/__init__.py
@@ -6,7 +6,6 @@
 # This software is released under the PostgreSQL Licence
 #
 ##########################################################################
-
 """Implements Backup Utility"""
 
 import simplejson as json
@@ -103,9 +102,12 @@ class BackupMessage(IProcessDesc):
             else:
                 self.cmd += cmd_arg(arg)
 
-    def get_server_details(self):
+    def get_server_name(self):
         s = get_server(self.sid)
 
+        if s is None:
+            return _("Not available")
+
         from pgadmin.utils.driver import get_driver
         driver = get_driver(PG_DEFAULT_DRIVER)
         manager = driver.connection_manager(self.sid)
@@ -113,7 +115,10 @@ class BackupMessage(IProcessDesc):
         host = manager.local_bind_host if manager.use_ssh_tunnel else s.host
         port = manager.local_bind_port if manager.use_ssh_tunnel else s.port
 
-        return s.name, host, port
+        s.name = html.safe_str(s.name)
+        host = html.safe_str(host)
+        port = html.safe_str(port)
+        return "{0} ({1}:{2})".format(s.name, host, port)
 
     @property
     def type_desc(self):
@@ -129,77 +134,45 @@ class BackupMessage(IProcessDesc):
 
     @property
     def message(self):
-        name, host, port = self.get_server_details()
-        name = html.safe_str(name)
-        host = html.safe_str(host)
-        port = html.safe_str(port)
+        server_name = self.get_server_name()
 
         if self.backup_type == BACKUP.OBJECT:
             return _(
                 "Backing up an object on the server '{0}' "
                 "from database '{1}'"
-            ).format(self.args_str.format(name, host, port),
+            ).format(server_name,
                      html.safe_str(self.database)
                      )
         if self.backup_type == BACKUP.GLOBALS:
             return _("Backing up the global objects on "
                      "the server '{0}'").format(
-                self.args_str.format(
-                    name, host, port
-                )
+                server_name
             )
         elif self.backup_type == BACKUP.SERVER:
             return _("Backing up the server '{0}'").format(
-                self.args_str.format(
-                    name, host, port
-                )
+                server_name
             )
         else:
             # It should never reach here.
             return "Unknown Backup"
 
     def details(self, cmd, args):
-        name, host, port = self.get_server_details()
-
-        res = '<div>'
-
+        server_name = self.get_server_name()
+        backup_type = _("Backup")
         if self.backup_type == BACKUP.OBJECT:
-            msg = _(
-                "Backing up an object on the server '{0}' "
-                "from database '{1}'..."
-            ).format(
-                self.args_str.format(
-                    name, host, port
-                ),
-                self.database
-            )
-            res += html.safe_str(msg)
+            backup_type = _("Backup Object")
         elif self.backup_type == BACKUP.GLOBALS:
-            msg = _("Backing up the global objects on "
-                    "the server '{0}'...").format(
-                self.args_str.format(
-                    name, host, port
-                )
-            )
-            res += html.safe_str(msg)
+            backup_type = _("Backup Globals")
         elif self.backup_type == BACKUP.SERVER:
-            msg = _("Backing up the server '{0}'...").format(
-                self.args_str.format(
-                    name, host, port
-                )
-            )
-            res += html.safe_str(msg)
-        else:
-            # It should never reach here.
-            res += "Backup"
-
-        res += '</div><div class="py-1">'
-        res += _("Running command:")
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(cmd + self.cmd)
-        res += '</div></div>'
+            backup_type = _("Backup Server")
 
-        return res
+        return {
+            "message": self.message,
+            "cmd": cmd + self.cmd,
+            "server": server_name,
+            "object": self.database,
+            "type": backup_type,
+        }
 
 
 @blueprint.route("/")
@@ -487,7 +460,7 @@ def create_backup_objects_job(sid):
 
     # Return response
     return make_json_response(
-        data={'job_id': jid, 'Success': 1}
+        data={'job_id': jid, 'desc': p.desc.message, 'Success': 1}
     )
 
 
diff --git a/web/pgadmin/tools/backup/static/js/backup.js b/web/pgadmin/tools/backup/static/js/backup.js
index afe0c50a9..ca2642fbe 100644
--- a/web/pgadmin/tools/backup/static/js/backup.js
+++ b/web/pgadmin/tools/backup/static/js/backup.js
@@ -181,7 +181,7 @@ define([
           gettext(data.errormsg)
         );
       } else {
-        pgBrowser.Events.trigger('pgadmin-bgprocess:created');
+        pgBrowser.BgProcessManager.startProcess(data.data.job_id, data.data.desc);
       }
     },
     url_for_utility_exists(id, params){
diff --git a/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py b/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py
index a5d5caa46..1b7c047fa 100644
--- a/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py
+++ b/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py
@@ -731,6 +731,7 @@ class BackupCreateJobTest(BaseTestGenerator):
                                   self.class_params['username'],
                                   self.class_params['database']
                                   )
+
         mock_result = server_mock.query.filter_by.return_value
         mock_result.first.return_value = mock_obj
 
@@ -743,7 +744,8 @@ class BackupCreateJobTest(BaseTestGenerator):
         batch_process_mock.return_value.start = MagicMock(
             return_value=True
         )
-
+        backup_message_mock.message = 'test'
+        batch_process_mock.return_value.desc = backup_message_mock
         export_password_env_mock.return_value = True
 
         server_response = server_utils.connect_server(self, self.server_id)
diff --git a/web/pgadmin/tools/backup/tests/test_backup_message.py b/web/pgadmin/tools/backup/tests/test_backup_message.py
index fb05fa869..673d9d1d8 100644
--- a/web/pgadmin/tools/backup/tests/test_backup_message.py
+++ b/web/pgadmin/tools/backup/tests/test_backup_message.py
@@ -125,12 +125,13 @@ class BackupMessageTest(BaseTestGenerator):
     ]
 
     @patch('pgadmin.utils.get_storage_directory')
-    @patch('pgadmin.tools.backup.BackupMessage.get_server_details')
-    def runTest(self, get_server_details_mock, get_storage_directory_mock):
-        get_server_details_mock.return_value = \
-            self.class_params['name'],\
-            self.class_params['host'],\
-            self.class_params['port']
+    @patch('pgadmin.tools.backup.BackupMessage.get_server_name')
+    def runTest(self, get_server_name_mock, get_storage_directory_mock):
+        get_server_name_mock.return_value = "{0} ({1}:{2})"\
+            .format(
+                self.class_params['name'],
+                self.class_params['host'],
+                self.class_params['port'])
 
         backup_obj = BackupMessage(
             self.class_params['type'],
@@ -149,4 +150,4 @@ class BackupMessageTest(BaseTestGenerator):
         obj_details = backup_obj.details(self.class_params['cmd'],
                                          self.class_params['args'])
 
-        self.assertIn(self.expected_details_cmd, obj_details)
+        self.assertEqual(self.expected_details_cmd, obj_details['cmd'])
diff --git a/web/pgadmin/tools/backup/tests/test_backup_utils.py b/web/pgadmin/tools/backup/tests/test_backup_utils.py
index 539115afb..6c134fb5a 100644
--- a/web/pgadmin/tools/backup/tests/test_backup_utils.py
+++ b/web/pgadmin/tools/backup/tests/test_backup_utils.py
@@ -56,16 +56,16 @@ def run_backup_job(tester, job_id, expected_params, assert_in, assert_not_in,
 
     backup_file = None
     if 'details' in the_process:
-        backup_det = the_process['details']
-        backup_file = backup_det[int(backup_det.find('--file')) +
-                                 8:int(backup_det.find('--host')) - 2]
+        backup_cmd = the_process['details']['cmd']
+        backup_file = backup_cmd[int(backup_cmd.find('--file')) +
+                                 8:int(backup_cmd.find('--host')) - 2]
 
     if expected_params['expected_cmd_opts']:
         for opt in expected_params['expected_cmd_opts']:
-            assert_in(opt, the_process['details'])
+            assert_in(opt, the_process['details']['cmd'])
     if expected_params['not_expected_cmd_opts']:
         for opt in expected_params['not_expected_cmd_opts']:
-            assert_not_in(opt, the_process['details'])
+            assert_not_in(opt, the_process['details']['cmd'])
 
     # Check the process details
     p_details = tester.get('/misc/bgprocess/{0}?_={1}'.format(
diff --git a/web/pgadmin/tools/backup/tests/test_batch_process.py b/web/pgadmin/tools/backup/tests/test_batch_process.py
index 2f376c746..cc6472f94 100644
--- a/web/pgadmin/tools/backup/tests/test_batch_process.py
+++ b/web/pgadmin/tools/backup/tests/test_batch_process.py
@@ -13,6 +13,12 @@ from pgadmin.tools.backup import BackupMessage, BACKUP
 from pgadmin.utils.route import BaseTestGenerator
 from pickle import dumps, loads
 from unittest.mock import patch, MagicMock
+from pgadmin.utils.preferences import Preferences
+import datetime
+import pytz
+
+start_time = \
+    datetime.datetime.now(pytz.utc).strftime("%Y-%m-%d %H:%M:%S.%f %z")
 
 
 class BatchProcessTest(BaseTestGenerator):
@@ -101,13 +107,14 @@ class BatchProcessTest(BaseTestGenerator):
          ))
     ]
 
-    @patch('pgadmin.tools.backup.BackupMessage.get_server_details')
+    @patch.object(Preferences, 'module', return_value=MagicMock())
+    @patch('pgadmin.tools.backup.BackupMessage.get_server_name')
     @patch('pgadmin.misc.bgprocess.processes.Popen')
     @patch('pgadmin.misc.bgprocess.processes.db')
     @patch('pgadmin.tools.backup.current_user')
     @patch('pgadmin.misc.bgprocess.processes.current_user')
     def runTest(self, current_user_mock, current_user, db_mock,
-                popen_mock, get_server_details_mock):
+                popen_mock, get_server_name_mock, pref_module):
         with self.app.app_context():
             current_user.id = 1
             current_user_mock.id = 1
@@ -137,10 +144,14 @@ class BatchProcessTest(BaseTestGenerator):
             db_mock.session.add.side_effect = db_session_add_mock
             db_mock.session.commit = MagicMock(return_value=True)
 
-            get_server_details_mock.return_value = \
-                self.class_params['name'], \
-                self.class_params['host'], \
-                self.class_params['port']
+            pref_module.return_value.preference.return_value.get.\
+                return_value = 5
+
+            get_server_name_mock.return_value = "{0} ({1}:{2})" \
+                .format(
+                    self.class_params['name'],
+                    self.class_params['host'],
+                    self.class_params['port'])
 
             backup_obj = BackupMessage(
                 self.class_params['type'],
@@ -171,13 +182,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         mock_result = process_mock.query.filter_by.return_value
         mock_result.first.return_value = TestMockProcess(
@@ -205,9 +218,7 @@ class BatchProcessTest(BaseTestGenerator):
     @patch('pgadmin.misc.bgprocess.processes.Process')
     @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
            'update_process_info')
-    @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
-           '_operate_orphan_process')
-    def _check_list(self, p, backup_obj, _operate_orphan_process_mock,
+    def _check_list(self, p, backup_obj,
                     update_process_info_mock, process_mock,
                     get_complete_file_path_mock, get_storage_directory_mock,
                     realpath_mock):
@@ -215,13 +226,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         process_mock.query.filter_by.return_value = [
             TestMockProcess(backup_obj,
@@ -232,7 +245,6 @@ class BatchProcessTest(BaseTestGenerator):
         get_complete_file_path_mock.return_value = self.class_params['bfile']
         realpath_mock.return_value = self.class_params['bfile']
         get_storage_directory_mock.return_value = '//'
-        _operate_orphan_process_mock.return_value = False
 
         ret_value = p.list()
         self.assertEqual(1, len(ret_value))
diff --git a/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx b/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
index 2706432be..9fedec760 100644
--- a/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
+++ b/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
@@ -65,21 +65,21 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
 
       Header: 'Object Type',
       accessor: 'object_type',
-      sortble: true,
+      sortable: true,
       resizable: false,
       disableGlobalFilter: true
     },
     {
       Header: 'Schema',
       accessor: 'nspname',
-      sortble: true,
+      sortable: true,
       resizable: false,
       disableGlobalFilter: true
     },
     {
       Header: 'Name',
       accessor: 'name_with_args',
-      sortble: true,
+      sortable: true,
       resizable: true,
       disableGlobalFilter: false,
       minWidth: 280
@@ -87,7 +87,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
     {
       Header: 'parameters',
       accessor: 'proargs',
-      sortble: false,
+      sortable: false,
       resizable: false,
       disableGlobalFilter: false,
       minWidth: 280,
@@ -96,7 +96,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
     {
       Header: 'Name',
       accessor: 'name',
-      sortble: false,
+      sortable: false,
       resizable: false,
       disableGlobalFilter: false,
       minWidth: 280,
@@ -105,7 +105,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
     {
       Header: 'ID',
       accessor: 'oid',
-      sortble: false,
+      sortable: false,
       resizable: false,
       disableGlobalFilter: false,
       minWidth: 280,
diff --git a/web/pgadmin/tools/import_export/__init__.py b/web/pgadmin/tools/import_export/__init__.py
index f30229da9..d7890bc7c 100644
--- a/web/pgadmin/tools/import_export/__init__.py
+++ b/web/pgadmin/tools/import_export/__init__.py
@@ -90,28 +90,27 @@ class IEMessage(IProcessDesc):
             else:
                 self._cmd += cmd_arg(arg)
 
-    def get_server_details(self):
+    def get_server_name(self):
         # Fetch the server details like hostname, port, roles etc
         s = Server.query.filter_by(
             id=self.sid, user_id=current_user.id
         ).first()
 
-        return s.name, s.host, s.port
+        if s is None:
+            return _("Not available")
+        return html.safe_str("{0} ({1}:{2})".format(s.name, s.host, s.port))
 
     @property
     def message(self):
         # Fetch the server details like hostname, port, roles etc
-        name, host, port = self.get_server_details()
-
         return _(
             "Copying table data '{0}.{1}' on database '{2}' "
-            "and server ({3}:{4})"
+            "and server '{3}'"
         ).format(
             html.safe_str(self.schema),
             html.safe_str(self.table),
             html.safe_str(self.database),
-            html.safe_str(host),
-            html.safe_str(port)
+            self.get_server_name()
         )
 
     @property
@@ -121,30 +120,14 @@ class IEMessage(IProcessDesc):
 
     def details(self, cmd, args):
         # Fetch the server details like hostname, port, roles etc
-        name, host, port = self.get_server_details()
-
-        res = '<div>'
-        res += _(
-            "Copying table data '{0}.{1}' on database '{2}' "
-            "for the server '{3}'"
-        ).format(
-            html.safe_str(self.schema),
-            html.safe_str(self.table),
-            html.safe_str(self.database),
-            "{0} ({1}:{2})".format(
-                html.safe_str(name),
-                html.safe_str(host),
-                html.safe_str(port)
-            )
-        )
-
-        res += '</div><div class="py-1">'
-        res += _("Running command:")
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(self._cmd)
-        res += '</div></div>'
-
-        return res
+        return {
+            "message": self.message,
+            "cmd": self._cmd,
+            "server": self.get_server_name(),
+            "object": "{0}/{1}.{2}".format(self.database, self.schema,
+                                           self.table),
+            "type": _("Import Data") if self.is_import else _("Export Data")
+        }
 
 
 @blueprint.route("/")
@@ -387,7 +370,7 @@ def create_import_export_job(sid):
 
     # Return response
     return make_json_response(
-        data={'job_id': jid, 'success': 1}
+        data={'job_id': jid, 'desc': p.desc.message, 'success': 1}
     )
 
 
diff --git a/web/pgadmin/tools/import_export/static/js/import_export.js b/web/pgadmin/tools/import_export/static/js/import_export.js
index 4cfebf480..d31d4590d 100644
--- a/web/pgadmin/tools/import_export/static/js/import_export.js
+++ b/web/pgadmin/tools/import_export/static/js/import_export.js
@@ -82,8 +82,7 @@ define([
           gettext(data.errormsg)
         );
       } else {
-        Notify.success(gettext('Import/Export job created.'));
-        pgBrowser.Events.trigger('pgadmin-bgprocess:created');
+        pgBrowser.BgProcessManager.startProcess(data.data.job_id, data.data.desc);
       }
     },
 
diff --git a/web/pgadmin/tools/import_export/tests/test_batch_process.py b/web/pgadmin/tools/import_export/tests/test_batch_process.py
index 45fd382cd..f01a0e72a 100644
--- a/web/pgadmin/tools/import_export/tests/test_batch_process.py
+++ b/web/pgadmin/tools/import_export/tests/test_batch_process.py
@@ -13,6 +13,12 @@ from pgadmin.tools.import_export import IEMessage
 from pgadmin.utils.route import BaseTestGenerator
 from pickle import dumps, loads
 from unittest.mock import patch, MagicMock
+from pgadmin.utils.preferences import Preferences
+import datetime
+import pytz
+
+start_time = \
+    datetime.datetime.now(pytz.utc).strftime("%Y-%m-%d %H:%M:%S.%f %z")
 
 
 class BatchProcessTest(BaseTestGenerator):
@@ -94,13 +100,14 @@ class BatchProcessTest(BaseTestGenerator):
          ))
     ]
 
-    @patch('pgadmin.tools.import_export.IEMessage.get_server_details')
+    @patch.object(Preferences, 'module', return_value=MagicMock())
+    @patch('pgadmin.tools.import_export.IEMessage.get_server_name')
     @patch('pgadmin.misc.bgprocess.processes.Popen')
     @patch('pgadmin.misc.bgprocess.processes.db')
     @patch('pgadmin.tools.import_export.current_user')
     @patch('pgadmin.misc.bgprocess.processes.current_user')
     def runTest(self, current_user_mock, current_user, db_mock,
-                popen_mock, get_server_details_mock):
+                popen_mock, get_server_name_mock, pref_module):
         with self.app.app_context():
             current_user.id = 1
             current_user_mock.id = 1
@@ -128,10 +135,14 @@ class BatchProcessTest(BaseTestGenerator):
             db_mock.session.add.side_effect = db_session_add_mock
             db_mock.session.commit = MagicMock(return_value=True)
 
-            get_server_details_mock.return_value = \
-                self.class_params['name'], \
-                self.class_params['host'], \
-                self.class_params['port']
+            pref_module.return_value.preference.return_value.get. \
+                return_value = 5
+
+            get_server_name_mock.return_value = "{0} ({1}:{2})" \
+                .format(
+                    self.class_params['name'],
+                    self.class_params['host'],
+                    self.class_params['port'])
 
             args = self.class_params['args'][1].format(
                 self.params['schema'],
@@ -176,13 +187,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         mock_result = process_mock.query.filter_by.return_value
         mock_result.first.return_value = TestMockProcess(
@@ -212,9 +225,7 @@ class BatchProcessTest(BaseTestGenerator):
     @patch('pgadmin.misc.bgprocess.processes.Process')
     @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
            'update_process_info')
-    @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
-           '_operate_orphan_process')
-    def _check_list(self, p, import_export_obj, _operate_orphan_process_mock,
+    def _check_list(self, p, import_export_obj,
                     update_process_info_mock, process_mock,
                     get_complete_file_path_mock, get_storage_directory_mock,
                     realpath_mock):
@@ -222,13 +233,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         process_mock.query.filter_by.return_value = [
             TestMockProcess(import_export_obj,
@@ -239,7 +252,6 @@ class BatchProcessTest(BaseTestGenerator):
         get_complete_file_path_mock.return_value = self.params['filename']
         realpath_mock.return_value = self.params['filename']
         get_storage_directory_mock.return_value = '//'
-        _operate_orphan_process_mock.return_value = False
 
         ret_value = p.list()
         self.assertEqual(1, len(ret_value))
diff --git a/web/pgadmin/tools/import_export/tests/test_import_export_create_job_unit_test.py b/web/pgadmin/tools/import_export/tests/test_import_export_create_job_unit_test.py
index ab81045a8..d45dfcb39 100644
--- a/web/pgadmin/tools/import_export/tests/test_import_export_create_job_unit_test.py
+++ b/web/pgadmin/tools/import_export/tests/test_import_export_create_job_unit_test.py
@@ -315,6 +315,8 @@ class IECreateJobTest(BaseTestGenerator):
             return_value=True
         )
 
+        ie_message_mock.message = 'test'
+        batch_process_mock.return_value.desc = ie_message_mock
         export_password_env_mock.return_value = True
 
         server_response = server_utils.connect_server(self, self.server_id)
diff --git a/web/pgadmin/tools/import_export/tests/test_import_export_message.py b/web/pgadmin/tools/import_export/tests/test_import_export_message.py
index 31ee76eed..5618dab54 100644
--- a/web/pgadmin/tools/import_export/tests/test_import_export_message.py
+++ b/web/pgadmin/tools/import_export/tests/test_import_export_message.py
@@ -39,7 +39,7 @@ class IEMessageTest(BaseTestGenerator):
                  ]
              ),
              expected_msg="Copying table data '{0}.{1}' on "
-                          "database '{2}' and server ({3}:{4})",
+                          "database '{2}' and server '{3} ({4}:{5})'",
              expected_storage_dir='/'
 
          )),
@@ -66,7 +66,7 @@ class IEMessageTest(BaseTestGenerator):
                  ]
              ),
              expected_msg="Copying table data '{0}.{1}' on "
-                          "database '{2}' and server ({3}:{4})",
+                          "database '{2}' and server '{3} ({4}:{5})'",
              expected_storage_dir='/test_path'
 
          )),
@@ -75,17 +75,17 @@ class IEMessageTest(BaseTestGenerator):
     @patch('os.path.realpath')
     @patch('pgadmin.misc.bgprocess.processes.get_storage_directory')
     @patch('pgadmin.misc.bgprocess.processes.get_complete_file_path')
-    @patch('pgadmin.tools.import_export.IEMessage.get_server_details')
-    def runTest(self, get_server_details_mock,
+    @patch('pgadmin.tools.import_export.IEMessage.get_server_name')
+    def runTest(self, get_server_name_mock,
                 get_complete_file_path_mock,
                 get_storage_directory_mock,
                 realpath_mock):
 
-        name = self.class_params['name']
-        host = self.class_params['host']
-        port = self.class_params['port']
-
-        get_server_details_mock.return_value = name, host, port
+        get_server_name_mock.return_value = "{0} ({1}:{2})" \
+            .format(
+                self.class_params['name'],
+                self.class_params['host'],
+                self.class_params['port'])
 
         get_complete_file_path_mock.return_value \
             = self.class_params['filename']
@@ -109,6 +109,7 @@ class IEMessageTest(BaseTestGenerator):
             self.class_params['schema'],
             self.class_params['table'],
             self.class_params['database'],
+            self.class_params['name'],
             self.class_params['host'],
             self.class_params['port']
         )
@@ -120,11 +121,11 @@ class IEMessageTest(BaseTestGenerator):
         obj_details = import_export_obj.details(self.class_params['cmd'],
                                                 self.class_params['args'])
 
-        self.assertIn(self.class_params['schema'], obj_details)
-        self.assertIn(self.class_params['table'], obj_details)
-        self.assertIn(self.class_params['database'], obj_details)
-        self.assertIn(self.class_params['host'], obj_details)
-        self.assertIn(str(self.class_params['port']), obj_details)
+        self.assertIn(self.class_params['schema'], obj_details['message'])
+        self.assertIn(self.class_params['table'], obj_details['message'])
+        self.assertIn(self.class_params['database'], obj_details['message'])
+        self.assertIn(self.class_params['host'], obj_details['message'])
+        self.assertIn(str(self.class_params['port']), obj_details['message'])
 
         if config.SERVER_MODE is False:
             self.skipTest(
diff --git a/web/pgadmin/tools/import_export/tests/test_import_export_utils.py b/web/pgadmin/tools/import_export/tests/test_import_export_utils.py
index f3098f736..9ac25a2c0 100644
--- a/web/pgadmin/tools/import_export/tests/test_import_export_utils.py
+++ b/web/pgadmin/tools/import_export/tests/test_import_export_utils.py
@@ -70,7 +70,7 @@ def run_import_export_job(tester, job_id, expected_params, assert_in,
 
     io_file = None
     if 'details' in the_process:
-        io_det = the_process['details']
+        io_det = the_process['details']['message']
 
         temp_io_det = io_det.upper()
 
@@ -82,10 +82,10 @@ def run_import_export_job(tester, job_id, expected_params, assert_in,
 
     if expected_params['expected_cmd_opts']:
         for opt in expected_params['expected_cmd_opts']:
-            assert_in(opt, the_process['details'])
+            assert_in(opt, the_process['details']['cmd'])
     if expected_params['not_expected_cmd_opts']:
         for opt in expected_params['not_expected_cmd_opts']:
-            assert_not_in(opt, the_process['details'])
+            assert_not_in(opt, the_process['details']['cmd'])
 
     # Check the process details
     p_details = tester.get('/misc/bgprocess/{0}?_={1}'.format(
diff --git a/web/pgadmin/tools/maintenance/__init__.py b/web/pgadmin/tools/maintenance/__init__.py
index f84da2587..facc8aa18 100644
--- a/web/pgadmin/tools/maintenance/__init__.py
+++ b/web/pgadmin/tools/maintenance/__init__.py
@@ -63,6 +63,9 @@ class Message(IProcessDesc):
     def get_server_name(self):
         s = get_server(self.sid)
 
+        if s is None:
+            return _("Not available")
+
         from pgadmin.utils.driver import get_driver
         driver = get_driver(PG_DEFAULT_DRIVER)
         manager = driver.connection_manager(self.sid)
@@ -129,15 +132,13 @@ class Message(IProcessDesc):
         return res
 
     def details(self, cmd, args):
-
-        res = '<div>' + self.message
-        res += '</div><div class="py-1">'
-        res += _("Running Query:")
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(self.query)
-        res += '</div></div>'
-
-        return res
+        return {
+            "message": self.message,
+            "query": self.query,
+            "server": self.get_server_name(),
+            "object": self.data['database'],
+            "type": self.type_desc,
+        }
 
 
 @blueprint.route("/")
@@ -272,7 +273,7 @@ def create_maintenance_job(sid, did):
 
     # Return response
     return make_json_response(
-        data={'job_id': jid, 'status': True,
+        data={'job_id': jid, 'desc': p.desc.message, 'status': True,
               'info': _('Maintenance job created.')}
     )
 
diff --git a/web/pgadmin/tools/maintenance/static/js/maintenance.js b/web/pgadmin/tools/maintenance/static/js/maintenance.js
index cbf9388e0..971653e8e 100644
--- a/web/pgadmin/tools/maintenance/static/js/maintenance.js
+++ b/web/pgadmin/tools/maintenance/static/js/maintenance.js
@@ -92,8 +92,7 @@ define([
           gettext(data.errormsg)
         );
       } else {
-        Notify.success(data.data.info);
-        pgBrowser.Events.trigger('pgadmin-bgprocess:created');
+        pgBrowser.BgProcessManager.startProcess(data.data.job_id, data.data.desc);
       }
     },
     setExtraParameters(treeInfo) {
diff --git a/web/pgadmin/tools/maintenance/tests/test_batch_process_maintenance.py b/web/pgadmin/tools/maintenance/tests/test_batch_process_maintenance.py
index 1d094ca79..741063957 100644
--- a/web/pgadmin/tools/maintenance/tests/test_batch_process_maintenance.py
+++ b/web/pgadmin/tools/maintenance/tests/test_batch_process_maintenance.py
@@ -13,6 +13,12 @@ from pgadmin.tools.maintenance import Message
 from pgadmin.utils.route import BaseTestGenerator
 from pickle import dumps, loads
 from unittest.mock import patch, MagicMock
+from pgadmin.utils.preferences import Preferences
+import datetime
+import pytz
+
+start_time = \
+    datetime.datetime.now(pytz.utc).strftime("%Y-%m-%d %H:%M:%S.%f %z")
 
 
 class BatchProcessTest(BaseTestGenerator):
@@ -53,13 +59,14 @@ class BatchProcessTest(BaseTestGenerator):
          ))
     ]
 
+    @patch.object(Preferences, 'module', return_value=MagicMock())
     @patch('pgadmin.tools.maintenance.Message.get_server_name')
     @patch('pgadmin.misc.bgprocess.processes.Popen')
     @patch('pgadmin.misc.bgprocess.processes.db')
     @patch('pgadmin.tools.maintenance.Server')
     @patch('pgadmin.misc.bgprocess.processes.current_user')
     def runTest(self, current_user_mock, server_mock, db_mock,
-                popen_mock, get_server_name_mock):
+                popen_mock, get_server_name_mock, pref_module):
         get_server_name_mock.return_value = self.SERVER_NAME
         with self.app.app_context():
             current_user_mock.id = 1
@@ -87,6 +94,9 @@ class BatchProcessTest(BaseTestGenerator):
             db_mock.session.add.side_effect = db_session_add_mock
             db_mock.session.commit = MagicMock(return_value=True)
 
+            pref_module.return_value.preference.return_value.get. \
+                return_value = 5
+
             maintenance_obj = Message(
                 self.class_params['sid'],
                 self.class_params['data'],
@@ -114,13 +124,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         mock_result = process_mock.query.filter_by.return_value
         mock_result.first.return_value = TestMockProcess(
@@ -146,21 +158,21 @@ class BatchProcessTest(BaseTestGenerator):
     @patch('pgadmin.misc.bgprocess.processes.Process')
     @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
            'update_process_info')
-    @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
-           '_operate_orphan_process')
-    def _check_list(self, p, maintenance_obj, _operate_orphan_process_mock,
+    def _check_list(self, p, maintenance_obj,
                     update_process_info_mock, process_mock):
         class TestMockProcess():
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         process_mock.query.filter_by.return_value = [
             TestMockProcess(maintenance_obj,
@@ -169,7 +181,6 @@ class BatchProcessTest(BaseTestGenerator):
         ]
 
         update_process_info_mock.return_value = [True, True]
-        _operate_orphan_process_mock.return_value = False
 
         ret_value = p.list()
         self.assertEqual(1, len(ret_value))
diff --git a/web/pgadmin/tools/maintenance/tests/test_create_maintenance_job.py b/web/pgadmin/tools/maintenance/tests/test_create_maintenance_job.py
index e6b940c0a..6e6be3333 100644
--- a/web/pgadmin/tools/maintenance/tests/test_create_maintenance_job.py
+++ b/web/pgadmin/tools/maintenance/tests/test_create_maintenance_job.py
@@ -101,7 +101,7 @@ class MaintenanceJobTest(BaseTestGenerator):
         self.assertTrue(the_process['exit_code'] in
                         self.expected_exit_code)
 
-        self.assertIn(self.expected_cmd, the_process['details'])
+        self.assertIn(self.expected_cmd, the_process['details']['query'])
 
         # Check the process details
         p_details = self.tester.get('/misc/bgprocess/{0}?_={1}'.format(
diff --git a/web/pgadmin/tools/maintenance/tests/test_maintenance_create_job_unit_test.py b/web/pgadmin/tools/maintenance/tests/test_maintenance_create_job_unit_test.py
index 0a71ff352..a29343303 100644
--- a/web/pgadmin/tools/maintenance/tests/test_maintenance_create_job_unit_test.py
+++ b/web/pgadmin/tools/maintenance/tests/test_maintenance_create_job_unit_test.py
@@ -177,6 +177,8 @@ class MaintenanceCreateJobTest(BaseTestGenerator):
         batch_process_mock.return_value.start = MagicMock(
             return_value=True
         )
+        message_mock.message = 'test'
+        batch_process_mock.return_value.desc = message_mock
         export_password_env_mock.return_value = True
 
         server_response = server_utils.connect_server(self, self.server_id)
diff --git a/web/pgadmin/tools/maintenance/tests/test_maintenance_message.py b/web/pgadmin/tools/maintenance/tests/test_maintenance_message.py
index 394f9eb7d..7a237aad5 100644
--- a/web/pgadmin/tools/maintenance/tests/test_maintenance_message.py
+++ b/web/pgadmin/tools/maintenance/tests/test_maintenance_message.py
@@ -128,4 +128,4 @@ class MaintenanceMessageTest(BaseTestGenerator):
 
         # Check the command
         obj_details = maintenance_obj.details(self.class_params['cmd'], None)
-        self.assertIn(self.expected_details_cmd, obj_details)
+        self.assertIn(self.expected_details_cmd, obj_details['query'])
diff --git a/web/pgadmin/tools/restore/__init__.py b/web/pgadmin/tools/restore/__init__.py
index 76f4d9df3..e823bdf06 100644
--- a/web/pgadmin/tools/restore/__init__.py
+++ b/web/pgadmin/tools/restore/__init__.py
@@ -56,9 +56,10 @@ blueprint = RestoreModule(
 
 
 class RestoreMessage(IProcessDesc):
-    def __init__(self, _sid, _bfile, *_args):
+    def __init__(self, _sid, _bfile, *_args, **_kwargs):
         self.sid = _sid
         self.bfile = _bfile
+        self.database = _kwargs['database'] if 'database' in _kwargs else None
         self.cmd = ''
 
         def cmd_arg(x):
@@ -75,11 +76,12 @@ class RestoreMessage(IProcessDesc):
             else:
                 self.cmd += cmd_arg(arg)
 
-    def get_server_details(self):
-
-        # Fetch the server details like hostname, port, roles etc
+    def get_server_name(self):
         s = get_server(self.sid)
 
+        if s is None:
+            return _("Not available")
+
         from pgadmin.utils.driver import get_driver
         driver = get_driver(PG_DEFAULT_DRIVER)
         manager = driver.connection_manager(self.sid)
@@ -87,42 +89,28 @@ class RestoreMessage(IProcessDesc):
         host = manager.local_bind_host if manager.use_ssh_tunnel else s.host
         port = manager.local_bind_port if manager.use_ssh_tunnel else s.port
 
-        return s.name, host, port
+        s.name = html.safe_str(s.name)
+        host = html.safe_str(host)
+        port = html.safe_str(port)
+        return "{0} ({1}:{2})".format(s.name, host, port)
 
     @property
     def message(self):
-        name, host, port = self.get_server_details()
-
-        return _("Restoring backup on the server '{0}'").format(
-            "{0} ({1}:{2})".format(
-                html.safe_str(name),
-                html.safe_str(host),
-                html.safe_str(port)
-            ),
-        )
+        return _("Restoring backup on the server '{0}'")\
+            .format(self.get_server_name())
 
     @property
     def type_desc(self):
         return _("Restoring backup on the server")
 
     def details(self, cmd, args):
-        name, host, port = self.get_server_details()
-        res = '<div>'
-
-        res += html.safe_str(
-            _(
-                "Restoring backup on the server '{0}'..."
-            ).format(
-                "{0} ({1}:{2})".format(name, host, port)
-            )
-        )
-
-        res += '</div><div class="py-1">'
-        res += _("Running command:")
-        res += '<div class="pg-bg-cmd enable-selection p-1">'
-        res += html.safe_str(cmd + self.cmd)
-        res += '</div></div>'
-        return res
+        return {
+            "message": self.message,
+            "cmd": cmd + self.cmd,
+            "server": self.get_server_name(),
+            "object": getattr(self, 'database', ''),
+            "type": _("Restore"),
+        }
 
 
 @blueprint.route("/")
@@ -409,7 +397,8 @@ def create_restore_job(sid):
                 data['file'].encode('utf-8') if hasattr(
                     data['file'], 'encode'
                 ) else data['file'],
-                *args
+                *args,
+                database=data['database']
             ),
             cmd=utility, args=args
         )
@@ -434,7 +423,7 @@ def create_restore_job(sid):
         )
     # Return response
     return make_json_response(
-        data={'job_id': jid, 'Success': 1}
+        data={'job_id': jid, 'desc': p.desc.message, 'Success': 1}
     )
 
 
diff --git a/web/pgadmin/tools/restore/static/js/restore.js b/web/pgadmin/tools/restore/static/js/restore.js
index 3ad192cf5..0f33ef334 100644
--- a/web/pgadmin/tools/restore/static/js/restore.js
+++ b/web/pgadmin/tools/restore/static/js/restore.js
@@ -97,7 +97,7 @@ define('tools.restore', [
           gettext(data.errormsg)
         );
       } else {
-        pgBrowser.Events.trigger('pgadmin-bgprocess:created');
+        pgBrowser.BgProcessManager.startProcess(data.data.job_id, data.data.desc);
       }
     },
     setExtraParameters: function(treeInfo, nodeData) {
diff --git a/web/pgadmin/tools/restore/tests/test_batch_process.py b/web/pgadmin/tools/restore/tests/test_batch_process.py
index 535b46617..6ce67ca3b 100644
--- a/web/pgadmin/tools/restore/tests/test_batch_process.py
+++ b/web/pgadmin/tools/restore/tests/test_batch_process.py
@@ -13,6 +13,12 @@ from pgadmin.tools.restore import RestoreMessage
 from pgadmin.utils.route import BaseTestGenerator
 from pickle import dumps, loads
 from unittest.mock import patch, MagicMock
+from pgadmin.utils.preferences import Preferences
+import datetime
+import pytz
+
+start_time = \
+    datetime.datetime.now(pytz.utc).strftime("%Y-%m-%d %H:%M:%S.%f %z")
 
 
 class BatchProcessTest(BaseTestGenerator):
@@ -46,13 +52,14 @@ class BatchProcessTest(BaseTestGenerator):
          ))
     ]
 
-    @patch('pgadmin.tools.restore.RestoreMessage.get_server_details')
+    @patch.object(Preferences, 'module', return_value=MagicMock())
+    @patch('pgadmin.tools.restore.RestoreMessage.get_server_name')
     @patch('pgadmin.misc.bgprocess.processes.Popen')
     @patch('pgadmin.misc.bgprocess.processes.db')
     @patch('pgadmin.tools.restore.current_user')
     @patch('pgadmin.misc.bgprocess.processes.current_user')
     def runTest(self, current_user_mock, current_user, db_mock,
-                popen_mock, get_server_details_mock):
+                popen_mock, get_server_name_mock, pref_module):
         with self.app.app_context():
             current_user.id = 1
             current_user_mock.id = 1
@@ -75,10 +82,14 @@ class BatchProcessTest(BaseTestGenerator):
                                      self.class_params['database']
                                  ))
 
-            get_server_details_mock.return_value = \
-                self.class_params['name'], \
-                self.class_params['host'], \
-                self.class_params['port']
+            pref_module.return_value.preference.return_value.get. \
+                return_value = 5
+
+            get_server_name_mock.return_value = "{0} ({1}:{2})" \
+                .format(
+                    self.class_params['name'],
+                    self.class_params['host'],
+                    self.class_params['port'])
 
             db_mock.session.add.side_effect = db_session_add_mock
             db_mock.session.commit = MagicMock(return_value=True)
@@ -110,13 +121,15 @@ class BatchProcessTest(BaseTestGenerator):
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         mock_result = process_mock.query.filter_by.return_value
         mock_result.first.return_value = TestMockProcess(
@@ -142,21 +155,21 @@ class BatchProcessTest(BaseTestGenerator):
     @patch('pgadmin.misc.bgprocess.processes.Process')
     @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
            'update_process_info')
-    @patch('pgadmin.misc.bgprocess.processes.BatchProcess.'
-           '_operate_orphan_process')
-    def _check_list(self, p, restore_obj, _operate_orphan_process_mock,
+    def _check_list(self, p, restore_obj,
                     update_process_info_mock, process_mock):
         class TestMockProcess():
             def __init__(self, desc, args, cmd):
                 self.pid = 1
                 self.exit_code = 1
-                self.start_time = '2018-04-17 06:18:56.315445 +0000'
+                self.start_time = start_time
                 self.end_time = None
                 self.desc = dumps(desc)
                 self.arguments = " ".join(args)
                 self.command = cmd
                 self.acknowledge = None
                 self.process_state = 0
+                self.utility_pid = 123
+                self.server_id = None
 
         process_mock.query.filter_by.return_value = [
             TestMockProcess(restore_obj,
@@ -165,7 +178,6 @@ class BatchProcessTest(BaseTestGenerator):
         ]
 
         update_process_info_mock.return_value = [True, True]
-        _operate_orphan_process_mock.return_value = False
 
         ret_value = p.list()
         self.assertEqual(1, len(ret_value))
diff --git a/web/pgadmin/tools/restore/tests/test_create_restore_job.py b/web/pgadmin/tools/restore/tests/test_create_restore_job.py
index 45feed0c0..fad9f54e4 100644
--- a/web/pgadmin/tools/restore/tests/test_create_restore_job.py
+++ b/web/pgadmin/tools/restore/tests/test_create_restore_job.py
@@ -143,10 +143,10 @@ class RestoreJobTest(BaseTestGenerator):
 
         if self.expected_cmd_opts:
             for opt in self.expected_cmd_opts:
-                self.assertIn(opt, the_process['details'])
+                self.assertIn(opt, the_process['details']['cmd'])
         if self.not_expected_cmd_opts:
             for opt in self.not_expected_cmd_opts:
-                self.assertNotIn(opt, the_process['details'])
+                self.assertNotIn(opt, the_process['details']['cmd'])
 
         # Check the process details
         p_details = self.tester.get('/misc/bgprocess/{0}?_={1}'.format(
diff --git a/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py b/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py
index 811603a78..5fce7895c 100644
--- a/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py
+++ b/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py
@@ -348,6 +348,8 @@ class RestoreCreateJobTest(BaseTestGenerator):
             return_value=True
         )
 
+        restore_message_mock.message = 'test'
+        batch_process_mock.return_value.desc = restore_message_mock
         export_password_env_mock.return_value = True
 
         server_response = server_utils.connect_server(self, self.server_id)
diff --git a/web/pgadmin/tools/restore/tests/test_restore_message.py b/web/pgadmin/tools/restore/tests/test_restore_message.py
index 6e2cbbe04..408e5d98d 100644
--- a/web/pgadmin/tools/restore/tests/test_restore_message.py
+++ b/web/pgadmin/tools/restore/tests/test_restore_message.py
@@ -49,12 +49,13 @@ class RestoreMessageTest(BaseTestGenerator):
          ))
     ]
 
-    @patch('pgadmin.tools.restore.RestoreMessage.get_server_details')
-    def runTest(self, get_server_details_mock):
-        get_server_details_mock.return_value = \
-            self.class_params['name'],\
-            self.class_params['host'],\
-            self.class_params['port']
+    @patch('pgadmin.tools.restore.RestoreMessage.get_server_name')
+    def runTest(self, get_server_name_mock):
+        get_server_name_mock.return_value = "{0} ({1}:{2})" \
+            .format(
+                self.class_params['name'],
+                self.class_params['host'],
+                self.class_params['port'])
 
         restore_obj = RestoreMessage(
             self.class_params['sid'],
@@ -68,4 +69,4 @@ class RestoreMessageTest(BaseTestGenerator):
         # Check the command
         obj_details = restore_obj.details(self.class_params['cmd'],
                                           self.class_params['args'])
-        self.assertIn(self.expected_details_cmd, obj_details)
+        self.assertEqual(self.expected_details_cmd, obj_details['cmd'])
diff --git a/web/regression/feature_utils/locators.py b/web/regression/feature_utils/locators.py
index 8088bc06a..51862f2ae 100644
--- a/web/regression/feature_utils/locators.py
+++ b/web/regression/feature_utils/locators.py
@@ -86,8 +86,10 @@ class NavMenuLocators:
         "//div[contains(@class,'wcFrameTitleBar')]" \
         "//div[contains(text(),'Process Watcher')]"
 
-    process_watcher_detailed_command_canvas_css = \
-        ".bg-process-details .bg-detailed-desc"
+    process_watcher_detailed_message_css = \
+        "div[data-test='process-details'] div[data-test='process-message']"
+    process_watcher_detailed_command_css = \
+        "div[data-test='process-details'] div[data-test='process-cmd']"
 
     process_watcher_close_button_xpath = \
         "//div[contains(@class,'wcFloating')]//" \
@@ -107,6 +109,8 @@ class NavMenuLocators:
 
     rcdock_tab = "div.dock-tab-btn[id$='{0}']"
 
+    process_start_close_selector = "div[data-test='process-popup-start'] button[data-label='Close']"
+    process_end_close_selector = "div[data-test='process-popup-end'] button[data-label='Close']"
     process_watcher_error_close_xpath = \
         ".btn.btn-sm-sq.btn-primary.pg-bg-close > i"
 
diff --git a/web/regression/javascript/fake_endpoints.js b/web/regression/javascript/fake_endpoints.js
index 79686fe55..b06219974 100644
--- a/web/regression/javascript/fake_endpoints.js
+++ b/web/regression/javascript/fake_endpoints.js
@@ -36,5 +36,9 @@ define(function () {
     'file_manager.save_file_dialog_view': '/file_manager/save_file_dialog_view/<int:trans_id>',
     'file_manager.save_show_hidden_file_option': '/file_manager/save_show_hidden_file_option/<int:trans_id>',
     'settings.save_file_format_setting': '/settings/save_file_format_setting/',
+    'bgprocess.detailed_status': '/misc/bgprocess/<pid>/<int:out>/<int:err>/',
+    'bgprocess.list': '/misc/bgprocess/',
+    'bgprocess.stop_process': '/misc/bgprocess/stop/<pid>',
+    'bgprocess.acknowledge': '/misc/bgprocess/<pid>'
   };
 });
diff --git a/web/regression/javascript/processes/BgProcessManager.spec.js b/web/regression/javascript/processes/BgProcessManager.spec.js
new file mode 100644
index 000000000..07bbeb5cd
--- /dev/null
+++ b/web/regression/javascript/processes/BgProcessManager.spec.js
@@ -0,0 +1,120 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from 'axios/index';
+import BgProcessManager, { BgProcessManagerProcessState } from '../../../pgadmin/misc/bgprocess/static/js/BgProcessManager';
+import * as BgProcessNotify from '../../../pgadmin/misc/bgprocess/static/js/BgProcessNotify';
+
+
+
+describe('BgProcessManager', ()=>{
+  let obj;
+  let networkMock;
+  const pgBrowser = jasmine.createSpyObj('pgBrowser', [], {
+    docker: {
+      findPanels: ()=>{/* dummy */},
+      addPanel: ()=>{/* dummy */}
+    }
+  });
+
+  beforeAll(()=>{
+    networkMock = new MockAdapter(axios);
+    networkMock.onGet('/misc/bgprocess/').reply(200, [{}]);
+    networkMock.onPut('/misc/bgprocess/stop/12345').reply(200,{});
+    networkMock.onPut('/misc/bgprocess/12345').reply(200,{});
+  });
+
+  afterAll(() => {
+    networkMock.restore();
+  });
+
+  beforeEach(()=>{
+    obj = new BgProcessManager(pgBrowser);
+  });
+
+  it('init', ()=>{
+    spyOn(obj, 'startWorker');
+    obj.init();
+    expect(obj.startWorker).toHaveBeenCalled();
+  });
+
+  it('procList', ()=>{
+    obj._procList = [{a: '1'}];
+    expect(obj.procList).toEqual([{a: '1'}]);
+  });
+
+  it('startWorker', (done)=>{
+    spyOn(obj, 'syncProcesses');
+    obj._pendingJobId = ['123123123123'];
+    obj.startWorker();
+
+    setTimeout(()=>{
+      expect(obj.syncProcesses).toHaveBeenCalled();
+      done();
+    }, 2000);
+  });
+
+  it('startProcess', ()=>{
+    let nSpy = spyOn(BgProcessNotify, 'processStarted');
+    obj.startProcess('12345', 'process desc');
+    expect(obj._pendingJobId).toEqual(['12345']);
+    expect(nSpy.calls.mostRecent().args[0]).toBe('process desc');
+  });
+
+
+  it('stopProcess', (done)=>{
+    obj._procList = [{
+      id: '12345',
+      process_state: BgProcessManagerProcessState.PROCESS_STARTED,
+    }];
+
+    obj.stopProcess('12345');
+    setTimeout(()=>{
+      expect(obj._procList[0].process_state).toBe(BgProcessManagerProcessState.PROCESS_TERMINATED);
+      done();
+    }, 500);
+  });
+
+  it('acknowledge', (done)=>{
+    obj._procList = [{
+      id: '12345',
+      process_state: BgProcessManagerProcessState.PROCESS_FINISHED,
+    }];
+
+    obj.acknowledge(['12345']);
+    setTimeout(()=>{
+      expect(obj._procList.length).toBe(0);
+      done();
+    }, 500);
+  });
+
+
+  it('checkPending', ()=>{
+    obj._procList = [{
+      id: '12345',
+      process_state: BgProcessManagerProcessState.PROCESS_FINISHED,
+    }];
+    obj._pendingJobId = ['12345'];
+    let nSpy = spyOn(BgProcessNotify, 'processCompleted');
+    obj.checkPending();
+    expect(nSpy).toHaveBeenCalled();
+  });
+
+
+  it('openProcessesPanel', ()=>{
+    const panel = {
+      focus: ()=>{/* dummy */}
+    };
+    spyOn(pgBrowser.docker, 'addPanel').and.returnValue(panel);
+
+    /* panel open */
+    spyOn(pgBrowser.docker, 'findPanels').and.returnValue([panel]);
+    obj.openProcessesPanel();
+    expect(pgBrowser.docker.addPanel).not.toHaveBeenCalled();
+
+    /* panel closed */
+    spyOn(pgBrowser.docker, 'findPanels')
+      .withArgs('processes').and.returnValue([])
+      .withArgs('properties').and.returnValue([panel]);
+    obj.openProcessesPanel();
+    expect(pgBrowser.docker.addPanel).toHaveBeenCalled();
+  });
+});
diff --git a/web/regression/javascript/processes/BgProcessNotify.spec.js b/web/regression/javascript/processes/BgProcessNotify.spec.js
new file mode 100644
index 000000000..454d8ba2c
--- /dev/null
+++ b/web/regression/javascript/processes/BgProcessNotify.spec.js
@@ -0,0 +1,75 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import jasmineEnzyme from 'jasmine-enzyme';
+import '../helper/enzyme.helper';
+import { createMount } from '@material-ui/core/test-utils';
+import BgProcessManager, { BgProcessManagerProcessState } from '../../../pgadmin/misc/bgprocess/static/js/BgProcessManager';
+import pgAdmin from 'sources/pgadmin';
+import * as BgProcessNotify from '../../../pgadmin/misc/bgprocess/static/js/BgProcessNotify';
+import Notifier from '../../../pgadmin/static/js/helpers/Notifier';
+
+describe('BgProcessNotify', ()=>{
+  let mount;
+
+  /* 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();
+    pgAdmin.Browser = pgAdmin.Browser || {};
+    pgAdmin.Browser.BgProcessManager = new BgProcessManager(pgAdmin.Browser);
+  });
+
+  it('processStarted', ()=>{
+    const nspy = spyOn(Notifier, 'notify');
+    BgProcessNotify.processStarted('some desc', ()=>{/* dummy */});
+    expect(nspy.calls.mostRecent().args[0].props).toEqual(jasmine.objectContaining({
+      title: 'Process started',
+      desc: 'some desc',
+    }));
+  });
+
+  it('processCompleted success', ()=>{
+    const nspy = spyOn(Notifier, 'notify');
+    BgProcessNotify.processCompleted('some desc', BgProcessManagerProcessState.PROCESS_FINISHED, ()=>{/* dummy */});
+    expect(nspy.calls.mostRecent().args[0].props).toEqual(jasmine.objectContaining({
+      title: 'Process completed',
+      desc: 'some desc',
+      success: true,
+    }));
+  });
+
+  it('processCompleted failed', ()=>{
+    const nspy = spyOn(Notifier, 'notify');
+    BgProcessNotify.processCompleted('some desc', BgProcessManagerProcessState.PROCESS_FAILED, ()=>{/* dummy */});
+    expect(nspy.calls.mostRecent().args[0].props).toEqual(jasmine.objectContaining({
+      title: 'Process failed',
+      desc: 'some desc',
+      success: false,
+    }));
+  });
+
+  it('processCompleted terminated', ()=>{
+    const nspy = spyOn(Notifier, 'notify');
+    BgProcessNotify.processCompleted('some desc', BgProcessManagerProcessState.PROCESS_TERMINATED, ()=>{/* dummy */});
+    expect(nspy.calls.mostRecent().args[0].props).toEqual(jasmine.objectContaining({
+      title: 'Process terminated',
+      desc: 'some desc',
+      success: false,
+    }));
+  });
+});
diff --git a/web/regression/javascript/processes/Proceses.spec.js b/web/regression/javascript/processes/Proceses.spec.js
new file mode 100644
index 000000000..0de21f8ca
--- /dev/null
+++ b/web/regression/javascript/processes/Proceses.spec.js
@@ -0,0 +1,76 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, 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 Theme from '../../../pgadmin/static/js/Theme';
+import BgProcessManager, { BgProcessManagerProcessState } from '../../../pgadmin/misc/bgprocess/static/js/BgProcessManager';
+import pgAdmin from 'sources/pgadmin';
+import Processes from '../../../pgadmin/misc/bgprocess/static/js/Processes';
+
+
+const processData = {
+  acknowledge: null,
+  current_storage_dir: null,
+  desc: 'Doing some operation on the server \'PostgreSQL 12 (localhost:5432)\'',
+  details: {
+    cmd: '/Library/PostgreSQL/12/bin/mybin --testing',
+    message: 'Doing some detailed operation on the server \'PostgreSQL 12 (localhost:5432)\'...'
+  },
+  etime: null,
+  execution_time: 0.09,
+  exit_code: null,
+  id: '220803091429498400',
+  process_state: BgProcessManagerProcessState.PROCESS_STARTED,
+  stime: '2022-08-03T09:14:30.191940+00:00',
+  type_desc: 'Operation on the server',
+  utility_pid: 140391
+};
+
+describe('Proceses', ()=>{
+  let mount;
+
+  /* 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();
+    pgAdmin.Browser = pgAdmin.Browser || {};
+    pgAdmin.Browser.BgProcessManager = new BgProcessManager(pgAdmin.Browser);
+    pgAdmin.Browser.BgProcessManager._procList = [processData];
+  });
+
+  describe('ProcessDetails', ()=>{
+    let ctrlMount = (props)=>{
+      return mount(<Theme>
+        <Processes
+          {...props}
+        />
+      </Theme>);
+    };
+
+    it('init', (done)=>{
+      let ctrl = ctrlMount({});
+      setTimeout(()=>{
+        ctrl.update();
+        expect(ctrl.find('PgTable').length).toBe(1);
+        done();
+      }, 1000);
+    });
+  });
+});
diff --git a/web/regression/javascript/processes/ProcessDetails.spec.js b/web/regression/javascript/processes/ProcessDetails.spec.js
new file mode 100644
index 000000000..e9fd59745
--- /dev/null
+++ b/web/regression/javascript/processes/ProcessDetails.spec.js
@@ -0,0 +1,116 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, 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 Theme from '../../../pgadmin/static/js/Theme';
+import MockAdapter from 'axios-mock-adapter';
+import axios from 'axios/index';
+import ProcessDetails from '../../../pgadmin/misc/bgprocess/static/js/ProcessDetails';
+import BgProcessManager, { BgProcessManagerProcessState } from '../../../pgadmin/misc/bgprocess/static/js/BgProcessManager';
+import pgAdmin from 'sources/pgadmin';
+import { MESSAGE_TYPE } from '../../../pgadmin/static/js/components/FormComponents';
+import _ from 'lodash';
+
+
+const processData = {
+  acknowledge: null,
+  current_storage_dir: null,
+  desc: 'Doing some operation on the server \'PostgreSQL 12 (localhost:5432)\'',
+  details: {
+    cmd: '/Library/PostgreSQL/12/bin/mybin --testing',
+    message: 'Doing some detailed operation on the server \'PostgreSQL 12 (localhost:5432)\'...'
+  },
+  etime: null,
+  execution_time: 0.09,
+  exit_code: null,
+  id: '220803091429498400',
+  process_state: BgProcessManagerProcessState.PROCESS_STARTED,
+  stime: '2022-08-03T09:14:30.191940+00:00',
+  type_desc: 'Operation on the server',
+  utility_pid: 140391
+};
+
+const detailsResponse = {
+  err: {
+    done: true,
+    lines: [['220803091259931276', 'INFO: operation log err']],
+    pos: 123
+  },
+  execution_time: 1.27,
+  exit_code: 0,
+  out: {
+    done: true,
+    lines: [['220803091259931276', 'INFO: operation log out']],
+    pos: 123
+  },
+  start_time: '2022-08-03 09:12:59.774503 +0000'
+};
+
+describe('ProcessDetails', ()=>{
+  let mount;
+  let networkMock;
+
+  /* Use createMount so that material ui components gets the required context */
+  /* https://material-ui.com/guides/testing/#api */
+  beforeAll(()=>{
+    mount = createMount();
+    networkMock = new MockAdapter(axios);
+    let initialResp = _.cloneDeep(detailsResponse);
+    initialResp.err.done = false;
+    initialResp.out.done = false;
+    initialResp.exit_code = null;
+    networkMock.onGet(`/misc/bgprocess/${processData.id}/0/0/`).reply(200, initialResp);
+    networkMock.onGet(`/misc/bgprocess/${processData.id}/123/123/`).reply(200, detailsResponse);
+  });
+
+  afterAll(() => {
+    mount.cleanUp();
+    networkMock.restore();
+  });
+
+  beforeEach(()=>{
+    jasmineEnzyme();
+    pgAdmin.Browser = pgAdmin.Browser || {};
+    pgAdmin.Browser.BgProcessManager = new BgProcessManager(pgAdmin.Browser);
+  });
+
+  describe('ProcessDetails', ()=>{
+    let ctrlMount = (props)=>{
+      return mount(<Theme>
+        <ProcessDetails
+          data={processData}
+          {...props}
+        />
+      </Theme>);
+    };
+
+    it('running and success', (done)=>{
+      let ctrl = ctrlMount({});
+      setTimeout(()=>{
+        ctrl.update();
+        expect(ctrl.find('NotifierMessage').props()).toEqual(jasmine.objectContaining({
+          type: MESSAGE_TYPE.INFO,
+          message: 'Running...',
+        }));
+        setTimeout(()=>{
+          ctrl.update();
+          expect(ctrl.find('NotifierMessage').props()).toEqual(jasmine.objectContaining({
+            type: MESSAGE_TYPE.SUCCESS,
+            message: 'Successfully completed.',
+          }));
+          ctrl.unmount();
+          done();
+        }, 2000);
+      }, 500);
+    });
+  });
+});
diff --git a/web/regression/python_test_utils/test_gui_helper.py b/web/regression/python_test_utils/test_gui_helper.py
index 95766b85b..49bcc20a0 100644
--- a/web/regression/python_test_utils/test_gui_helper.py
+++ b/web/regression/python_test_utils/test_gui_helper.py
@@ -6,48 +6,59 @@
 # This software is released under the PostgreSQL Licence
 #
 ##########################################################################
+import time
 from regression.feature_utils.locators import NavMenuLocators
 from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions as EC
 
 
-def close_bgprocess_popup(tester):
+def close_bgprocess_start_popup(tester):
     """
     Allows us to close the background process popup window
     """
-    # In cases where backup div is not closed (sometime due to some error)
-    try:
-        tester.page.wait_for_element_to_disappear(
-            lambda x: tester.driver.find_element(
-                By.XPATH, ".ajs-message.ajs-bg-bgprocess.ajs-visible"))
-    except Exception:
-        tester.driver.find_element(
-            By.CSS_SELECTOR,
-            NavMenuLocators.process_watcher_error_close_xpath).click()
+    tester.driver.find_element(
+        By.CSS_SELECTOR,
+        NavMenuLocators.process_start_close_selector).click()
 
-    # In cases where restore div is not closed (sometime due to some error)
-    try:
-        tester.page.wait_for_element_to_disappear(
-            lambda x: tester.driver.find_element(
-                By.XPATH,
-                "//div[@class='card-header bg-primary d-flex']/div"
-                "[contains(text(), 'Restoring backup')]"))
-    except Exception:
-        tester.driver.find_element(
-            By.CSS_SELECTOR,
-            NavMenuLocators.process_watcher_error_close_xpath).click()
 
-    # In cases where maintenance window is not closed (sometime due to some
-    # error)
-    try:
-        tester.page.wait_for_element_to_disappear(
-            lambda x: tester.driver.find_element(
-                By.XPATH,
-                "//div[@class='card-header bg-primary d-flex']/div"
-                "[contains(text(), 'Maintenance')]"))
-    except Exception:
-        tester.driver.find_element(
-            By.CSS_SELECTOR,
-            NavMenuLocators.process_watcher_error_close_xpath).click()
+def wait_for_process_start(tester):
+    tester.wait.until(EC.visibility_of_element_located(
+        (By.CSS_SELECTOR,
+         NavMenuLocators.process_start_close_selector)))
+    close_bgprocess_start_popup(tester)
+
+
+def wait_for_process_end(self):
+    """This will wait for process to complete dialogue status"""
+    attempts = 120
+    status = False
+    while attempts > 0:
+        try:
+            button = self.page.find_by_css_selector(NavMenuLocators.process_end_close_selector)
+            status = True
+            button.click()
+            break
+        except Exception:
+            attempts -= 1
+            time.sleep(.5)
+    return status
+
+
+def open_process_details(tester):
+    status = wait_for_process_end(tester)
+    if not status:
+        raise RuntimeError("Process not completed")
+
+    tester.page.click_tab("Processes")
+    time.sleep(3)
+    tester.page.find_by_css_selector(
+        "div[data-test='processes'] "
+        "div[data-test='row-container']:nth-child(1) "
+        "div[role='row'] div[role='cell']:nth-child(3) button").click()
+
+    tester.page.wait_for_element_to_disappear(
+        lambda driver: driver.find_element(
+            By.CSS_SELECTOR, "span[data-test='loading-logs']"))
 
 
 def close_process_watcher(tester):
diff --git a/web/regression/python_test_utils/test_utils.py b/web/regression/python_test_utils/test_utils.py
index 5a5a9379a..dfcceb17a 100644
--- a/web/regression/python_test_utils/test_utils.py
+++ b/web/regression/python_test_utils/test_utils.py
@@ -1185,28 +1185,6 @@ def check_binary_path_or_skip_test(cls, utility_name):
             cls.skipTest(ret_val)
 
 
-def get_watcher_dialogue_status(self):
-    """This will get watcher dialogue status"""
-    import time
-    attempts = 120
-    status = None
-    while attempts > 0:
-        try:
-            status = self.page.find_by_css_selector(
-                ".pg-bg-status-text").text
-
-            if 'Failed' in status:
-                break
-            if status == 'Started' or status == 'Running...':
-                attempts -= 1
-                time.sleep(.5)
-            else:
-                break
-        except Exception:
-            attempts -= 1
-    return status
-
-
 def get_driver_version():
     version = getattr(psycopg2, '__version__', None)
     return version
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 8873198a4..5c2e590a8 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -473,7 +473,7 @@ module.exports = [{
           imports: [
             'pure|pgadmin.browser.quick_search',
             'pure|pgadmin.tools.user_management',
-            'pure|pgadmin.browser.bgprocess',
+            'pure|pgadmin.browser.bgprocessmanager',
             'pure|pgadmin.node.server_group',
             'pure|pgadmin.node.server',
             'pure|pgadmin.node.database',
diff --git a/web/webpack.shim.js b/web/webpack.shim.js
index b01b4f4ee..7f0a9c3c4 100644
--- a/web/webpack.shim.js
+++ b/web/webpack.shim.js
@@ -179,7 +179,7 @@ var webpackShimConfig = {
     'pgadmin.about': path.join(__dirname, './pgadmin/about/static/js/about'),
     'pgadmin.authenticate.kerberos': path.join(__dirname, './pgadmin/authenticate/static/js/kerberos'),
     'pgadmin.browser': path.join(__dirname, './pgadmin/browser/static/js/browser'),
-    'pgadmin.browser.bgprocess': path.join(__dirname, './pgadmin/misc/bgprocess/static/js/bgprocess'),
+    'pgadmin.browser.bgprocessmanager': path.join(__dirname, './pgadmin/misc/bgprocess/static/js'),
     'pgadmin.browser.collection': path.join(__dirname, './pgadmin/browser/static/js/collection'),
     'pgadmin.browser.datamodel': path.join(__dirname, './pgadmin/browser/static/js/datamodel'),
     'pgadmin.browser.endpoints': '/browser/js/endpoints',
