diff --git a/docs/en_US/images/delete.png b/docs/en_US/images/delete.png
deleted file mode 100644
index e5936e8278aa04251a7b1d6cc1d85b207330aea4..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/download.png b/docs/en_US/images/download.png
deleted file mode 100644
index b3efacc7460585684d24b3d7541a8a1c02ec6c26..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/edit.png b/docs/en_US/images/edit.png
deleted file mode 100644
index a52560bbf3eeab7efd3574e430df65a18a04ece6..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/folder.png b/docs/en_US/images/folder.png
deleted file mode 100644
index 473632c4631659932ab07c0e0d5f8ce240870b62..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/gridview.png b/docs/en_US/images/gridview.png
deleted file mode 100644
index 41edbac36fa202c6a0eb73d019fb5782dfb0de57..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/home.png b/docs/en_US/images/home.png
deleted file mode 100644
index 6c671548c95a975444ee08cef73561655ae27068..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/refresh.png b/docs/en_US/images/refresh.png
deleted file mode 100644
index 58738a14da43cde8394a1158a967755cb5535d11..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/sm_download.png b/docs/en_US/images/sm_download.png
new file mode 100644
index 0000000000000000000000000000000000000000..50471b7608e9d6b2e724152da69c497bec70c6e1
GIT binary patch
diff --git a/docs/en_US/images/sm_go_back.png b/docs/en_US/images/sm_go_back.png
new file mode 100644
index 0000000000000000000000000000000000000000..2fb4641baa2ef7f3e7fb4467c92277c37f64af2f
GIT binary patch
diff --git a/docs/en_US/images/sm_home.png b/docs/en_US/images/sm_home.png
new file mode 100644
index 0000000000000000000000000000000000000000..f6b13b6f8421ed8fb71b155a7736ea90a4a12b98
GIT binary patch
diff --git a/docs/en_US/images/sm_new_folder.png b/docs/en_US/images/sm_new_folder.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e04e410ff1ba6322d092b50eefcbbe532e350d4
GIT binary patch
diff --git a/docs/en_US/images/sm_options.png b/docs/en_US/images/sm_options.png
new file mode 100644
index 0000000000000000000000000000000000000000..f12951fc75aedfb3e07a827b582ff7cd8d01b2b9
GIT binary patch
diff --git a/docs/en_US/images/sm_refresh.png b/docs/en_US/images/sm_refresh.png
new file mode 100644
index 0000000000000000000000000000000000000000..c7914c0190e994b3c562867af85c8357a082170b
GIT binary patch
diff --git a/docs/en_US/images/storage_manager.png b/docs/en_US/images/storage_manager.png
index 4ad42ce91f4b9315af008e771757a562c3d46af7..ac33ea9fd0bde9ec3615067038d884b7c03a3c73 100644
GIT binary patch
diff --git a/docs/en_US/images/tableview.png b/docs/en_US/images/tableview.png
deleted file mode 100644
index 0191c4fe619187ae00327f758dbfda86fc3f732b..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/uparrow.png b/docs/en_US/images/uparrow.png
deleted file mode 100644
index 3c4303d859e1a59848c6269b2da24d1755dd1560..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/images/upload.png b/docs/en_US/images/upload.png
deleted file mode 100644
index ec9d0eb80fe819efd123c42526c2ed5cb597a7c1..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/docs/en_US/storage_manager.rst b/docs/en_US/storage_manager.rst
index 36bb5d6f8..aee923598 100644
--- a/docs/en_US/storage_manager.rst
+++ b/docs/en_US/storage_manager.rst
@@ -20,47 +20,53 @@ Use icons on the top of the *Storage Manager* window to manage storage:
 
 Use the ``Home`` icon |home| to return to the home directory.
 
-.. |home| image:: images/home.png
+.. |home| image:: images/sm_home.png
 
 Use the ``Up Arrow`` icon |uparrow| to return to the previous directory.
 
-.. |uparrow| image:: images/uparrow.png
+.. |uparrow| image:: images/sm_go_back.png
 
 Use the ``Refresh`` icon |refresh| to display the most-recent files available.
 
-.. |refresh| image:: images/refresh.png
+.. |refresh| image:: images/sm_refresh.png
 
 Select the ``Download`` icon |download| to download the selected file.
 
-.. |download| image:: images/download.png
-
-Select the ``Delete`` icon |delete| to delete the selected file or folder.
-
-.. |delete| image:: images/delete.png
-
-Select the ``Edit`` icon |edit|  to rename a file or folder.
-
-.. |edit| image:: images/edit.png
-
-Use the ``Upload`` icon |upload| to upload a file.
-
-.. |upload| image:: images/upload.png
+.. |download| image:: images/sm_download.png
 
 Use the ``New Folder`` icon |folder| to add a new folder.
 
-.. |folder| image:: images/folder.png
-
-Use the ``Grid View`` icon |gridview| to display all the files and folders in a grid view.
+.. |folder| image:: images/sm_new_folder.png
 
-.. |gridview| image:: images/gridview.png
+Use the *Format* drop down list to select the format of the files to be displayed; choose from *sql*, *csv*, or *All Files*.
 
-Use the ``Table View`` icon |tableview| to display all the files and folders in a list view.
+Other Options
+*********************
 
-.. |tableview| image:: images/tableview.png
+.. image:: images/sm_options.png
+    :alt: Other options
+    :align: center
 
-Click on the check box next to *Show hidden files and folders* at the bottom of the window to view hidden files and folders.
+.. table::
+   :class: longtable
+   :widths: 1 5
+
+   +----------------------+---------------------------------------------------------------------------------------------------+
+   | Menu                 | Behavior                                                                                          |
+   +======================+===================================================================================================+
+   | *Rename*             | Click the *Rename* option to rename a file/folder.                                                |
+   +----------------------+---------------------------------------------------------------------------------------------------+   
+   | *Delete*             | Click the *Delete* option to rename a file/folder.                                                |
+   +----------------------+---------------------------------------------------------------------------------------------------+
+   | *Upload*             | Click the *Upload* option to upload multiple files to the current folder.                         |
+   +----------------------+---------------------------------------------------------------------------------------------------+
+   | *List View*          | Click the *List View* option to to display all the files and folders in a list view.              |
+   +----------------------+---------------------------------------------------------------------------------------------------+
+   | *Grid View*          | Click the *Grid View* option to to display all the files and folders in a grid view.              |
+   +----------------------+---------------------------------------------------------------------------------------------------+
+   | *Show Hidden Files*  | Click the *Show Hidden Files* option to view hidden files and folders.                            |
+   +----------------------+---------------------------------------------------------------------------------------------------+
 
-Use the *Format* drop down list to select the format of the files to be displayed; choose from *sql*, *csv*, or *All Files*.
 
 You can also download backup files through *Storage Manager* at the successful completion of the backups taken through :ref:`Backup Dialog <backup_dialog>`, :ref:`Backup Global Dialog <backup_globals_dialog>`, or :ref:`Backup Server Dialog <backup_server_dialog>`.
 
diff --git a/runtime/package.json b/runtime/package.json
index 1051ba603..0015fbc95 100644
--- a/runtime/package.json
+++ b/runtime/package.json
@@ -7,6 +7,7 @@
   "license": "PostgreSQL",
   "chromium-args": "--disable-popup-blocking --disable-gpu",
   "user-agent": "Nwjs:%nwver-%osinfo-%chromium_ver",
+  "nodejs": true,
   "window": {
     "width": 750,
     "height": 600,
diff --git a/web/config.py b/web/config.py
index 6091924b3..50b09a40c 100644
--- a/web/config.py
+++ b/web/config.py
@@ -822,6 +822,7 @@ except ImportError:
 system_config_dir = '/etc/pgadmin'
 if sys.platform.startswith('win32'):
     system_config_dir = os.environ['CommonProgramFiles'] + '/pgadmin'
+    print(system_config_dir)
 elif sys.platform.startswith('darwin'):
     system_config_dir = '/Library/Preferences/pgadmin'
 
diff --git a/web/package.json b/web/package.json
index 60eef375e..d9894085e 100644
--- a/web/package.json
+++ b/web/package.json
@@ -111,12 +111,12 @@
     "closest": "^0.0.1",
     "codemirror": "^5.59.2",
     "context-menu": "^2.0.0",
+    "convert-units": "^2.3.4",
     "css-loader": "^5.0.1",
     "cssnano": "^5.0.2",
     "dagre": "^0.8.4",
     "date-fns": "^2.24.0",
     "diff-arrays-of-objects": "^1.1.8",
-    "dropzone": "^5.9.3",
     "html2canvas": "^1.0.0-rc.7",
     "immutability-helper": "^3.0.0",
     "imports-loader": "^2.0.0",
@@ -150,6 +150,7 @@
     "react-data-grid": "git+https://github.com/adityatoshniwal/react-data-grid.git/#8d9bc16ddd7c419acfbbd1c1cc2b70eb9f5b453c",
     "react-dom": "^17.0.1",
     "react-draggable": "^4.4.4",
+    "react-dropzone": "^14.2.1",
     "react-leaflet": "^3.2.2",
     "react-rnd": "^10.3.5",
     "react-router-dom": "^6.2.2",
@@ -165,7 +166,6 @@
     "socket.io-client": "^4.0.0",
     "split.js": "^1.5.10",
     "styled-components": "^5.2.1",
-    "tablesorter": "^2.31.2",
     "tempusdominus-bootstrap-4": "^5.1.2",
     "tempusdominus-core": "^5.19.3",
     "underscore": "^1.13.1",
diff --git a/web/pgadmin/browser/static/js/node.js b/web/pgadmin/browser/static/js/node.js
index 2d12c4ed9..199ee986f 100644
--- a/web/pgadmin/browser/static/js/node.js
+++ b/web/pgadmin/browser/static/js/node.js
@@ -551,7 +551,25 @@ define('pgadmin.browser.node', [
 
       }
     },
+    registerDockerPanel: function(docker, name, params) {
+      var w = docker || pgBrowser.docker,
+        p = w.findPanels(name);
+
+      if (p && p.length == 1)
+        return;
 
+      p = new pgBrowser.Panel({
+        name: name,
+        showTitle: true,
+        isCloseable: true,
+        isPrivate: true,
+        isLayoutMember: false,
+        canMaximise: true,
+        content: '<div class="obj_properties container-fluid h-100"></div>',
+        ...params,
+      });
+      p.load(w);
+    },
     registerUtilityPanel: function(docker) {
       var w = docker || pgBrowser.docker,
         p = w.findPanels('utility_props');
diff --git a/web/pgadmin/misc/bgprocess/static/js/bgprocess.js b/web/pgadmin/misc/bgprocess/static/js/bgprocess.js
index b007fec3f..ddc965e7a 100644
--- a/web/pgadmin/misc/bgprocess/static/js/bgprocess.js
+++ b/web/pgadmin/misc/bgprocess/static/js/bgprocess.js
@@ -9,7 +9,7 @@
 
 define('misc.bgprocess', [
   'sources/pgadmin', 'sources/gettext', 'sources/url_for', 'underscore',
-  'jquery', 'pgadmin.browser', 'alertify',
+  'jquery', 'pgadmin.browser', 'alertify', 'pgadmin.tools.file_manager',
 ], function(
   pgAdmin, gettext, url_for, _, $, pgBrowser, Alertify
 ) {
@@ -625,9 +625,7 @@ define('misc.bgprocess', [
 
         var self = this;
         if(self.current_storage_dir) {
-          pgBrowser.Events.trigger(
-            'pgadmin:tools:storage_manager', self.current_storage_dir
-          );
+          pgAdmin.Tools.FileManager.openStorageManager(self.current_storage_dir);
         }
       },
     });
diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py
index f9562b1a8..abedf800c 100644
--- a/web/pgadmin/misc/file_manager/__init__.py
+++ b/web/pgadmin/misc/file_manager/__init__.py
@@ -28,9 +28,11 @@ from flask_babel import gettext
 from flask_security import login_required
 from pgadmin.utils import PgAdminModule
 from pgadmin.utils import get_storage_directory
-from pgadmin.utils.ajax import make_json_response
+from pgadmin.utils.ajax import make_json_response, unauthorized, \
+    internal_server_error
 from pgadmin.utils.preferences import Preferences
 from pgadmin.utils.constants import PREF_LABEL_OPTIONS, MIMETYPE_APP_JS
+from pgadmin.settings.utils import get_file_type_setting
 
 # Checks if platform is Windows
 if _platform == "win32":
@@ -132,9 +134,9 @@ class FileManagerModule(PgAdminModule):
             list: a list of url endpoints exposed to the client.
         """
         return [
+            'file_manager.init',
             'file_manager.filemanager',
             'file_manager.index',
-            'file_manager.get_trans_id',
             'file_manager.delete_trans_id',
             'file_manager.save_last_dir',
             'file_manager.save_file_dialog_view',
@@ -196,74 +198,56 @@ def utility():
         mimetype=MIMETYPE_APP_JS)
 
 
-@blueprint.route("/file_manager.js")
-@login_required
-def file_manager_js():
-    """render the required javascript"""
-    return Response(response=render_template(
-        "file_manager/js/file_manager.js", _=gettext),
-        status=200,
-        mimetype=MIMETYPE_APP_JS)
-
-
-@blueprint.route("/en.json")
-@login_required
-def language():
-    """render the required javascript"""
-    return Response(response=render_template(
-        "file_manager/js/languages/en.json", _=gettext),
-        status=200)
-
-
-@blueprint.route("/file_manager_config.js")
-@login_required
-def file_manager_config_js():
-    """render the required javascript"""
-    return Response(response=render_template(
-        "file_manager/js/file_manager_config.js", _=gettext),
-        status=200,
-        mimetype=MIMETYPE_APP_JS)
-
-
-@blueprint.route("/<int:trans_id>/file_manager_config.json")
-@login_required
-def file_manager_config(trans_id):
-    """render the required json"""
-    data = Filemanager.get_trasaction_selection(trans_id)
-    pref = Preferences.module('file_manager')
-    file_dialog_view = pref.preference('file_dialog_view').get()[0]
-    show_hidden_files = pref.preference('show_hidden_files').get()
-
-    return Response(response=render_template(
-        "file_manager/js/file_manager_config.json",
-        _=gettext,
-        data=data,
-        file_dialog_view=file_dialog_view,
-        show_hidden_files=show_hidden_files
-    ),
-        status=200,
-        mimetype="application/json"
-    )
-
-
 @blueprint.route(
-    "/get_trans_id", methods=["GET", "POST"], endpoint='get_trans_id'
+    "/init", methods=["POST"], endpoint='init'
 )
 @login_required
-def get_trans_id():
+def init_filemanager():
     if len(req.data) != 0:
         configs = json.loads(req.data)
         trans_id = Filemanager.create_new_transaction(configs)
-        global transid
-        transid = trans_id
-    return make_json_response(
-        data={'fileTransId': transid, 'status': True}
-    )
+        data = Filemanager.get_trasaction_selection(trans_id)
+        pref = Preferences.module('file_manager')
+
+        res_data = {
+            'transId': trans_id,
+            "options": {
+                "culture": "en",
+                "lang": "py",
+                "defaultViewMode":
+                    pref.preference('file_dialog_view').get()[0],
+                "autoload": True,
+                "showFullPath": False,
+                "dialog_type": data['dialog_type'],
+                "show_hidden_files":
+                    pref.preference('show_hidden_files').get(),
+                "fileRoot": data['fileroot'],
+                "capabilities": data['capabilities'],
+                "allowed_file_types": data['supported_types'],
+                "platform_type": data['platform_type'],
+                "show_volumes": data['show_volumes'],
+                "homedir": data['homedir'],
+                "last_selected_format": get_file_type_setting(
+                    data['supported_types'])
+            },
+            "security": {
+                "uploadPolicy": data['security']['uploadPolicy'],
+                "uploadRestrictions": data['security']['uploadRestrictions'],
+            },
+            "upload": {
+                "multiple": data['upload']['multiple'],
+                "number": 20,
+                "fileSizeLimit": data['upload']['fileSizeLimit'],
+                "imagesOnly": False
+            }
+        }
+
+    return make_json_response(data=res_data)
 
 
 @blueprint.route(
-    "/del_trans_id/<int:trans_id>",
-    methods=["GET", "POST"], endpoint='delete_trans_id'
+    "/delete_trans_id/<int:trans_id>",
+    methods=["DELETE"], endpoint='delete_trans_id'
 )
 @login_required
 def delete_trans_id(trans_id):
@@ -279,9 +263,7 @@ def delete_trans_id(trans_id):
 @login_required
 def save_last_directory_visited(trans_id):
     blueprint.last_directory_visited.set(req.json['path'])
-    return make_json_response(
-        data={'status': True}
-    )
+    return make_json_response(status=200)
 
 
 @blueprint.route(
@@ -291,9 +273,7 @@ def save_last_directory_visited(trans_id):
 @login_required
 def save_file_dialog_view(trans_id):
     blueprint.file_dialog_view.set(req.json['view'])
-    return make_json_response(
-        data={'status': True}
-    )
+    return make_json_response(status=200)
 
 
 @blueprint.route(
@@ -303,9 +283,7 @@ def save_file_dialog_view(trans_id):
 @login_required
 def save_show_hidden_file_option(trans_id):
     blueprint.show_hidden_files.set(req.json['show_hidden'])
-    return make_json_response(
-        data={'status': True}
-    )
+    return make_json_response(status=200)
 
 
 class Filemanager(object):
@@ -321,14 +299,6 @@ class Filemanager(object):
 
     def __init__(self, trans_id):
         self.trans_id = trans_id
-        self.patherror = encode_json(
-            {
-                'Error': gettext(
-                    'No permission to operate on specified path.'
-                ),
-                'Code': 0
-            }
-        )
         self.dir = get_storage_directory()
 
         if self.dir is not None and isinstance(self.dir, list):
@@ -387,7 +357,7 @@ class Filemanager(object):
         # tuples with (capabilities, files_only, folders_only, title)
         capability_map = {
             'select_file': (
-                ['select_file', 'rename', 'upload', 'create'],
+                ['select_file', 'rename', 'upload', 'delete'],
                 True,
                 False,
                 gettext("Select File")
@@ -421,6 +391,8 @@ class Filemanager(object):
 
         # get last visited directory, if not present then traverse in reverse
         # order to find closest parent directory
+        if 'init_path' in params:
+            blueprint.last_directory_visited.get(params['init_path'])
         last_dir = blueprint.last_directory_visited.get()
         check_dir_exists = False
         if last_dir is None:
@@ -436,9 +408,8 @@ class Filemanager(object):
 
         # create configs using above configs
         configs = {
-            # for JS json compatibility
-            "fileroot": last_dir.replace('\\', '\\\\'),
-            "homedir": homedir.replace('\\', '\\\\'),
+            "fileroot": last_dir,
+            "homedir": homedir,
             "dialog_type": fm_type,
             "title": title,
             "upload": {
@@ -499,14 +470,14 @@ class Filemanager(object):
         file_manager_data = session['fileManagerData']
         # Return from the function if transaction id not found
         if str(trans_id) not in file_manager_data:
-            return make_json_response(data={'status': True})
+            return make_json_response(status=200)
 
         # Remove the information of unique transaction id
         # from the session variable.
         file_manager_data.pop(str(trans_id), None)
         session['fileManagerData'] = file_manager_data
 
-        return make_json_response(data={'status': True})
+        return make_json_response(status=200)
 
     @staticmethod
     def _get_drives_with_size(drive_name=None):
@@ -590,7 +561,7 @@ class Filemanager(object):
         :param orig_path: path after user dir
         :return:
         """
-        files = {}
+        files = []
 
         for f in sorted(os.listdir(orig_path)):
             system_path = os.path.join(os.path.join(orig_path, f))
@@ -617,14 +588,13 @@ class Filemanager(object):
                 if files_only == 'true':
                     continue
                 file_extension = "dir"
-                user_path = "{0}/".format(user_path)
             # filter files based on file_type
             elif Filemanager._skip_file_extension(
                     file_type, supported_types, folders_only, file_extension):
                 continue
 
             # create a list of files and folders
-            files[f] = {
+            files.append({
                 "Filename": f,
                 "Path": user_path,
                 "file_type": file_extension,
@@ -634,7 +604,7 @@ class Filemanager(object):
                     "Date Modified": modified,
                     "Size": sizeof_fmt(getsize(system_path))
                 }
-            }
+            })
 
         return files
 
@@ -649,23 +619,16 @@ class Filemanager(object):
 
         path = unquote(path)
 
-        try:
-            Filemanager.check_access_permission(in_dir, path)
-        except Exception as e:
-            Filemanager.resume_windows_warning()
-            files = {
-                'Code': 0,
-                'Error': str(e)
-            }
-            return files
+        Filemanager.check_access_permission(in_dir, path)
+        Filemanager.resume_windows_warning()
 
-        files = {}
+        files = []
         if (_platform == "win32" and (path == '/' or path == '\\'))\
                 and in_dir is None:
             drives = Filemanager._get_drives_with_size()
             for drive, drive_size in drives:
                 path = file_name = "{0}:".format(drive)
-                files[file_name] = {
+                files.append({
                     "Filename": file_name,
                     "Path": path,
                     "file_type": 'drive',
@@ -675,7 +638,7 @@ class Filemanager(object):
                         "Date Modified": "",
                         "Size": drive_size
                     }
-                }
+                })
             Filemanager.resume_windows_warning()
             return files
 
@@ -683,10 +646,9 @@ class Filemanager(object):
 
         if not path_exists(orig_path):
             Filemanager.resume_windows_warning()
-            return {
-                'Code': 0,
-                'Error': gettext("'{0}' file does not exist.").format(path)
-            }
+            return make_json_response(
+                status=404,
+                errormsg=gettext("'{0}' file does not exist.").format(path))
 
         user_dir = path
         folders_only = trans_data.get('folders_only', '')
@@ -705,11 +667,7 @@ class Filemanager(object):
             if (hasattr(e, 'strerror') and
                     e.strerror == gettext('Permission denied')):
                 err_msg = str(e.strerror)
-
-            files = {
-                'Code': 0,
-                'Error': err_msg
-            }
+            return unauthorized(err_msg)
         Filemanager.resume_windows_warning()
         return files
 
@@ -735,9 +693,10 @@ class Filemanager(object):
 
         # Do not allow user to access outside his storage dir
         # in server mode.
-        if not orig_path.startswith(in_dir):
-            raise InternalServerError(
-                gettext("Access denied ({0})").format(path))
+        try:
+            pathlib.Path(orig_path).relative_to(in_dir)
+        except ValueError:
+            raise PermissionError(gettext("Access denied ({0})").format(path))
 
     @staticmethod
     def get_abs_path(in_dir, path):
@@ -789,33 +748,13 @@ class Filemanager(object):
             self.dir = ""
         orig_path = "{0}{1}".format(self.dir, path)
 
-        try:
-            Filemanager.check_access_permission(self.dir, path)
-        except Exception as e:
-            thefile = {
-                'Filename': split_path(path)[-1],
-                'FileType': '',
-                'Path': path,
-                'Error': str(e),
-                'Code': 0,
-                'Info': '',
-                'Properties': {
-                    date_created: '',
-                    date_modified: '',
-                    'Width': '',
-                    'Height': '',
-                    'Size': ''
-                }
-            }
-            return thefile
+        Filemanager.check_access_permission(self.dir, path)
 
         user_dir = path
         thefile = {
             'Filename': split_path(orig_path)[-1],
             'FileType': '',
             'Path': user_dir,
-            'Error': '',
-            'Code': 1,
             'Info': '',
             'Properties': {
                 date_created: '',
@@ -827,10 +766,9 @@ class Filemanager(object):
         }
 
         if not path_exists(orig_path):
-            thefile['Error'] = gettext(
-                "'{0}' file does not exist.").format(path)
-            thefile['Code'] = -1
-            return thefile
+            return make_json_response(
+                status=404,
+                errormsg=gettext("'{0}' file does not exist.").format(path))
 
         if split_path(user_dir)[-1] == '/'\
                 or os.path.isfile(orig_path) is False:
@@ -868,19 +806,12 @@ class Filemanager(object):
         Rename file or folder
         """
         if not self.validate_request('rename'):
-            return self.ERROR_NOT_ALLOWED
+            return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
         the_dir = self.dir if self.dir is not None else ''
 
-        try:
-            Filemanager.check_access_permission(the_dir, old)
-            Filemanager.check_access_permission(the_dir, new)
-        except Exception as e:
-            res = {
-                'Error': str(e),
-                'Code': 0
-            }
-            return res
+        Filemanager.check_access_permission(the_dir, old)
+        Filemanager.check_access_permission(the_dir, new)
 
         # check if it's dir
         if old[-1] == '/':
@@ -906,39 +837,27 @@ class Filemanager(object):
         try:
             os.rename(oldpath_sys, newpath_sys)
         except Exception as e:
-            code = 0
-            error_msg = "{0} {1}".format(
-                gettext('There was an error renaming the file:'), e)
+            return internal_server_error("{0} {1}".format(
+                gettext('There was an error renaming the file:'), e))
 
-        result = {
+        return {
             'Old Path': old,
             'Old Name': oldname,
             'New Path': newpath,
             'New Name': newname,
-            'Error': error_msg,
-            'Code': code
         }
 
-        return result
-
     def delete(self, path=None, req=None):
         """
         Delete file or folder
         """
         if not self.validate_request('delete'):
-            return self.ERROR_NOT_ALLOWED
+            return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
         the_dir = self.dir if self.dir is not None else ''
         orig_path = "{0}{1}".format(the_dir, path)
 
-        try:
-            Filemanager.check_access_permission(the_dir, path)
-        except Exception as e:
-            res = {
-                'Error': str(e),
-                'Code': 0
-            }
-            return res
+        Filemanager.check_access_permission(the_dir, path)
 
         err_msg = ''
         code = 1
@@ -948,23 +867,17 @@ class Filemanager(object):
             else:
                 os.remove(orig_path)
         except Exception as e:
-            code = 0
-            err_msg = str(e.strerror)
+            return internal_server_error("{0} {1}".format(
+                gettext('There was an error deleting the file:'), e))
 
-        result = {
-            'Path': path,
-            'Error': err_msg,
-            'Code': code
-        }
-
-        return result
+        return make_json_response(status=200)
 
     def add(self, req=None):
         """
         File upload functionality
         """
         if not self.validate_request('upload'):
-            return self.ERROR_NOT_ALLOWED
+            return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
         the_dir = self.dir if self.dir is not None else ''
         err_msg = ''
@@ -986,7 +899,7 @@ class Filemanager(object):
                         )
                     ).relative_to(the_dir)
             except ValueError:
-                return self.ERROR_NOT_ALLOWED
+                return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
             with open(new_name, 'wb') as f:
                 while True:
@@ -996,25 +909,15 @@ class Filemanager(object):
                         break
                     f.write(data)
         except Exception as e:
-            code = 0
-            err_msg = str(e.strerror) if hasattr(e, 'strerror') else str(e)
+            return internal_server_error("{0} {1}".format(
+                gettext('There was an error adding the file:'), e))
 
-        try:
-            Filemanager.check_access_permission(the_dir, path)
-        except Exception as e:
-            res = {
-                'Error': str(e),
-                'Code': 0
-            }
-            return res
+        Filemanager.check_access_permission(the_dir, path)
 
-        result = {
+        return {
             'Path': path,
             'Name': new_name,
-            'Error': err_msg,
-            'Code': code
         }
-        return result
 
     def is_file_exist(self, path, name, req=None):
         """
@@ -1026,48 +929,40 @@ class Filemanager(object):
 
         name = unquote(name)
         path = unquote(path)
-        try:
-            orig_path = "{0}{1}".format(the_dir, path)
-            Filemanager.check_access_permission(
-                the_dir, "{}{}".format(path, name))
 
-            new_name = "{0}{1}".format(orig_path, name)
-            if not os.path.exists(new_name):
-                code = 0
-        except Exception as e:
+        orig_path = "{0}{1}".format(the_dir, path)
+        Filemanager.check_access_permission(
+            the_dir, "{}{}".format(path, name))
+
+        new_name = "{0}{1}".format(orig_path, name)
+        if not os.path.exists(new_name):
             code = 0
-            if hasattr(e, 'strerror'):
-                err_msg = str(e.strerror)
-            else:
-                err_msg = str(e)
 
-        result = {
+        return {
             'Path': path,
             'Name': name,
-            'Error': err_msg,
-            'Code': code
+            'Code': code,
         }
 
-        return result
-
     @staticmethod
-    def get_new_name(in_dir, path, new_name, count=1):
+    def get_new_name(in_dir, path, name):
         """
         Utility to provide new name for folder if file
         with same name already exists
         """
-        last_char = new_name[-1]
-        t_new_path = "{}/{}{}_{}".format(in_dir, path, new_name, count)
-        if last_char == 'r' and not path_exists(t_new_path):
-            return t_new_path, new_name
-        else:
-            last_char = int(t_new_path[-1]) + 1
-            new_path = "{}/{}{}_{}".format(in_dir, path, new_name, last_char)
-            if path_exists(new_path):
-                count += 1
-                return Filemanager.get_new_name(in_dir, path, new_name, count)
+        new_name = name
+        count = 0
+        while True:
+            file_path = "{}{}/".format(path, new_name)
+            create_path = file_path
+            if in_dir != "":
+                create_path = "{}/{}".format(in_dir, file_path)
+
+            if not path_exists(create_path):
+                return create_path, file_path, new_name
             else:
-                return new_path, new_name
+                count += 1
+                new_name = "{}_{}".format(name, count)
 
     @staticmethod
     def check_file_for_bom_and_binary(filename, enc="utf-8"):
@@ -1125,17 +1020,15 @@ class Filemanager(object):
                 append({os.path.basename(filename): enc})
 
         except IOError as ex:
-            status = False
             # we don't want to expose real path of file
             # so only show error message.
             if ex.strerror == 'Permission denied':
-                err_msg = str(ex.strerror)
+                return unauthorized(str(ex.strerror))
             else:
-                err_msg = str(ex)
+                return internal_server_error(str(ex))
 
         except Exception as ex:
-            status = False
-            err_msg = str(ex)
+            return internal_server_error(str(ex))
 
         # Remove root storage path from error message
         # when running in Server mode
@@ -1146,52 +1039,30 @@ class Filemanager(object):
 
         return status, err_msg, is_binary, is_startswith_bom, enc
 
-    def addfolder(self, path, name):
+    def addfolder(self, path, name, req=None):
         """
         Functionality to create new folder
         """
         if not self.validate_request('create'):
-            return self.ERROR_NOT_ALLOWED
+            return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
-        the_dir = self.dir if self.dir is not None else ''
+        user_dir = self.dir if self.dir is not None else ''
+
+        Filemanager.check_access_permission(user_dir, "{}{}".format(
+            path, name))
 
+        create_path, new_path, new_name = \
+            self.get_new_name(user_dir, path, name)
         try:
-            Filemanager.check_access_permission(the_dir, "{}{}".format(
-                path, name))
+            os.mkdir(create_path)
         except Exception as e:
-            res = {
-                'Error': str(e),
-                'Code': 0
-            }
-            return res
-
-        if the_dir != "":
-            new_path = "{}/{}{}/".format(the_dir, path, name)
-        else:
-            new_path = "{}{}/".format(path, name)
-
-        err_msg = ''
-        code = 1
-        new_name = name
-        if not path_exists(new_path):
-            try:
-                os.mkdir(new_path)
-            except Exception as e:
-                code = 0
-                err_msg = str(e.strerror)
-        else:
-            new_path, new_name = self.get_new_name(the_dir, path, name)
-            try:
-                os.mkdir(new_path)
-            except Exception as e:
-                code = 0
-                err_msg = str(e.strerror)
+            return internal_server_error(str(e))
 
         result = {
             'Parent': path,
+            'Path': new_path,
             'Name': new_name,
-            'Error': err_msg,
-            'Code': code
+            'Date Modified': time.ctime(time.time())
         }
 
         return result
@@ -1201,20 +1072,14 @@ class Filemanager(object):
         Functionality to download file
         """
         if not self.validate_request('download'):
-            return self.ERROR_NOT_ALLOWED
+            return unauthorized(self.ERROR_NOT_ALLOWED['Error'])
 
         the_dir = self.dir if self.dir is not None else ''
         orig_path = "{0}{1}".format(the_dir, path)
 
-        try:
-            Filemanager.check_access_permission(
-                the_dir, "{}{}".format(path, path)
-            )
-        except Exception as e:
-            resp = Response(str(e))
-            resp.headers['Content-Disposition'] = \
-                'attachment; filename=' + name
-            return resp
+        Filemanager.check_access_permission(
+            the_dir, "{}{}".format(path, path)
+        )
 
         name = os.path.basename(path)
         if orig_path and len(orig_path) > 0:
@@ -1232,12 +1097,7 @@ class Filemanager(object):
     def permission(self, path=None, req=None):
         the_dir = self.dir if self.dir is not None else ''
         res = {'Code': 1}
-        try:
-            Filemanager.check_access_permission(the_dir, path)
-        except Exception as e:
-            err_msg = str(e)
-            res['Code'] = 0
-            res['Error'] = err_msg
+        Filemanager.check_access_permission(the_dir, path)
         return res
 
 
@@ -1272,9 +1132,12 @@ def file_manager(trans_id):
         }
         mode = req.args['mode']
 
+    func = getattr(my_fm, mode)
     try:
-        func = getattr(my_fm, mode)
         res = func(**kwargs)
-        return make_json_response(data={'result': res, 'status': True})
-    except Exception:
-        return getattr(my_fm, mode)(**kwargs)
+    except PermissionError as e:
+        return unauthorized(str(e))
+
+    if type(res) == Response:
+        return res
+    return make_json_response(data={'result': res, 'status': True})
diff --git a/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx b/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx
new file mode 100644
index 000000000..2c8bd8aa6
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/FileManagerModule.jsx
@@ -0,0 +1,121 @@
+
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+import gettext from 'sources/gettext';
+import Notifier from '../../../../static/js/helpers/Notifier';
+import React from 'react';
+import FileManager from './components/FileManager';
+import { getBrowser } from '../../../../static/js/utils';
+
+export default class FileManagerModule {
+  static instance;
+
+  static getInstance(...args) {
+    if(!FileManagerModule.instance) {
+      FileManagerModule.instance = new FileManagerModule(...args);
+    }
+    return FileManagerModule.instance;
+  }
+
+  constructor(pgAdmin) {
+    this.pgAdmin = pgAdmin;
+  }
+
+  init() {
+    if(this.initialized)
+      return;
+    this.initialized = true;
+
+    if(this.pgAdmin.server_mode == 'True') {
+      // Define the nodes on which the menus to be appear
+      this.pgAdmin.Browser.add_menus([{
+        name: 'storage_manager',
+        module: this,
+        applies: ['tools'],
+        callback: 'openStorageManager',
+        priority: 11,
+        label: gettext('Storage Manager...'),
+        enable: true,
+      }]);
+    }
+  }
+
+  openStorageManager(path) {
+    this.show({
+      dialog_type: 'storage_dialog',
+      supported_types: ['sql', 'csv', 'json', '*'],
+      dialog_title: gettext('Storage Manager'),
+      path: path,
+    });
+  }
+
+  showInternal(params, onOK, onCancel, modalObj) {
+    const modal = modalObj || Notifier;
+    let title = params.dialog_title;
+    if(!title) {
+      if(params.dialog_type == 'create_file') {
+        title = gettext('Save File');
+      } else if(params.dialog_type == 'select_file') {
+        title = gettext('Select File');
+      } else {
+        title = gettext('Storage Manager');
+      }
+    }
+    modal.showModal(title, (closeModal)=>{
+      return (
+        <FileManager
+          params={params}
+          closeModal={closeModal}
+          onCancel={onCancel}
+          onOK={onOK}
+        />
+      );
+    }, {
+      isResizeable: true,
+      onClose: onCancel,
+      dialogWidth: 700, dialogHeight: 400
+    });
+  }
+
+  showNative(params, onOK, onCancel) {
+    // https://docs.nwjs.io/en/latest/References/Changes%20to%20DOM/
+    let fileEle = document.createElement('input');
+    let accept = params.supported_types?.map((v)=>(v=='*' ? '' : `.${v}`))?.join(',');
+    fileEle.setAttribute('type', 'file');
+    fileEle.setAttribute('accept', accept);
+    fileEle.onchange = (e)=>{
+      if(e.target.value) {
+        onOK?.(e.target.value);
+      } else {
+        onCancel?.();
+      }
+    };
+    if(params.dialog_type == 'create_file') {
+      fileEle.setAttribute('nwsaveas', '');
+    } else if(params.dialog_type == 'select_folder') {
+      fileEle.setAttribute('nwdirectory', '');
+    }
+    fileEle.dispatchEvent(new MouseEvent('click'));
+  }
+
+  show(params, onOK, onCancel, modalObj) {
+    let {name: browser} = getBrowser();
+    if(browser == 'Nwjs') {
+      try {
+        this.showNative(params, onOK, onCancel);
+      } catch {
+        // Fall back to internal
+        this.showInternal(params, onOK, onCancel, modalObj);
+      }
+    } else {
+      // Fall back to internal
+      this.showInternal(params, onOK, onCancel, modalObj);
+    }
+  }
+}
diff --git a/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx b/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx
new file mode 100644
index 000000000..abc019660
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/components/FileManager.jsx
@@ -0,0 +1,746 @@
+import { Box, makeStyles } from '@material-ui/core';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { DefaultButton, PgButtonGroup, PgIconButton, PrimaryButton } from '../../../../../static/js/components/Buttons';
+import { useModalStyles } from '../../../../../static/js/helpers/ModalProvider';
+import CloseIcon from '@material-ui/icons/CloseRounded';
+import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
+import HomeRoundedIcon from '@material-ui/icons/HomeRounded';
+import ArrowUpwardRoundedIcon from '@material-ui/icons/ArrowUpwardRounded';
+import MoreHorizRoundedIcon from '@material-ui/icons/MoreHorizRounded';
+import SyncRoundedIcon from '@material-ui/icons/SyncRounded';
+import CreateNewFolderRoundedIcon from '@material-ui/icons/CreateNewFolderRounded';
+import GetAppRoundedIcon from '@material-ui/icons/GetAppRounded';
+import gettext from 'sources/gettext';
+import clsx from 'clsx';
+import { FormFooterMessage, InputSelectNonSearch, InputText, MESSAGE_TYPE } from '../../../../../static/js/components/FormComponents';
+import ListView from './ListView';
+import { PgMenu, PgMenuDivider, PgMenuItem, usePgMenuGroup } from '../../../../../static/js/components/Menu';
+import getApiInstance, { parseApiError } from '../../../../../static/js/api_instance';
+import Loader from 'sources/components/Loader';
+import url_for from 'sources/url_for';
+import Uploader from './Uploader';
+import GridView from './GridView';
+import convert from 'convert-units';
+import PropTypes from 'prop-types';
+import { downloadBlob } from '../../../../../static/js/utils';
+import ErrorBoundary from '../../../../../static/js/helpers/ErrorBoundary';
+
+
+const useStyles = makeStyles((theme)=>({
+  footerSaveAs: {
+    justifyContent: 'initial',
+    padding: '4px 8px',
+    display: 'flex',
+    alignItems: 'center',
+  },
+  footer1: {
+    justifyContent: 'space-between',
+    padding: '4px 8px',
+    display: 'flex',
+    alignItems: 'center',
+  },
+  toolbar: {
+    padding: '4px',
+    display: 'flex',
+    ...theme.mixins.panelBorder?.bottom,
+  },
+  inputFilename: {
+    lineHeight: 1,
+    width: '100%',
+  },
+  inputSearch: {
+    marginLeft: '4px',
+    lineHeight: 1,
+    width: '130px',
+  },
+  formatSelect: {
+    '& .MuiSelect-select': {
+      paddingTop: '4px',
+      paddingBottom: '4px',
+    }
+  },
+  replaceOverlay: {
+    position: 'absolute',
+    top: 0,
+    bottom: 0,
+    left: 0,
+    right: 0,
+    backgroundColor: theme.otherVars.loader.backgroundColor,
+    zIndex: 2,
+    display: 'flex',
+  },
+  replaceDialog: {
+    margin: 'auto',
+    marginLeft: '1rem',
+    marginRight: '1rem',
+    color: theme.palette.text.primary,
+    backgroundColor: theme.palette.background.default,
+    width: '100%',
+    ...theme.mixins.panelBorder.all,
+  }
+}));
+
+export function getComparator(sortColumn) {
+  const key = sortColumn?.columnKey;
+  const dir = sortColumn?.direction == 'ASC' ? 1 : -1;
+  switch (key) {
+  case 'Filename':
+    return (a, b) => {
+      return dir*(a['Filename'].localeCompare(b['Filename']));
+    };
+  case 'Properties.DateModified':
+    return (a, b) => {
+      try {
+        let a1 = new Date(a['Properties']['Date Modified']);
+        let b1 = new Date(b['Properties']['Date Modified']);
+        if(a1 > b1) return dir*1;
+        return dir*(a1 < b1 ? -1 : 0);
+      } catch {
+        return 0;
+      }
+    };
+  case 'Properties.Size':
+    return (a, b) => {
+      const parseAndConvert = (columnVal)=>{
+        if(columnVal.file_type != 'dir' && columnVal['Properties']['Size']) {
+          let [size, unit] = columnVal['Properties']['Size'].split(' ');
+          return convert(size).from(unit.toUpperCase()).to('B');
+        }
+        return -1;
+      };
+      try {
+        let a1 = parseAndConvert(a);
+        let b1 = parseAndConvert(b);
+        if(a1 > b1) return dir*1;
+        return dir*(a1 < b1 ? -1 : 0);
+      } catch {
+        return 0;
+      }
+    };
+  default:
+    return ()=>0;
+  }
+}
+
+export class FileManagerUtils {
+  constructor(api, params) {
+    this.api = api;
+    this.params = params;
+    this.config = {};
+    this.currPath = '';
+    this.separator = '/';
+  }
+
+  get transId() {
+    return this.config.transId;
+  }
+
+  get fileConnectorUrl() {
+    return `${url_for('file_manager.index')}filemanager/${this.transId}/`;
+  }
+
+  get fileRoot() {
+    return this.config.options.fileRoot;
+  }
+
+  get allowedFileTypes() {
+    return this.config.options?.allowed_file_types;
+  }
+
+  get showHiddenFiles() {
+    return this.config.options?.show_hidden_files;
+  }
+
+  set showHiddenFiles(val) {
+    this.config.options.show_hidden_files = val;
+    this.api.put(url_for('file_manager.save_show_hidden_file_option', {
+      trans_id: this.transId,
+    }), {
+      show_hidden: val,
+    }).catch((error)=>{
+      console.error(error);
+      /* Do nothing */
+    });
+  }
+
+  hasCapability(val) {
+    return this.config?.options?.capabilities?.includes(val);
+  }
+
+  async initialize() {
+    let res = await this.api.post(url_for('file_manager.init'), this.params);
+    this.config = res.data.data;
+    if(this.config.options.platform_type == 'win32') {
+      this.separator = '\\';
+    }
+  }
+
+  join(path1, path2) {
+    if(path1.endsWith(this.separator)) {
+      return path1 + path2;
+    }
+    return path1 + this.separator + path2;
+  }
+
+  getExt(filename) {
+    if (filename.split('.').length == 1) {
+      return '';
+    }
+    return filename.split('.').pop();
+  }
+
+  async getFolder(path) {
+    const newPath = path || this.fileRoot;
+    let res = await this.api.post(this.fileConnectorUrl, {
+      'path': newPath,
+      'mode': 'getfolder',
+      'file_type': this.config.options.last_selected_format || '*',
+      'show_hidden': this.showHiddenFiles,
+    });
+    this.currPath = newPath;
+    return res.data.data.result;
+  }
+
+  async addFolder(row) {
+    let res = await this.api.post(this.fileConnectorUrl, {
+      'path': this.currPath,
+      'mode': 'addfolder',
+      'name': row.Filename,
+    });
+    return {
+      Filename: res.data.data.result.Name,
+      Path: res.data.data.result.Path,
+      file_type: 'dir',
+      Properties: {
+        'Date Modified': res.data.data.result['Date Modified'],
+      }
+    };
+  }
+
+  async renameItem(row) {
+    let res = await this.api.post(this.fileConnectorUrl, {
+      'mode': 'rename',
+      'old': row.Path,
+      'new': row.Filename,
+    });
+    return {
+      ...row,
+      Path: res.data.data.result['New Path'],
+      Filename: res.data.data.result['New Name'],
+    };
+  }
+
+  async deleteItem(row, fileName) {
+    const path = fileName ? this.join(row.Path, fileName) : row.Path;
+    await this.api.post(this.fileConnectorUrl, {
+      'mode': 'delete',
+      'path': path,
+    });
+    return path;
+  }
+
+  async uploadItem(fileObj, onUploadProgress) {
+    const formData = new FormData();
+    formData.append('newfile', fileObj);
+    formData.append('mode', 'add');
+    formData.append('currentpath', this.currPath);
+    return this.api({
+      method: 'POST',
+      url: this.fileConnectorUrl,
+      headers: { 'Content-Type': 'multipart/form-data' },
+      data: formData,
+      onUploadProgress: onUploadProgress,
+      maxContentLength: Infinity,
+      maxBodyLength: Infinity,
+    });
+  }
+
+  async setLastVisitedDir(path) {
+    return this.api.post(url_for('file_manager.save_last_dir', {
+      trans_id: this.transId,
+    }), {
+      'path': path,
+    });
+  }
+
+  async downloadFile(row) {
+    let res = await this.api({
+      method: 'POST',
+      url: this.fileConnectorUrl,
+      responseType: 'blob',
+      data: {
+        'mode': 'download',
+        'path': row.Path,
+      },
+    });
+    downloadBlob(res.data, res.headers.filename);
+  }
+
+  setDialogView(view) {
+    this.config.options.defaultViewMode = view;
+    this.api.post(url_for('file_manager.save_file_dialog_view', {
+      trans_id: this.transId,
+    }), {view: view})
+      .catch((err)=>{
+        /* Do not fail anything */
+        console.error(err);
+      });
+  }
+
+  setFileType(fileType) {
+    this.config.options.last_selected_format = fileType;
+    this.api.post(url_for('settings.save_file_format_setting'), this.config.options)
+      .catch((err)=>{
+        /* Do not fail anything */
+        console.error(err);
+      });
+  }
+
+  async checkPermission(path) {
+    let res = await this.api.post(this.fileConnectorUrl, {
+      'path': path,
+      'mode': 'permission',
+    });
+    if (res.data.data.result.Code === 1) {
+      return null;
+    } else {
+      return res.data.data.result.Error;
+    }
+  }
+
+  async isFileExists(path, fileName) {
+    let res = await this.api.post(this.fileConnectorUrl, {
+      'path': path,
+      'name': fileName,
+      'mode': 'is_file_exist',
+    });
+    return Boolean(res.data.data.result.Code);
+  }
+
+  async destroy() {
+    await this.api.delete(url_for('file_manager.delete_trans_id', {
+      'trans_id': this.transId,
+    }));
+  }
+
+  isWinDrive(text) {
+    return text && text.length == 2 && text.endsWith(':') && this.config?.options?.platform_type == 'win32';
+  }
+
+  dirname(path) {
+    let ret = path;
+    if(!path) {
+      return ret;
+    }
+    if(path.endsWith(this.separator)) {
+      ret = ret.slice(0, -1);
+    }
+    if(this.isWinDrive(ret)) {
+      ret = this.separator;
+    } else {
+      ret = ret.slice(0, ret.lastIndexOf(this.separator)+1);
+    }
+    return ret;
+  }
+}
+
+function ReplaceFile({onYes, onNo}) {
+  const classes = useStyles();
+  const modalClasses = useModalStyles();
+  return (
+    <Box className={classes.replaceOverlay}>
+      <Box margin={'8px'} className={classes.replaceDialog}>
+        <Box padding={'1rem'}>{gettext('Are you sure you want to replace this file?')}</Box>
+        <Box className={modalClasses.footer}>
+          <DefaultButton data-test="no" startIcon={<CloseIcon />} onClick={onNo} >{gettext('No')}</DefaultButton>
+          <PrimaryButton data-test="yes" className={modalClasses.margin} startIcon={<CheckRoundedIcon />}
+            onClick={onYes} autoFocus>{gettext('Yes')}</PrimaryButton>
+        </Box>
+      </Box>
+    </Box>
+  );
+}
+ReplaceFile.propTypes = {
+  onYes: PropTypes.func,
+  onNo: PropTypes.func
+};
+
+export default function FileManager({params, closeModal, onOK, onCancel}) {
+  const classes = useStyles();
+  const modalClasses = useModalStyles();
+  const apiObj = useMemo(()=>getApiInstance(), []);
+  const fmUtilsObj = useMemo(()=>new FileManagerUtils(apiObj, params), []);
+
+  const {openMenuName, toggleMenu, onMenuClose} = usePgMenuGroup();
+  const [loaderText, setLoaderText] = useState('Loading...');
+  const [items, setItems] = useState([]);
+  const [path, setPath] = useState('');
+  const [errorMsg, setErrorMsg] = useState('');
+  const [search, setSearch] = useState('');
+  const [saveAs, setSaveAs] = useState('');
+  const [okBtnDisable, setOkBtnDisable] = useState(true);
+  const [downloadBtnDisable, setDownloadBtnDisable] = useState(true);
+  const [viewMode, setViewMode] = useState('list');
+  const [showUploader, setShowUploader] = useState(false);
+  const [[showReplace, onReplaceYes], setReplaceFile] = useState([false, null]);
+  const [fileType, setFileType] = useState('*');
+  const [sortColumns, setSortColumns] = useState([]);
+  const selectedRowIdx = useRef();
+  const optionsRef = React.useRef(null);
+  const saveAsRef = React.useRef(null);
+  const [operation, setOperation] = useState({
+    type: null, idx: null
+  });
+
+  const sortedItems = useMemo(()=>(
+    [...items].sort(getComparator(sortColumns[0]))
+  ), [items, sortColumns]);
+
+  const filteredItems = useMemo(()=>{
+    return sortedItems.filter((i)=>i.Filename?.toLowerCase().includes(search?.toLocaleLowerCase()));
+  }, [items, sortColumns, search]);
+
+  const itemsText = useMemo(()=>{
+    let suffix = items.length == 1 ? 'item' : 'items';
+    if(items.length == filteredItems.length) {
+      return `${items.length} ${suffix}`;
+    }
+    return `${filteredItems.length} of ${items.length} ${suffix}`;
+  }, [items, filteredItems]);
+
+  const openDir = async (dirPath)=>{
+    setErrorMsg('');
+    setLoaderText('Loading...');
+    try {
+      if(fmUtilsObj.isWinDrive(dirPath)) {
+        dirPath += fmUtilsObj.separator;
+      }
+      let newItems = await fmUtilsObj.getFolder(dirPath || fmUtilsObj.currPath);
+      setItems(newItems);
+      setPath(fmUtilsObj.currPath);
+      params.dialog_type == 'storage_dialog' && fmUtilsObj.setLastVisitedDir(fmUtilsObj.currPath);
+    } catch (error) {
+      console.error(error);
+      setErrorMsg(parseApiError(error));
+    }
+    setLoaderText('');
+  };
+  const completeOperation = async (oldRow, newRow, rowIdx, func)=>{
+    setOperation({});
+    if(oldRow?.Filename == newRow.Filename) {
+      setItems((prev)=>[
+        ...prev.slice(0, rowIdx),
+        oldRow,
+        ...prev.slice(rowIdx+1)
+      ]);
+      return;
+    }
+    setItems((prev)=>[
+      ...prev.slice(0, rowIdx),
+      newRow,
+      ...prev.slice(rowIdx+1)
+    ]);
+    try {
+      const actualRow = await func(newRow);
+      setItems((prev)=>[
+        ...prev.slice(0, rowIdx),
+        actualRow,
+        ...prev.slice(rowIdx+1)
+      ]);
+    } catch (error) {
+      setErrorMsg(parseApiError(error));
+      if(oldRow) {
+        setItems((prev)=>[
+          ...prev.slice(0, rowIdx),
+          oldRow,
+          ...prev.slice(rowIdx+1)
+        ]);
+      } else {
+        setItems((prev)=>[
+          ...prev.slice(0, rowIdx),
+          ...prev.slice(rowIdx+1)
+        ]);
+      }
+    }
+  };
+  const onDownload = async ()=>{
+    setLoaderText('Downloading...');
+    try {
+      await fmUtilsObj.downloadFile(filteredItems[selectedRowIdx.current]);
+    } catch (error) {
+      setErrorMsg(parseApiError(error));
+      console.error(error);
+    }
+    setLoaderText('');
+  };
+  const onAddFolder = ()=>{
+    setItems((prev)=>[
+      {Filename: 'Untitled Folder', file_type: 'dir'},
+      ...prev,
+    ]);
+    setOperation({
+      type: 'add',
+      idx: 0,
+      onComplete: async (row, rowIdx)=>{
+        setErrorMsg('');
+        setLoaderText('Creating folder...');
+        await completeOperation(null, row, rowIdx, fmUtilsObj.addFolder.bind(fmUtilsObj));
+        setLoaderText('');
+      }
+    });
+  };
+  const renameSelectedItem = (e)=>{
+    e.keepOpen = false;
+    setErrorMsg('');
+    if(_.isUndefined(selectedRowIdx.current) || _.isNull(selectedRowIdx.current)) {
+      return;
+    }
+    setOperation({
+      type: 'rename',
+      idx: selectedRowIdx.current,
+      onComplete: async (row, rowIdx)=>{
+        setErrorMsg('');
+        setLoaderText('Renaming...');
+        let oldRow = items[rowIdx];
+        await completeOperation(oldRow, row, rowIdx, fmUtilsObj.renameItem.bind(fmUtilsObj));
+        setLoaderText('');
+      }
+    });
+  };
+  const deleteSelectedItem = async (e)=>{
+    e.keepOpen = false;
+    setErrorMsg('');
+    if(_.isUndefined(selectedRowIdx.current) || _.isNull(selectedRowIdx.current)) {
+      return;
+    }
+    setLoaderText('Deleting...');
+    try {
+      await fmUtilsObj.deleteItem(items[selectedRowIdx.current]);
+      setItems((prev)=>[
+        ...prev.slice(0, selectedRowIdx.current),
+        ...prev.slice(selectedRowIdx.current+1),
+      ]);
+    } catch (error) {
+      setErrorMsg(parseApiError(error));
+      console.error(error);
+    }
+    setLoaderText('');
+  };
+  const toggleViewMode = (e, val)=>{
+    e.keepOpen = false;
+    setViewMode(val);
+    fmUtilsObj.setDialogView(val);
+  };
+  const onOkClick = useCallback(async ()=>{
+    setLoaderText('Please wait...');
+    let onOkPath = null;
+    if(params.dialog_type == 'create_file') {
+      let newFileName = saveAs;
+      onOkPath = fmUtilsObj.join(fmUtilsObj.currPath, newFileName);
+      let error = await fmUtilsObj.checkPermission(onOkPath);
+      if(error) {
+        setErrorMsg(error);
+        setLoaderText('');
+        return;
+      }
+      let exists = await fmUtilsObj.isFileExists(fmUtilsObj.currPath, newFileName);
+      if(exists) {
+        setLoaderText('');
+        setReplaceFile([true, async ()=>{
+          await fmUtilsObj.setLastVisitedDir(fmUtilsObj.currPath);
+          onOK?.(onOkPath);
+          closeModal();
+        }]);
+        return;
+      }
+    } else if(selectedRowIdx?.current >= 0 && filteredItems[selectedRowIdx?.current]) {
+      onOkPath = filteredItems[selectedRowIdx?.current]['Path'];
+    }
+    await fmUtilsObj.setLastVisitedDir(fmUtilsObj.currPath);
+    onOK?.(onOkPath);
+    closeModal();
+  }, [filteredItems, saveAs]);
+  const onItemEnter = useCallback(async (row)=>{
+    if(row.file_type == 'dir' || row.file_type == 'drive') {
+      await openDir(row.Path);
+    } else {
+      if(params.dialog_type == 'select_file') {
+        onOkClick();
+      }
+    }
+  }, [filteredItems]);
+  const onItemSelect = useCallback((idx)=>{
+    selectedRowIdx.current = idx;
+    okBtnDisableCheck();
+    if(params.dialog_type == 'storage_dialog') {
+      setDownloadBtnDisable(filteredItems[selectedRowIdx.current]?.file_type == 'dir');
+    }
+  }, [filteredItems]);
+  const okBtnDisableCheck = ()=>{
+    let disabled = true;
+    if(params.dialog_type == 'create_file') {
+      disabled = !saveAs.trim();
+    } else if(selectedRowIdx.current >= 0 && filteredItems[selectedRowIdx.current]) {
+      let selectedfileType = filteredItems[selectedRowIdx.current]?.file_type;
+      if((selectedfileType == 'dir' && fmUtilsObj.hasCapability('select_folder'))
+      || (selectedfileType != 'dir' && fmUtilsObj.hasCapability('select_file'))) {
+        disabled = false;
+      }
+    }
+    setOkBtnDisable(disabled);
+  };
+  useEffect(()=>{
+    const init = async ()=>{
+      await fmUtilsObj.initialize();
+      setFileType(fmUtilsObj.config?.options?.last_selected_format || '*');
+      if(fmUtilsObj.config?.options?.defaultViewMode) {
+        setViewMode(fmUtilsObj.config?.options?.defaultViewMode);
+      } else {
+        setViewMode('list');
+      }
+      openDir(params?.path);
+      params?.path && fmUtilsObj.setLastVisitedDir(params?.path);
+    };
+    init();
+    setTimeout(()=>{
+      saveAsRef.current && saveAsRef.current.focus();
+    }, 300);
+    return ()=>{
+      fmUtilsObj.destroy();
+    };
+  }, []);
+
+  useEffect(()=>{
+    okBtnDisableCheck();
+  }, [saveAs]);
+
+  return (
+    <ErrorBoundary>
+      <Box display="flex" flexDirection="column" height="100%" className={modalClasses.container}>
+        <Box flexGrow="1" display="flex" flexDirection="column" position="relative" overflow="hidden">
+          <Loader message={loaderText} />
+          {showReplace && <ReplaceFile onNo={()=>setReplaceFile([false, null])} onYes={onReplaceYes}/>}
+          <Box className={classes.toolbar}>
+            <PgButtonGroup size="small" style={{flexGrow: 1}}>
+              <PgIconButton title={gettext('Home')} onClick={async ()=>{
+                await openDir(fmUtilsObj.config?.options?.homedir);
+              }} icon={<HomeRoundedIcon />} disabled={showUploader} />
+              <PgIconButton title={gettext('Go Back')} onClick={async ()=>{
+                await openDir(fmUtilsObj.dirname(fmUtilsObj.currPath));
+              }} icon={<ArrowUpwardRoundedIcon />} disabled={!fmUtilsObj.dirname(fmUtilsObj.currPath) || showUploader} />
+              <InputText className={classes.inputFilename}
+                data-label="file-path"
+                controlProps={{maxLength: null}}
+                onKeyDown={async (e)=>{
+                  if(e.code === 'Enter') {
+                    e.preventDefault();
+                    await openDir(path);
+                  }
+                }} value={path} onChange={setPath} readonly={showUploader} />
+              <PgIconButton title={gettext('Refresh')} onClick={async ()=>{
+                await openDir();
+              }} icon={<SyncRoundedIcon />} disabled={showUploader} />
+            </PgButtonGroup>
+            <InputText type="search" className={classes.inputSearch} data-label="search" placeholder='Search' value={search} onChange={setSearch} />
+            <PgButtonGroup size="small" style={{marginLeft: '4px'}}>
+              {params.dialog_type == 'storage_dialog' &&
+              <PgIconButton title={gettext('Download')} icon={<GetAppRoundedIcon />}
+                onClick={onDownload} disabled={showUploader || downloadBtnDisable} />}
+              {fmUtilsObj.hasCapability('create') && <PgIconButton title={gettext('New Folder')} icon={<CreateNewFolderRoundedIcon />}
+                onClick={onAddFolder} disabled={showUploader} />}
+            </PgButtonGroup>
+            <PgButtonGroup size="small" style={{marginLeft: '4px'}}>
+              <PgIconButton title={gettext('Options')} icon={<MoreHorizRoundedIcon />}
+                name="menu-options" ref={optionsRef} onClick={toggleMenu} disabled={showUploader} />
+            </PgButtonGroup>
+            <PgMenu
+              anchorRef={optionsRef}
+              open={openMenuName=='menu-options'}
+              onClose={onMenuClose}
+              label={gettext('Options')}
+            >
+              {fmUtilsObj.hasCapability('rename') && <PgMenuItem hasCheck onClick={renameSelectedItem}>
+                {gettext('Rename')}
+              </PgMenuItem>}
+              {fmUtilsObj.hasCapability('delete') && <PgMenuItem hasCheck onClick={deleteSelectedItem}>
+                {gettext('Delete')}
+              </PgMenuItem>}
+              {fmUtilsObj.hasCapability('upload') && <>
+                <PgMenuDivider />
+                <PgMenuItem hasCheck onClick={(e)=>{
+                  e.keepOpen = false;
+                  setShowUploader(true);
+                }}>{gettext('Upload')}</PgMenuItem>
+              </>}
+              <PgMenuDivider />
+              <PgMenuItem hasCheck checked={viewMode == 'list'} onClick={(e)=>toggleViewMode(e, 'list')}>{gettext('List View')}</PgMenuItem>
+              <PgMenuItem hasCheck checked={viewMode == 'grid'} onClick={(e)=>toggleViewMode(e, 'grid')}>{gettext('Grid View')}</PgMenuItem>
+              <PgMenuDivider />
+              <PgMenuItem hasCheck checked={fmUtilsObj.showHiddenFiles} onClick={async (e)=>{
+                e.keepOpen = false;
+                fmUtilsObj.showHiddenFiles = !fmUtilsObj.showHiddenFiles;
+                await openDir();
+              }}>{gettext('Show Hidden Files')}</PgMenuItem>
+            </PgMenu>
+          </Box>
+          <Box flexGrow="1" display="flex" flexDirection="column" position="relative" overflow="hidden">
+            {showUploader &&
+              <Uploader fmUtilsObj={fmUtilsObj}
+                onClose={async (filesUploaded)=>{
+                  setShowUploader(false);
+                  if(filesUploaded) {
+                    await openDir();
+                  }
+                }}/>}
+            {viewMode == 'list' &&
+            <ListView key={fmUtilsObj.currPath} items={filteredItems} operation={operation} onItemEnter={onItemEnter}
+              onItemSelect={onItemSelect} sortColumns={sortColumns} onSortColumnsChange={setSortColumns}/>}
+            {viewMode == 'grid' &&
+            <GridView key={fmUtilsObj.currPath} items={filteredItems} operation={operation} onItemEnter={onItemEnter}
+              onItemSelect={onItemSelect} />}
+            <FormFooterMessage type={MESSAGE_TYPE.ERROR} message={errorMsg} closable onClose={()=>setErrorMsg('')}  />
+            {params.dialog_type == 'create_file' &&
+            <Box className={clsx(modalClasses.footer, classes.footerSaveAs)}>
+              <span style={{whiteSpace: 'nowrap', marginRight: '4px'}}>Save as</span>
+              <InputText inputRef={saveAsRef} autoFocus style={{height: '28px'}} value={saveAs} onChange={setSaveAs} />
+            </Box>}
+            <Box className={clsx(modalClasses.footer, classes.footer1)}>
+              <Box>{itemsText}</Box>
+              <Box>
+                <span style={{marginRight: '8px'}}>File Format</span>
+                <InputSelectNonSearch value={fileType} className={classes.formatSelect}
+                  onChange={(e)=>{
+                    let val = e.target.value;
+                    fmUtilsObj.setFileType(val);
+                    openDir(fmUtilsObj.currPath);
+                    setFileType(val);
+                  }}
+                  options={fmUtilsObj.allowedFileTypes?.map((type)=>({
+                    label: type == '*' ? gettext('All Files') : type, value: type
+                  }))} />
+              </Box>
+            </Box>
+          </Box>
+        </Box>
+        <Box className={modalClasses.footer}>
+          <PgButtonGroup style={{flexGrow: 1}}>
+          </PgButtonGroup>
+          <DefaultButton data-test="close" startIcon={<CloseIcon />} onClick={()=>{
+            onCancel?.();
+            closeModal();
+          }} >{gettext('Cancel')}</DefaultButton>
+          {params.dialog_type != 'storage_dialog' &&
+            <PrimaryButton data-test="save" className={modalClasses.margin} startIcon={<CheckRoundedIcon />}
+              onClick={()=>onOkClick(saveAs)} disabled={okBtnDisable || showUploader}>{params.btn_primary || gettext('Select')}</PrimaryButton>}
+        </Box>
+      </Box>
+    </ErrorBoundary>
+  );
+}
+
+FileManager.propTypes = {
+  params: PropTypes.object,
+  closeModal: PropTypes.func,
+  onOK: PropTypes.func,
+  onCancel: PropTypes.func,
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/components/FileManagerConstants.js b/web/pgadmin/misc/file_manager/static/js/components/FileManagerConstants.js
new file mode 100644
index 000000000..657bf66f5
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/components/FileManagerConstants.js
@@ -0,0 +1,11 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2022, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+export const FILE_MANGER_EVENTS = {
+  ADD_FOLDER: 'ADD_FOLDER'
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/components/GridView.jsx b/web/pgadmin/misc/file_manager/static/js/components/GridView.jsx
new file mode 100644
index 000000000..39254aeae
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/components/GridView.jsx
@@ -0,0 +1,141 @@
+import { Box, makeStyles } from '@material-ui/core';
+import React, {useState, useEffect, useRef, useLayoutEffect} from 'react';
+import FolderIcon from '@material-ui/icons/Folder';
+import DescriptionIcon from '@material-ui/icons/Description';
+import LockRoundedIcon from '@material-ui/icons/LockRounded';
+import StorageRoundedIcon from '@material-ui/icons/StorageRounded';
+import PropTypes from 'prop-types';
+
+
+const useStyles = makeStyles((theme)=>({
+  grid: {
+    display: 'flex',
+    fontSize: '13px',
+    flexWrap: 'wrap',
+    overflow: 'hidden',
+  },
+  gridItem: {
+    width: '100px',
+    margin: '4px',
+    textAlign: 'center',
+    position: 'relative',
+  },
+  gridItemContent: {
+    padding: '4px',
+    border: '1px solid transparent',
+    cursor: 'pointer',
+    '&[aria-selected=true]': {
+      backgroundColor: theme.palette.primary.light,
+      color: theme.otherVars.qtDatagridSelectFg,
+      borderColor: theme.palette.primary.main,
+    },
+  },
+  gridFilename: {
+    overflowWrap: 'break-word',
+  },
+  gridItemEdit: {
+    border: `1px solid ${theme.otherVars.inputBorderColor}`,
+    backgroundColor: theme.palette.background.default,
+  },
+  protected: {
+    height: '1.25rem',
+    width: '1.25rem',
+    position: 'absolute',
+    left: '52px',
+    color: theme.palette.error.main,
+    backgroundColor: 'inherit',
+  }
+}));
+
+export function ItemView({idx, row, selected, onItemSelect, onItemEnter, onEditComplete}) {
+  const classes = useStyles();
+  const editMode = Boolean(onEditComplete);
+  const fileNameRef = useRef();
+
+  useLayoutEffect(()=>{
+    if(editMode) {
+      fileNameRef.current?.focus();
+    }
+  }, [editMode]);
+
+  const handleKeyDown = (e)=>{
+    if(e.code == 'Tab') {
+      e.stopPropagation();
+    }
+    if(e.code == 'Enter') {
+      onEditComplete({...row, Filename: fileNameRef.current.textContent?.trim()});
+    }
+    if(e.code == 'Escape') {
+      e.preventDefault();
+      e.stopPropagation();
+      fileNameRef.current.textContent = row.Filename;
+      onEditComplete(row);
+    }
+  };
+  
+  let icon = <DescriptionIcon style={{fontSize: '2.5rem'}} />;
+  if(row.file_type == 'dir') {
+    icon = <FolderIcon style={{fontSize: '2.5rem'}} />;
+  } else if(row.file_type == 'drive') {
+    icon = <StorageRoundedIcon style={{fontSize: '2.5rem'}} />;
+  }
+
+  return (
+    <li className={classes.gridItem} aria-rowindex={idx} aria-selected={selected}>
+      <div className={classes.gridItemContent} aria-selected={selected} onClick={()=>onItemSelect(idx)} onDoubleClick={()=>onItemEnter(row)}>
+        <div>
+          {icon}
+          {Boolean(row.Protected) && <LockRoundedIcon className={classes.protected}/>}
+        </div>
+        <div ref={fileNameRef} onKeyDown={handleKeyDown} onBlur={()=>onEditComplete(row)}
+          className={editMode ? classes.gridItemEdit : classes.gridFilename} suppressContentEditableWarning={true}
+          contentEditable={editMode} data-test="filename-div">{row['Filename']}</div>
+      </div>
+    </li>
+  );
+}
+ItemView.propTypes = {
+  idx: PropTypes.number,
+  row: PropTypes.object,
+  selected: PropTypes.bool,
+  onItemSelect: PropTypes.func,
+  onItemEnter: PropTypes.func,
+  onEditComplete: PropTypes.func,
+};
+
+export default function GridView({items, operation, onItemSelect, onItemEnter}) {
+  const classes = useStyles();
+  const [selectedIdx, setSelectedIdx] = useState(null);
+  const gridRef = useRef();
+
+  useEffect(()=>{
+    onItemSelect(selectedIdx);
+  }, [selectedIdx]);
+
+
+  let onEditComplete = null;
+  if(operation?.onComplete) {
+    onEditComplete = (row)=>{
+      operation?.onComplete?.(row, operation.idx);
+    };
+  }
+
+  return (
+    <Box flexGrow={1} overflow="hidden auto">
+      <ul ref={gridRef} className={classes.grid}>
+        {items.map((item, i)=>(
+          <ItemView key={i} idx={i} row={item} selected={selectedIdx==i} onItemSelect={setSelectedIdx}
+            onItemEnter={onItemEnter} onEditComplete={operation.idx==i ? onEditComplete : null} />)
+        )}
+      </ul>
+      {items.length == 0 && <Box textAlign="center" p={1}>No files/folders found</Box>}
+    </Box>
+  );
+}
+
+GridView.propTypes = {
+  items: PropTypes.arrayOf(PropTypes.object),
+  operation: PropTypes.object,
+  onItemSelect: PropTypes.func,
+  onItemEnter: PropTypes.func,
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/components/ListView.jsx b/web/pgadmin/misc/file_manager/static/js/components/ListView.jsx
new file mode 100644
index 000000000..f74d3e87c
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/components/ListView.jsx
@@ -0,0 +1,233 @@
+import { Box, makeStyles } from '@material-ui/core';
+import React, { useContext, useRef, useEffect } from 'react';
+import { Row } from 'react-data-grid';
+import PgReactDataGrid from '../../../../../static/js/components/PgReactDataGrid';
+import FolderIcon from '@material-ui/icons/Folder';
+import StorageRoundedIcon from '@material-ui/icons/StorageRounded';
+import DescriptionIcon from '@material-ui/icons/Description';
+import LockRoundedIcon from '@material-ui/icons/LockRounded';
+import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
+import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
+import PropTypes from 'prop-types';
+
+const useStyles = makeStyles((theme)=>({
+  grid: {
+    fontSize: '13px',
+    '& .rdg-header-row': {
+      '& .rdg-cell': {
+        padding: '0px 4px',
+      }
+    },
+    '& .rdg-cell': {
+      padding: '0px 4px',
+      '&[aria-colindex="1"]': {
+        padding: '0px 4px',
+        '&.rdg-editor-container': {
+          padding: '0px',
+        },
+      }
+    }
+  },
+  input: {
+    appearance: 'none',
+    width: '100%',
+    height: '100%',
+    verticalAlign: 'top',
+    outline: 'none',
+    backgroundColor: theme.palette.background.default,
+    color: theme.palette.text.primary,
+    border: 0,
+    boxShadow: 'inset 0 0 0 1.5px '+theme.palette.primary.main,
+    padding: '0 2px',
+    '::selection': {
+      background: theme.palette.primary.light,
+    }
+  },
+  protected: {
+    height: '0.75rem',
+    width: '0.75rem',
+    position: 'absolute',
+    left: '14px',
+    top: '5px',
+    color: theme.palette.error.main,
+    backgroundColor: 'inherit',
+  }
+}));
+
+export const GridContextUtils = React.createContext();
+
+export function FileNameEditor({row, column, onRowChange, onClose}) {
+  const classes = useStyles();
+  const value = row[column.key] ?? '';
+  const [localVal, setLocalVal] = React.useState(value);
+  const localValRef = useRef(localVal);
+
+  localValRef.current = localVal;
+  useEffect(()=>{
+    return ()=>{
+      /* When unmounted, trigger onRowChange */
+      onRowChange({ ...row, [column.key]: localValRef.current?.trim()}, true);
+    };
+  }, []);
+
+  const onKeyDown = (e)=>{
+    if(e.code === 'Tab' || e.code === 'Enter') {
+      e.preventDefault();
+      onClose();
+    }
+  };
+  return (
+    <input
+      className={classes.input}
+      value={localVal}
+      onChange={(e)=>{
+        setLocalVal(e.target.value);
+      }}
+      onKeyDown={onKeyDown}
+      autoFocus
+    />
+  );
+}
+
+FileNameEditor.propTypes = {
+  row: PropTypes.object,
+  column: PropTypes.object,
+  onRowChange: PropTypes.func,
+  onClose: PropTypes.func,
+};
+
+function CutomSortIcon({sortDirection}) {
+  if(sortDirection == 'DESC') {
+    return <KeyboardArrowDownIcon style={{fontSize: '1.2rem'}} />;
+  } else if(sortDirection == 'ASC') {
+    return <KeyboardArrowUpIcon style={{fontSize: '1.2rem'}} />;
+  }
+  return <></>;
+}
+CutomSortIcon.propTypes = {
+  sortDirection: PropTypes.string,
+};
+
+export function CustomRow({inTest=false, ...props}) {
+  const gridUtils = useContext(GridContextUtils);
+  const handleKeyDown = (e)=>{
+    if(e.code == 'Tab' || e.code == 'ArrowRight' || e.code == 'ArrowLeft') {
+      e.stopPropagation();
+    }
+    if(e.code == 'Enter') {
+      gridUtils.onItemEnter(props.row);
+    }
+  };
+  const isRowSelected = props.selectedCellIdx >= 0;
+  useEffect(()=>{
+    if(isRowSelected) {
+      gridUtils.onItemSelect(props.rowIdx);
+    }
+  }, [props.selectedCellIdx]);
+  if(inTest) {
+    return <div data-test='test-div' tabIndex={0}  onKeyDown={handleKeyDown}></div>;
+  }
+  return (
+    <Row {...props} onKeyDown={handleKeyDown} onRowDoubleClick={(row)=>gridUtils.onItemEnter(row)}
+      selectCell={(row, column)=>props.selectCell(row, column)} aria-selected={isRowSelected}/>
+  );
+}
+CustomRow.propTypes = {
+  inTest: PropTypes.bool,
+  row: PropTypes.object,
+  selectedCellIdx: PropTypes.number,
+  rowIdx: PropTypes.number,
+  selectCell: PropTypes.func,
+};
+
+function FileNameFormatter({row}) {
+  const classes = useStyles();
+  let icon = <DescriptionIcon style={{fontSize: '1.2rem'}} />;
+  if(row.file_type == 'dir') {
+    icon = <FolderIcon style={{fontSize: '1.2rem'}} />;
+  } else if(row.file_type == 'drive') {
+    icon = <StorageRoundedIcon style={{fontSize: '1.2rem'}} />;
+  }
+  return <>
+    {icon}
+    {Boolean(row.Protected) && <LockRoundedIcon className={classes.protected}/>}
+    <span style={{marginLeft: '4px'}}>{row['Filename']}</span>
+  </>;
+}
+FileNameFormatter.propTypes = {
+  row: PropTypes.object,
+};
+
+const columns = [
+  {
+    key: 'Filename',
+    name: 'Name',
+    formatter: FileNameFormatter,
+    editor: FileNameEditor,
+    editorOptions: {
+      editOnClick: false,
+      onCellKeyDown: (e)=>e.preventDefault(),
+    }
+  },{
+    key: 'Properties.DateModified',
+    name: 'Date Modified',
+    formatter: ({row})=><>{row.Properties?.['Date Modified']}</>
+  },{
+    key: 'Properties.Size',
+    name: 'Size',
+    formatter: ({row})=><>{row.file_type != 'dir' && row.Properties?.['Size']}</>
+  }
+];
+
+
+export default function ListView({items, operation, onItemSelect, onItemEnter, ...props}) {
+  const classes = useStyles();
+  const gridRef = useRef();
+
+  useEffect(()=>{
+    if(operation.type) {
+      operation.type == 'add' && gridRef.current.scrollToRow(operation.idx);
+      gridRef.current.selectCell({idx: 0, rowIdx: operation.idx}, true);
+    }
+  }, [operation]);
+
+  useEffect(()=>{
+    gridRef.current.selectCell({idx: 0, rowIdx: 0});
+  }, [gridRef.current?.element]);
+
+  return (
+    <GridContextUtils.Provider value={{onItemEnter: onItemEnter, onItemSelect: onItemSelect}}>
+      <PgReactDataGrid
+        gridRef={gridRef}
+        id="files"
+        className={classes.grid}
+        hasSelectColumn={false}
+        columns={columns}
+        rows={items}
+        defaultColumnOptions={{
+          sortable: true,
+          resizable: true
+        }}
+        headerRowHeight={28}
+        rowHeight={28}
+        mincolumnWidthBy={25}
+        enableCellSelect={false}
+        components={{
+          sortIcon: CutomSortIcon,
+          rowRenderer: CustomRow,
+          noRowsFallback: <Box textAlign="center" gridColumn="1/-1" p={1}>No files/folders found</Box>,
+        }}
+        onRowsChange={(rows)=>{
+          operation?.onComplete?.(rows[operation.idx], operation.idx);
+        }}
+        {...props}
+      />
+    </GridContextUtils.Provider>
+  );
+}
+ListView.propTypes = {
+  items: PropTypes.arrayOf(PropTypes.object),
+  operation: PropTypes.object,
+  onItemSelect: PropTypes.func,
+  onItemEnter: PropTypes.func,
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/components/Uploader.jsx b/web/pgadmin/misc/file_manager/static/js/components/Uploader.jsx
new file mode 100644
index 000000000..50f659e87
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/components/Uploader.jsx
@@ -0,0 +1,210 @@
+import React, { useCallback, useReducer, useEffect, useMemo } from 'react';
+import { Box, List, ListItem, makeStyles } from '@material-ui/core';
+import CloseIcon from '@material-ui/icons/CloseRounded';
+import { PgIconButton } from '../../../../../static/js/components/Buttons';
+import gettext from 'sources/gettext';
+import {useDropzone} from 'react-dropzone';
+import { FormFooterMessage, MESSAGE_TYPE } from '../../../../../static/js/components/FormComponents';
+import DeleteIcon from '@material-ui/icons/Delete';
+import convert from 'convert-units';
+import _ from 'lodash';
+import PropTypes from 'prop-types';
+
+const useStyles = makeStyles((theme)=>({
+  root: {
+    position: 'absolute',
+    top: 0,
+    bottom: 0,
+    left: 0,
+    right: 0,
+    zIndex: 1,
+    backgroundColor: theme.palette.background.default,
+    display: 'flex',
+    flexDirection: 'column',
+    padding: '4px',
+  },
+  uploadArea: {
+    border: `1px dashed ${theme.palette.grey[600]}`,
+    display: 'flex',
+    alignItems: 'center',
+    justifyContent: 'center',
+    flexGrow: 1,
+    flexDirection: 'column',
+    cursor: 'move',
+    textAlign: 'center',
+    padding: '4px',
+  },
+  uploadFilesRoot: {
+    width: '350px',
+    border: `1px dashed ${theme.palette.grey[600]}`,
+    borderLeft: 'none',
+    overflowX: 'hidden',
+    overflowY: 'auto'
+  },
+  uploadProgress: {
+    position: 'unset',
+    padding: 0,
+  },
+  uploadPending: {
+
+  }
+}));
+
+export function filesReducer(state, action) {
+  let newState = [...state];
+  switch (action.type) {
+  case 'add':
+    newState.unshift(...action.files.map((file)=>({
+      id: _.uniqueId('f'),
+      file: file,
+      progress: 0,
+      started: false,
+      failed: false,
+      done: false,
+      deleting: false,
+    })));
+    break;
+  case 'started':
+    _.find(newState, (f)=>f.id==action.id).started = true;
+    break;
+  case 'progress':
+    _.find(newState, (f)=>f.id==action.id).progress = action.value;
+    break;
+  case 'failed':
+    _.find(newState, (f)=>f.id==action.id).failed = true;
+    break;
+  case 'done':
+    _.find(newState, (f)=>f.id==action.id).done = true;
+    break;
+  case 'deleting':
+    _.find(newState, (f)=>f.id==action.id).deleting = true;
+    break;
+  case 'delete':
+    newState = newState.filter((f)=>f.id!=action.id) || [];
+    break;
+  default:
+    break;
+  }
+  return newState;
+}
+
+export function getFileSize(bytes) {
+  let conVal = convert(bytes).from('B').toBest();
+  conVal.val = Math.round(conVal.val * 100) / 100;
+  return `${conVal.val} ${conVal.unit}`;
+}
+
+export function UploadedFile({upfile, deleteFile}) {
+  let type = MESSAGE_TYPE.INFO;
+  let message = `Uploading... ${upfile.progress?.toString() || ''}%`;
+  if(upfile.done) {
+    type = MESSAGE_TYPE.SUCCESS;
+    message = 'Uploaded!';
+  } else if(upfile.failed) {
+    type = MESSAGE_TYPE.ERROR;
+    message = 'Failed!';
+  }
+
+  return (
+    <ListItem style={{cursor: 'auto'}}>
+      <Box display="flex" alignItems="flex-start">
+        <Box overflow="hidden" style={{overflowWrap: 'break-word'}} >{upfile.file.name}</Box>
+        <Box marginLeft="auto">
+          <PgIconButton title={gettext('Delete')} icon={<DeleteIcon  />} size="xs" noBorder onClick={deleteFile} />
+        </Box>
+      </Box>
+      <span>{useMemo(()=>getFileSize(upfile.file.size), [])}</span>
+      <FormFooterMessage type={type} message={message}
+        closable={false} showIcon={false} textCenter={true} style={{position: 'unset', padding: '0px 0px 4px', fontSize: '0.9em'}} />
+    </ListItem>
+  );
+}
+UploadedFile.propTypes = {
+  upfile: PropTypes.object,
+  deleteFile: PropTypes.func,
+};
+
+
+export default function Uploader({fmUtilsObj, onClose}) {
+  const classes = useStyles();
+  const [files, dispatchFileAction] = useReducer(filesReducer, []);
+  const onDrop = useCallback(acceptedFiles => {
+    dispatchFileAction({
+      type: 'add',
+      files: acceptedFiles,
+    });
+  }, []);
+  const {getRootProps, getInputProps} = useDropzone({onDrop});
+
+  useEffect(()=>{
+    files.forEach(async (upfile)=>{
+      if(!upfile.started && !upfile.failed) {
+        try {
+          dispatchFileAction({
+            type: 'started',
+            id: upfile.id,
+          });
+          await fmUtilsObj.uploadItem(upfile.file, (progressEvent)=>{
+            const {loaded, total} = progressEvent;
+            const percent = Math.floor((loaded * 100) / total);
+            dispatchFileAction({
+              type: 'progress',
+              id: upfile.id,
+              value: percent,
+            });
+          });
+          dispatchFileAction({
+            type: 'done',
+            id: upfile.id,
+          });
+        } catch {
+          dispatchFileAction({
+            type: 'failed',
+            id: upfile.id,
+          });
+        }
+      }
+    });
+  }, [files.length]);
+
+  return (
+    <Box className={classes.root}>
+      <Box display="flex" justifyContent="flex-end">
+        <PgIconButton title={gettext('Close')} icon={<CloseIcon  />} size="xs" noBorder onClick={onClose} />
+      </Box>
+      <Box display="flex" flexGrow={1} overflow="hidden">
+        <Box className={classes.uploadArea} {...getRootProps()}>
+          <input {...getInputProps()} />
+          <Box>{gettext('Drop files here, or click to select files.')}</Box>
+          <Box>{gettext('The file size limit (per file) is 50 MB.')}</Box>
+        </Box>
+        {files.length > 0 &&
+          <Box className={classes.uploadFilesRoot}>
+            <List>
+              {files.map((upfile)=>(
+                <UploadedFile key={upfile.id} upfile={upfile} deleteFile={async ()=>{
+                  dispatchFileAction({
+                    type: 'deleting',
+                    id: upfile.id,
+                  });
+                  try {
+                    await fmUtilsObj.deleteItem({Path: fmUtilsObj.currPath}, upfile.file.name);
+                    dispatchFileAction({
+                      type: 'delete',
+                      id: upfile.id,
+                    });
+                  } catch(error) {
+                    console.error(error);
+                  }
+                }}/>
+              ))}
+            </List>
+          </Box>}
+      </Box>
+    </Box>
+  );
+}
+Uploader.propTypes = {
+  fmUtilsObj: PropTypes.object,
+  onClose: PropTypes.func,
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/create_dialogue.js b/web/pgadmin/misc/file_manager/static/js/create_dialogue.js
deleted file mode 100644
index cdd9917e1..000000000
--- a/web/pgadmin/misc/file_manager/static/js/create_dialogue.js
+++ /dev/null
@@ -1,195 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import gettext from 'sources/gettext';
-import url_for from 'sources/url_for';
-import $ from 'jquery';
-import Alertify from 'pgadmin.alertifyjs';
-import pgAdmin from 'sources/pgadmin';
-import {removeTransId, set_last_traversed_dir} from './helpers';
-import Notify from '../../../../static/js/helpers/Notifier';
-
-// Declare the Create mode dialog
-module.exports =  Alertify.dialog('createModeDlg', function() {
-  // Dialog property
-  return {
-    setup: function() {
-      return {
-        buttons: [{
-          text: gettext('Cancel'),
-          key: 27,
-          className: 'btn btn-secondary fa fa-times file_manager_create_cancel pg-alertify-button',
-        },{
-          text: gettext('Create'),
-          key: 13,
-          className: 'btn btn-primary fa fa-file file_manager_create file_manager_ok pg-alertify-button disabled',
-        }],
-        options: {
-          closableByDimmer: false,
-          maximizable: false,
-          closable: false,
-          movable: true,
-          padding: !1,
-          overflow: !1,
-          model: 0,
-          resizable: true,
-          pinnable: false,
-          modal: false,
-          autoReset: false,
-        },
-      };
-    },
-    replace_file: function() {
-      var $yesBtn = $('.replace_file .btn_yes'),
-        $noBtn = $('.replace_file .btn_no');
-
-      $('.storage_dialog #uploader .input-path').attr('disabled', true);
-      $('.file_manager_ok').addClass('disabled');
-      $('.replace_file, .fm_dimmer').show();
-
-      $yesBtn.on('click',() => {
-        $('.replace_file, .fm_dimmer').hide();
-        $yesBtn.off();
-        $noBtn.off();
-        var newFile = $('.storage_dialog #uploader .input-path').val();
-
-        pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile);
-        $('.file_manager_create_cancel').trigger('click');
-        $('.storage_dialog #uploader .input-path').attr('disabled', false);
-        $('.file_manager_ok').removeClass('disabled');
-      });
-
-      $noBtn.on('click',() => {
-        $('.replace_file, .fm_dimmer').hide();
-        $yesBtn.off();
-        $noBtn.off();
-        $('.storage_dialog #uploader .input-path').attr('disabled', false);
-        $('.file_manager_ok').removeClass('disabled');
-      });
-    },
-    is_file_exist: function() {
-      var full_path = $('.storage_dialog #uploader .input-path').val(),
-        path = full_path.substr(0, full_path.lastIndexOf('/') + 1),
-        selected_item = full_path.substr(full_path.lastIndexOf('/') + 1),
-        is_exist = false;
-
-      var file_data = {
-        'path': path,
-        'name': selected_item,
-        'mode': 'is_file_exist',
-      };
-
-      $.ajax({
-        type: 'POST',
-        data: JSON.stringify(file_data),
-        url: url_for('file_manager.filemanager', {
-          'trans_id': this.trans_id,
-        }),
-        dataType: 'json',
-        contentType: 'application/x-download; charset=utf-8',
-        async: false,
-      })
-        .done(function(resp) {
-          var data = resp.data.result;
-          if (data['Code'] === 1) {
-            is_exist = true;
-          } else {
-            is_exist = false;
-          }
-        });
-      return is_exist;
-    },
-    check_permission: function(path) {
-      var permission = false,
-        post_data = {
-          'path': path,
-          'mode': 'permission',
-        };
-
-      $.ajax({
-        type: 'POST',
-        data: JSON.stringify(post_data),
-        url: url_for('file_manager.filemanager', {
-          'trans_id': this.trans_id,
-        }),
-        dataType: 'json',
-        contentType: 'application/json; charset=utf-8',
-        async: false,
-      })
-        .done(function(resp) {
-          var data = resp.data.result;
-          if (data.Code === 1) {
-            permission = true;
-          } else {
-            $('.file_manager_ok').addClass('disabled');
-            Notify.error(data.Error);
-          }
-        })
-        .fail(function() {
-          $('.file_manager_ok').addClass('disabled');
-          Notify.error(gettext('Error occurred while checking access permission.'));
-        });
-      return permission;
-    },
-    callback: function(closeEvent) {
-      closeEvent.cancel = false;
-      if (closeEvent.button.text == gettext('Create')) {
-        var act_variable = document.activeElement.id;
-        if(act_variable != 'refresh_list') {
-          var newFile = $('.storage_dialog #uploader .input-path').val(),
-            file_data = {
-              'path': $('.currentpath').val(),
-            },
-            innerbody,
-            ext = $('.allowed_file_types select').val();
-
-          /*
-             Add the file extension if necessary, and if the file type selector
-             isn't set to "All Files". If there's no . at all in the path, or
-             there is a . already but it's not following the last /, AND the
-             extension isn't *, then we add the extension.
-           */
-          if ((!newFile.includes('.') ||
-              newFile.split('.').pop() != ext) &&
-              ext != '*') {
-            newFile = newFile + '.' + ext;
-            $('.storage_dialog #uploader .input-path').val(newFile);
-          }
-
-          if (!this.check_permission(newFile)) {
-            closeEvent.cancel = true;
-            return;
-          }
-
-          if (!_.isUndefined(newFile) && newFile !== '' && this.is_file_exist()) {
-            this.replace_file();
-            this.$container.find('.replace_file').find('.btn_yes').trigger('focus');
-            closeEvent.cancel = true;
-          } else {
-            pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile);
-            innerbody = $(this.elements.body).find('.storage_content');
-            $(innerbody).find('*').off();
-            innerbody.remove();
-            removeTransId(this.trans_id);
-          }
-
-          set_last_traversed_dir(file_data, this.trans_id);
-        } else {
-          closeEvent.cancel = true;
-        }
-      } else if (closeEvent.button.text == gettext('Cancel')) {
-        innerbody = $(this.elements.body).find('.storage_content');
-        $(innerbody).find('*').off();
-        innerbody.remove();
-        removeTransId(this.trans_id);
-        pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:create_file');
-      }
-    },
-  };
-}, false, 'fileSelectionDlg');
diff --git a/web/pgadmin/misc/file_manager/static/js/file_manager.js b/web/pgadmin/misc/file_manager/static/js/file_manager.js
deleted file mode 100644
index 0b4a33cc1..000000000
--- a/web/pgadmin/misc/file_manager/static/js/file_manager.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import './select_dialogue';
-import './create_dialogue';
-import './storage_dialogue';
-
-define('misc.file_manager', [
-  'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
-  'sources/pgadmin', 'pgadmin.alertifyjs',
-], function(gettext, url_for, $, _, pgAdmin, Alertify) {
-  pgAdmin = pgAdmin || window.pgAdmin || {};
-
-  /*
-   *
-   *
-   * Hmm... this module is already been initialized, we can refer to the old
-   * object from here.
-   */
-  if (pgAdmin.FileManager) {
-    return pgAdmin.FileManager;
-  }
-
-  pgAdmin.FileManager = {
-    init: function() {
-      if (this.initialized) {
-        return;
-      }
-
-      this.initialized = true;
-
-    },
-    // Call dialogs subject to dialog_type param
-    show_dialog: function(params) {
-      let dialogWidth = pgAdmin.Browser.stdW.calc(pgAdmin.Browser.stdW.md);
-      let dialogHeight = pgAdmin.Browser.stdH.calc(pgAdmin.Browser.stdH.lg);
-      if (params.dialog_type == 'create_file') {
-        Alertify.createModeDlg(params).resizeTo(dialogWidth, dialogHeight);
-      } else if(params.dialog_type == 'storage_dialog') {
-        Alertify.fileStorageDlg(params).resizeTo(dialogWidth, dialogHeight);
-      }
-      else {
-        Alertify.fileSelectionDlg(params).resizeTo(dialogWidth, dialogHeight);
-      }
-    },
-  };
-
-  return pgAdmin.FileManager;
-});
diff --git a/web/pgadmin/misc/file_manager/static/js/helpers.js b/web/pgadmin/misc/file_manager/static/js/helpers.js
deleted file mode 100644
index af24bfa71..000000000
--- a/web/pgadmin/misc/file_manager/static/js/helpers.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import url_for from 'sources/url_for';
-import $ from 'jquery';
-
-// Send a request to get transaction id
-export function getTransId(configs) {
-  return $.ajax({
-    data: configs,
-    type: 'POST',
-    async: false,
-    url: url_for('file_manager.get_trans_id'),
-    dataType: 'json',
-    contentType: 'application/json; charset=utf-8',
-  });
-}
-
-// Function to remove trans id from session
-export function removeTransId(trans_id) {
-  return $.ajax({
-    type: 'GET',
-    async: false,
-    url: url_for('file_manager.delete_trans_id', {
-      'trans_id': trans_id,
-    }),
-    dataType: 'json',
-    contentType: 'application/json; charset=utf-8',
-  });
-}
-
-export function set_last_traversed_dir(path, trans_id) {
-  return $.ajax({
-    url: url_for('file_manager.save_last_dir', {
-      'trans_id': trans_id,
-    }),
-    type: 'POST',
-    data: JSON.stringify(path),
-    contentType: 'application/json',
-  });
-}
diff --git a/web/pgadmin/misc/file_manager/static/js/index.js b/web/pgadmin/misc/file_manager/static/js/index.js
new file mode 100644
index 000000000..63ddc7629
--- /dev/null
+++ b/web/pgadmin/misc/file_manager/static/js/index.js
@@ -0,0 +1,25 @@
+/////////////////////////////////////////////////////////////
+//
+// 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 FileManagerModule from './FileManagerModule';
+
+/* eslint-disable */
+/* This is used to change publicPath of webpack at runtime for loading chunks */
+/* Do not add let, var, const to this variable */
+__webpack_public_path__ = window.resourceBasePath;
+/* eslint-enable */
+
+if(!pgAdmin.Tools) {
+  pgAdmin.Tools = {};
+}
+pgAdmin.Tools.FileManager = FileManagerModule.getInstance(pgAdmin);
+
+module.exports = {
+  FileManager: pgAdmin.Tools.FileManager,
+};
diff --git a/web/pgadmin/misc/file_manager/static/js/select_dialogue.js b/web/pgadmin/misc/file_manager/static/js/select_dialogue.js
deleted file mode 100644
index 74903e1cd..000000000
--- a/web/pgadmin/misc/file_manager/static/js/select_dialogue.js
+++ /dev/null
@@ -1,148 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import gettext from 'sources/gettext';
-import url_for from 'sources/url_for';
-import $ from 'jquery';
-import Alertify from 'pgadmin.alertifyjs';
-import pgAdmin from 'sources/pgadmin';
-import {getTransId, removeTransId, set_last_traversed_dir} from './helpers';
-
-// Declare the Selection dialog
-module.exports =  Alertify.dialog('fileSelectionDlg', function() {
-  // Dialog property
-  return {
-    main: function(params) {
-      // Set title and button name
-      var self = this;
-      if (_.isUndefined(params['dialog_title'])) {
-        params['dialog_title'] = gettext('Select file');
-      }
-      self.dialog_type = params['dialog_type'];
-
-      this.set('title', params['dialog_title']);
-      this.params = JSON.stringify(params);
-
-      this.show();
-
-    },
-    settings: {
-      label: undefined,
-    },
-    settingUpdated: function(key, oldValue, newValue) {
-      switch (key) {
-      case 'message':
-        this.setMessage(newValue);
-        break;
-      case 'label':
-        if (this.__internal.buttons[0].element) {
-          this.__internal.buttons[0].element.innerHTML = newValue;
-        }
-        break;
-      default:
-        break;
-      }
-    },
-    prepare: function() {
-      var self = this;
-
-      self.$container.find('.storage_content').remove();
-      self.$container.append('<div class=\'storage_content\'></div>');
-
-      var content = self.$container.find('.storage_content');
-      content.empty();
-
-      // Add our class to alertify
-      $(this.elements.body.childNodes[0]).addClass('alertify_tools_dialog_properties');
-      $(this.elements.root).css('z-index', 3002);
-      $.get(url_for('file_manager.index'), function(data) {
-        content.append(data);
-      });
-
-      var transId = getTransId(self.params);
-      var t_res;
-      if (transId.readyState == 4) {
-        t_res = JSON.parse(transId.responseText);
-      }
-      self.trans_id = _.isUndefined(t_res) ? 0 : t_res.data.fileTransId;
-
-      setTimeout(function() {
-        $(self.$container.find('.file_manager')).on('enter-key', function() {
-          $($(self.elements.footer).find('.file_manager_ok')).trigger('click');
-        });
-      }, 200);
-      if(self.__internal.buttons[1])
-        self.__internal.buttons[1].element.disabled = true;
-    },
-    setup: function() {
-      return {
-        buttons: [{
-          text: gettext('Cancel'),
-          key: 27,
-          className: 'btn btn-secondary fa fa-times pg-alertify-button',
-        },{
-          text: gettext('Select'),
-          key: 13,
-          className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled',
-        }],
-        options: {
-          closableByDimmer: false,
-          maximizable: false,
-          closable: false,
-          movable: true,
-          padding: !1,
-          overflow: !1,
-          model: 0,
-          resizable: true,
-          pinnable: false,
-          modal: false,
-          autoReset: false,
-        },
-      };
-    },
-    callback: function(closeEvent) {
-      var innerbody;
-      closeEvent.cancel = false;
-      if (closeEvent.button.text == gettext('Select')) {
-        var act_variable = document.activeElement.id;
-        if(act_variable !='refresh_list') {
-          var newFile = $('.storage_dialog #uploader .input-path').val(),
-            file_data = {
-              'path': $('.currentpath').val(),
-            };
-
-          pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:' + this.dialog_type, newFile);
-          innerbody = $(this.elements.body).find('.storage_content');
-          $(innerbody).find('*').off();
-          innerbody.remove();
-          removeTransId(this.trans_id);
-          // Ajax call to store the last directory visited once user press select button
-
-          set_last_traversed_dir(file_data, this.trans_id);
-        } else {
-          closeEvent.cancel = true;
-        }
-      } else if (closeEvent.button.text == gettext('Cancel')) {
-        innerbody = $(this.elements.body).find('.storage_content');
-        $(innerbody).find('*').off();
-        innerbody.remove();
-        removeTransId(this.trans_id);
-        pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:' + this.dialog_type);
-      }
-    },
-    build: function() {
-      this.$container = $('<div class="storage_dialog file_selection_dlg"></div>');
-      this.elements.content.appendChild(this.$container.get(0));
-      Alertify.pgDialogBuild.apply(this);
-    },
-    hooks: {
-      onshow: function() {/* This is intentional (SonarQube) */},
-    },
-  };
-});
diff --git a/web/pgadmin/misc/file_manager/static/js/storage_dialogue.js b/web/pgadmin/misc/file_manager/static/js/storage_dialogue.js
deleted file mode 100644
index 38f01f599..000000000
--- a/web/pgadmin/misc/file_manager/static/js/storage_dialogue.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import gettext from 'sources/gettext';
-import Alertify from 'pgadmin.alertifyjs';
-
-// Declare the Storage dialog
-module.exports =  Alertify.dialog('fileStorageDlg', function() {
-  // Dialog property
-  return {
-    settingUpdated: function(key, oldValue, newValue) {
-      if(key == 'message') {
-        this.setMessage(newValue);
-      }
-    },
-    setup: function() {
-      return {
-        buttons: [{
-          text: gettext('Cancel'),
-          key: 27,
-          className: 'btn btn-secondary fa fa-times pg-alertify-button',
-        }],
-        options: {
-          closableByDimmer: false,
-          maximizable: false,
-          closable: false,
-          movable: true,
-          padding: !1,
-          overflow: !1,
-          model: 0,
-          resizable: true,
-          pinnable: false,
-          modal: false,
-          autoReset: false,
-        },
-      };
-    },
-  };
-}, true, 'fileSelectionDlg');
diff --git a/web/pgadmin/misc/file_manager/static/js/utility.js b/web/pgadmin/misc/file_manager/static/js/utility.js
deleted file mode 100644
index 47bd36f8c..000000000
--- a/web/pgadmin/misc/file_manager/static/js/utility.js
+++ /dev/null
@@ -1,2008 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-/**
- * Filemanager JS core
- *
- * filemanager.js
- *
- *  @license  MIT License
- *  @author Jason Huck - Core Five Labs
- *  @author Simon Georget <simon (at) linea21 (dot) com>
- *  @copyright  Authors
- */
-import Notify from '../../../../static/js/helpers/Notifier';
-
-define([
-  'jquery', 'underscore',
-  'sources/gettext', 'sources/url_for', 'dropzone', 'sources/pgadmin',
-  'sources/csrf', 'tablesorter', 'tablesorter-metric',
-], function($, _, gettext, url_for, Dropzone, pgAdmin, csrf) {
-
-  pgAdmin.Browser = pgAdmin.Browser || {};
-
-  /*---------------------------------------------------------
-    Define functions used for various operations
-  ---------------------------------------------------------*/
-  // Set the CSRF Token
-  csrf.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
-
-  // Return file extension
-  var getFileExtension = function(name) {
-    var found = name.lastIndexOf('.') + 1;
-    return (found > 0 ? name.substr(found) : '');
-  };
-
-  /* Common function to load:
-   * en.json language file
-   * file_manager_config.js config file
-   * return transaction id
-   */
-  var loadData = function(url) {
-    return $.ajax({
-      async: false,
-      cache: false,
-      url: url,
-      dataType: 'json',
-      contentType: 'application/json; charset=utf-8',
-    });
-  };
-
-  var getFileFormat = function(data) {
-  // Get last selected file format
-    return $.ajax({
-      async: false,
-      cache: false,
-      url: url_for('settings.get_file_format_setting'),
-      data : $.extend({}, data),
-      dataType: 'json',
-      contentType: 'application/json; charset=utf-8',
-    });
-  };
-
-  // Set enable/disable state of list and grid view
-  var setViewButtonsFor = function(viewMode) {
-    if (viewMode == 'grid') {
-      $('.grid').addClass('ON');
-      $('.list').removeClass('ON');
-    } else {
-      $('.list').addClass('ON');
-      $('.grid').removeClass('ON');
-    }
-  };
-
-  var save_file_dialog_view = function(view, trans_id) {
-    return $.ajax({
-      url: url_for('file_manager.save_file_dialog_view', {
-        'trans_id': trans_id,
-      }),
-      type: 'POST',
-      async: true,
-      data: JSON.stringify({
-        'view': view,
-      }),
-      contentType: 'application/json',
-    });
-  };
-
-  var save_show_hidden_file_option = function(option, trans_id) {
-    return $.ajax({
-      url: url_for('file_manager.save_show_hidden_file_option', {
-        'trans_id': trans_id,
-      }),
-      type: 'PUT',
-      async: true,
-      data: JSON.stringify({
-        'show_hidden': option,
-      }),
-      contentType: 'application/json',
-    });
-  };
-
-  // nameFormat (), separate filename from extension
-  var nameFormat = function(input) {
-    var filename = '';
-    if (input.lastIndexOf('.') != -1) {
-      filename = input.substr(0, input.lastIndexOf('.'));
-      filename += '.' + input.split('.').pop();
-    } else {
-      filename = input;
-    }
-    return filename;
-  };
-
-  /*
-   * Test if Data structure has the 'cap' capability
-   * 'cap' is one of 'select', 'rename', 'delete', 'download'
-   */
-  var has_capability = function(data, cap) {
-    if (typeof(data.Capabilities) == 'undefined') {
-      return true;
-    } else {
-      return ($.inArray(cap, data.Capabilities) > -1);
-    }
-  };
-
-  // return filename extension
-  var getExtension = function(filename) {
-    if (filename.split('.').length == 1) {
-      return '';
-    }
-    return filename.split('.').pop();
-  };
-
-  /*
-   * Binds specific actions to the toolbar based on capability.
-   * and show/hide buttons
-   */
-  var bindToolbar = function(data) {
-
-    // hide/show rename, upload and create button
-    if (_.has(data, 'Capabilities')) {
-      _.each(data.Capabilities, function(cap) {
-        var target_btn = 'button.' + cap,
-          $target_el = $('.file_manager').find(target_btn);
-        if (!has_capability(data, cap) || pgAdmin.FileUtils.hideButtons()) {
-          $target_el.hide();
-        } else {
-          $target_el.show();
-        }
-      });
-    }
-
-    if (!has_capability(data, 'delete') || pgAdmin.FileUtils.hideButtons()) {
-      $('.file_manager').find('button.delete').hide();
-    } else {
-      $('.file_manager').find('button.delete').on('click',() => {
-        // hide dimmer
-        $('.fileinfo .delete_item, .fm_dimmer').show();
-      });
-
-      // take action based on pressed button yes or no
-      $('.fileinfo .delete_item button.btn_yes').off().on('click', function() {
-        var path;
-        if ($('.fileinfo').data('view') == 'grid') {
-          path = decodeURI($('.fileinfo').find('#contents li.selected .clip span').attr('data-alt'));
-          if (path.lastIndexOf('/') == path.length - 1) {
-            data.Path = path;
-            deleteItem(data);
-          } else {
-            deleteItem(data);
-          }
-        } else {
-          path = $('.fileinfo').find('table#contents tbody tr.selected td:first-child').attr('title');
-          if (path.lastIndexOf('/') == path.length - 1) {
-            data.Path = path;
-            deleteItem(data);
-          } else {
-            deleteItem(data);
-          }
-        }
-        // hide dimmer
-        $('.fileinfo .fm_dimmer').hide();
-      });
-
-    }
-
-    // Download file on download button click
-    if (!has_capability(data, 'download') || pgAdmin.FileUtils.hideButtons()) {
-      $('.file_manager').find('button.download').hide();
-    } else {
-      $('.file_manager').find('button.download').off().on('click', function() {
-        var path,
-          params = {};
-
-        params[pgAdmin.csrf_token_header] = pgAdmin.csrf_token;
-
-        if ($('.fileinfo').data('view') == 'grid') {
-          path = $('.fileinfo li.selected').find('.clip span').attr('data-alt');
-        } else {
-          path = $('.fileinfo').find('table#contents tbody tr.selected td:first-child').attr('title');
-        }
-        download_file(path);
-      });
-    }
-  };
-
-  // enable/disable button when files/folder are loaded
-  var enable_disable_btn = function() {
-    if ($('.fileinfo').data('view') == 'grid') {
-      var $grid_file = $('.file_manager').find('#contents li.selected');
-      $grid_file.removeClass('selected');
-      $('.file_manager').find('button.delete').prop('disabled', true);
-      $('.file_manager').find('button.download').prop('disabled', true);
-      $('.file_manager').find('button.rename').prop('disabled', true);
-      if ($grid_file.length > 0) {
-        $('.file_manager_ok').addClass('disabled');
-        $('.file_manager_ok').attr('disabled', true);
-      }
-    } else {
-      var $list_file = $('.fileinfo').find('table#contents tbody tr.selected');
-      $list_file.removeClass('selected');
-      $('.file_manager').find('button.delete').prop('disabled', true);
-      $('.file_manager').find('button.download').prop('disabled', true);
-      $('.file_manager').find('button.rename').prop('disabled', true);
-      if ($list_file.length > 0) {
-        $('.file_manager_ok').addClass('disabled');
-        $('.file_manager_ok').attr('disabled', true);
-      }
-    }
-
-    $('.delete_item').hide();
-    // clear address bar
-    $('.file_manager #uploader .input-path').show();
-    $('.file_manager #uploader .show_selected_file').remove();
-  };
-
-  /*
-   * Rename the current item and returns the new name.
-   * by double clicking or by clicking the "Rename" button in
-   * table(list) views.
-   */
-  var renameItem = function(data) {
-    var finalName = '',
-      lg = pgAdmin.FileUtils.lg,
-      getNewName = function(rname) {
-        if (rname !== '') {
-          var givenName = nameFormat(rname),
-            suffix = getExtension(data.Filename);
-          if (suffix.length > 0) {
-            givenName = givenName + '.' + suffix;
-          }
-
-          var oldPath = data.Path,
-            post_data = {
-              'mode': 'rename',
-              'old': data.Path,
-              'new': givenName,
-            };
-
-          $.ajax({
-            type: 'POST',
-            data: JSON.stringify(post_data),
-            url: pgAdmin.FileUtils.fileConnector,
-            dataType: 'json',
-            contentType: 'application/json; charset=utf-8',
-            async: false,
-          })
-            .done(function(resp) {
-              var result = resp.data.result;
-              if (result.Code === 1) {
-                var newPath = result['New Path'],
-                  newName = result['New Name'],
-                  title = $('#preview h1').attr('title');
-
-                if (typeof title != 'undefined' && title == oldPath) {
-                  $('#preview h1').text(newName);
-                }
-
-                if ($('.fileinfo').data('view') == 'grid') {
-                  $('.fileinfo span[data-alt="' + oldPath + '"]').parent().next('div span').text(newName);
-                  $('.fileinfo span[data-alt="' + oldPath + '"]').attr('data-alt', newPath);
-                } else {
-                  $('.fileinfo td[title="' + oldPath + '"]').text(newName);
-                  $('.fileinfo td[title="' + oldPath + '"]').attr('title', newPath);
-                }
-                $('#preview h1').html(newName);
-
-                // actualized data for binding
-                data.Path = newPath;
-                data.Filename = newName;
-
-                // UnBind toolbar functions.
-                $('.fileinfo').find('button.rename, button.delete, button.download').off();
-
-                Notify.success(lg.successful_rename);
-              } else {
-                Notify.error(result.Error);
-              }
-
-              finalName = result['New Name'];
-            });
-        }
-      };
-
-    getNewName(data.NewFilename);
-    return finalName;
-  };
-
-  /*
-   * delete the folder or files by clicking the "Delete" button
-   * in table(list) view
-   */
-  var deleteItem = function(data) {
-    var isDeleted = false,
-      lg = pgAdmin.FileUtils.lg;
-
-    var doDelete = function(sel_data) {
-      var post_data = {
-        'mode': 'delete',
-        'path': sel_data.Path,
-      };
-
-      $.ajax({
-        type: 'POST',
-        data: JSON.stringify(post_data),
-        url: pgAdmin.FileUtils.fileConnector,
-        dataType: 'json',
-        contentType: 'application/json; charset=utf-8',
-        async: false,
-      })
-        .done(function(resp) {
-          var result = resp.data.result;
-          if (result.Code === 1) {
-            isDeleted = true;
-            if (isDeleted) {
-              Notify.success(lg.successful_delete);
-              var rootpath = result.Path.substring(0, result.Path.length - 1); // removing the last slash
-              rootpath = rootpath.substr(0, rootpath.lastIndexOf('/') + 1);
-              getFolderInfo(rootpath);
-            }
-          } else {
-            isDeleted = false;
-            Notify.error(result.Error);
-          }
-        });
-      return isDeleted;
-    };
-
-    doDelete(data);
-    return isDeleted;
-  };
-
-  /*---------------------------------------------------------
-    Functions to Retrieve File and Folder Details
-  ---------------------------------------------------------*/
-  /*
-   * Retrieves information about the specified file as a JSON
-   * object and uses that data to populate a template for
-   * list views. Binds the toolbar for that file/folder to
-   * enable specific actions. Called whenever an item is
-   * clicked in list views.
-   */
-  var getFileInfo = function(file) {
-    // Update location for status, upload, & new folder functions.
-    pgAdmin.FileUtils.setUploader(file);
-    var capabilities = pgAdmin.FileUtils.data.capabilities,
-      is_file_valid = false,
-      post_data = {
-        'path': file,
-        'mode': 'getinfo',
-      };
-
-    // Retrieve the data & populate the template.
-    $.ajax({
-      type: 'POST',
-      data: JSON.stringify(post_data),
-      url: pgAdmin.FileUtils.fileConnector,
-      dataType: 'json',
-      contentType: 'application/json; charset=utf-8',
-      async: false,
-    })
-      .done(function(resp) {
-        var data = resp.data.result;
-        if (data.Code === 1) {
-          $('.file_manager_ok').removeClass('disabled');
-          $('.file_manager_ok').attr('disabled', false);
-          data.Capabilities = capabilities;
-          bindToolbar(data);
-          if (data.FileType == 'Directory') {
-          // Enable/Disable level up button
-            enab_dis_level_up();
-            $('.file_manager_ok').addClass('disabled');
-            $('.file_manager_ok').attr('disabled', true);
-            $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
-            $('.file_manager button.download').attr('disabled', 'disabled');
-
-            if (file.charAt(file.length - 1) != '/' && file.charAt(file.length - 1) != '\\') {
-              file += '/';
-            }
-            getFolderInfo(file);
-          } else {
-            is_file_valid = true;
-          }
-        } else {
-          $('.file_manager_ok').addClass('disabled');
-          $('.file_manager_ok').attr('disabled', true);
-          Notify.error(data.Error);
-        }
-
-        // Disable select button if user select file.
-        if (pgAdmin.FileUtils.data.Capabilities.includes('select_folder')) {
-          $('.file_manager_ok').addClass('disabled');
-          $('.file_manager_ok').attr('disabled', true);
-        }
-
-      });
-    return is_file_valid;
-  };
-
-  var checkPermission = function(path) {
-    var permission = false,
-      post_data = {
-        'path': path,
-        'mode': 'permission',
-      };
-
-    $.ajax({
-      type: 'POST',
-      data: JSON.stringify(post_data),
-      url: pgAdmin.FileUtils.fileConnector,
-      dataType: 'json',
-      contentType: 'application/json; charset=utf-8',
-      async: false,
-    })
-      .done(function(resp) {
-        var data = resp.data.result;
-        if (data.Code === 1) {
-          permission = true;
-        } else {
-          $('.file_manager_ok').addClass('disabled');
-          $('.file_manager_ok').attr('disabled', true);
-          Notify.error(data.Error);
-        }
-      })
-      .fail(function() {
-        $('.file_manager_ok').addClass('disabled');
-        $('.file_manager_ok').attr('disabled', true);
-        Notify.error(
-          gettext('Error occurred while checking access permission.')
-        );
-      });
-    return permission;
-  };
-
-  var getNoDataView = function(data) {
-    var lg = pgAdmin.FileUtils.lg;
-    var cap_no_folders = ['upload', 'create'];
-    data.Capabilities = cap_no_folders;
-    bindToolbar(data);
-
-    return `<div class="no_folder_found">${lg.could_not_retrieve_folder}</div>`;
-  };
-
-  var getCapClasses = function(item_data, capabilities) {
-    let capClasses = '';
-    capClasses = Object.keys(capabilities).map(function(cap) {
-      if (has_capability(item_data, capabilities[cap])) {
-        return 'cap_' + capabilities[cap];
-      }
-    }).join(' ');
-    return capClasses;
-  };
-
-  var getGridView = function(data, capabilities) {
-    let ret_ele = '<ul id="contents" class="grid">',
-      no_data = _.isEmpty(data);
-
-    if(!no_data) {
-      ret_ele += Object.keys(data).sort(function keyOrder(x, y) {
-        return pgAdmin.natural_sort(x.toLowerCase(), y.toLowerCase());
-      }).map(function(key) {
-        let item_data = data[key],
-          props = item_data.Properties,
-          filename = _.escape(item_data.Filename),
-          icon_type = '',
-          cap_classes = '';
-
-        cap_classes = getCapClasses(item_data, capabilities);
-
-        item_data.Capabilities = capabilities;
-        bindToolbar(item_data);
-
-        if (item_data.file_type == 'dir') {
-          icon_type = 'fa fa-folder-open fm_folder_grid';
-          props.Size = '';
-        } else if (item_data.file_type == 'drive') {
-          icon_type = 'fa fa-hdd fm_drive';
-          props.Size = '';
-        } else {
-          icon_type = 'fa fa-file-alt fm_file_grid';
-        }
-
-        /* For the html ele */
-        let item_ele =
-          `<li class="${cap_classes}" tabindex="0">
-            <div class="clip">
-            <span data-alt="${_.escape(item_data.Path)}" class="${icon_type}"></span>`;
-
-        if (item_data.Protected == 1) {
-          item_ele += '<span class="fa fa-lock fm_lock_icon" data-protected="protected" role="img"></span>';
-        }
-
-        item_ele += '</div>';
-
-        if (!has_capability(item_data, 'rename')) {
-          item_ele += `<span>${filename}</span>`;
-        } else {
-          item_ele +=
-            `<div>
-              <input type="text" class="fm_file_rename" />
-              <span class="less_text" title="${filename}">${filename}</span>
-            </div>`;
-        }
-        if (props.Width && props.Width != '') {
-          item_ele += `<span class="meta dimensions">${props.Width}x${props.Height}</span>`;
-        }
-        if (props.Size && props.Size != '') {
-          item_ele += `<span class="meta size">${props.Size}</span>`;
-        }
-        if (props['Date Created'] && props['Date Created'] != '') {
-          item_ele += `<span class="meta created">${props['Date Created']}</span>`;
-        }
-        if (props['Date Modified'] && props['Date Modified'] != '') {
-          item_ele += `<span class="meta modified">${props['Date Modified']}</span>`;
-        }
-        item_ele += '</li>';
-
-        return item_ele;
-      }).join('\n');
-    }
-
-    ret_ele += '</ul>';
-
-    if(no_data) {
-      ret_ele += getNoDataView(data);
-    }
-    return ret_ele;
-  };
-
-  var getListView = function(data, capabilities) {
-    let lg = pgAdmin.FileUtils.lg;
-    let no_data = _.isEmpty(data);
-
-    /* file_listing_table class makes height 100%, because of which No folder message is not displayed
-     * file_listing_table_no_data will be removed when new folder is created
-     */
-    let ret_ele =
-      `<table id="contents" class="table table-bordered table-noouter-border table-bottom-border table-right-border table-hover tablesorter file_listing_table ${no_data?'file_listing_table_no_data':''}">
-        <thead>
-          <tr>
-            <th tabindex="0">
-              <span>${lg.name}</span>
-            </th>
-            <th class="sorter-metric" data-metric-name-full="byte|Byte|BYTE" data-metric-name-abbr="b|B">
-              <span>${lg.size}</span>
-            </th>
-            <th class="sorter-shortDate">
-              <span>${lg.modified}</span>
-            </th>
-          </tr>
-        </thead>
-        <tbody>`;
-
-    if(!no_data) {
-      ret_ele += Object.keys(data).sort(function keyOrder(x, y) {
-        return pgAdmin.natural_sort(x.toLowerCase(), y.toLowerCase());
-      }).map(function(key) {
-        let item_data = data[key],
-          props = item_data.Properties,
-          icon_type = '',
-          class_type = '',
-          cap_classes = '';
-
-        cap_classes = getCapClasses(item_data, capabilities);
-
-        item_data.Capabilities = capabilities;
-        bindToolbar(item_data);
-
-        if (item_data.file_type == 'dir') {
-          class_type = 'tbl_folder';
-          icon_type = 'fa fa-folder-open fm_folder_list';
-          props.Size = '';
-        } else if (item_data.file_type == 'drive') {
-          class_type = 'tbl_drive';
-          icon_type = 'fa fa-hdd';
-          props.Size = '';
-        } else {
-          class_type = 'tbl_file';
-          icon_type = 'fa fa-file-alt';
-        }
-
-        /* For the html ele */
-        let item_ele =
-          `<tr class="${cap_classes}" tabindex="0">
-            <td title="${_.escape(item_data.Path)}" class="${class_type}">`;
-
-        let data_protected = '';
-        if (item_data.Protected == 1) {
-          data_protected = '<i class="fa fa-lock tbl_lock_icon" data-protected="protected" role="img"></i>';
-        }
-        if (!has_capability(data[key], 'rename')) {
-          item_ele +=
-            `${data_protected};
-            <span title="${item_data.Filename}">${_.escape(item_data.Filename)}</span>`;
-        } else {
-          item_ele +=
-            `<div>
-              <input aria-label="file_rename" type="text" class="fm_file_rename"/>
-              <div class="fm_file_name">
-                <div class="d-flex">
-                  <span class="fm_file_list ${icon_type}"></span>
-                  ${data_protected}
-                  <span class="less_text ml-2" title="${item_data.Filename}">${_.escape(item_data.Filename)}</span>
-                </div>
-              <div>
-            </div>`;
-        }
-        item_ele += '</td>';
-        if (props.Size && props.Size != '') {
-          item_ele += `<td><span class="less_text" title="${props.Size}">${props.Size}</span></td>`;
-        } else {
-          item_ele += '<td></td>';
-        }
-
-        if (props['Date Modified'] && props['Date Modified'] != '') {
-          item_ele += `<td>${props['Date Modified']}</td>`;
-        } else {
-          item_ele += '<td></td>';
-        }
-
-        item_ele += '</tr>';
-
-        return item_ele;
-      }).join('\n');
-    }
-
-    ret_ele +=
-      `</tbody>
-      </table>`;
-
-    if(no_data) {
-      ret_ele += getNoDataView(data);
-    }
-    return ret_ele;
-  };
-
-  var enableSelect = function() {
-    // Enable select button if user select folder.
-    if (pgAdmin.FileUtils.data && pgAdmin.FileUtils.data.Capabilities.includes('select_folder')) {
-      $('.file_manager_ok').removeClass('disabled');
-      $('.file_manager_ok').attr('disabled', false);
-    }
-  };
-
-  var disableSelect = function() {
-    // Disable select button if user select file.
-    $('.file_manager_ok').addClass('disabled');
-    $('.file_manager_ok').attr('disabled', true);
-  };
-
-  /*
-   * Retrieves data for all items within the given folder and
-   * creates a list view.
-   */
-  var getFolderInfo = function(path, file_type, user_input) {
-    $('.storage_dialog #uploader .input-path').prop('disabled', true);
-    if (!file_type) {
-      file_type = '';
-    }
-    var capabilities = pgAdmin.FileUtils.data.Capabilities;
-    enableSelect();
-
-    // Update location for status, upload, & new folder functions.
-    pgAdmin.FileUtils.setUploader(path);
-    if(user_input) {
-      $('.storage_dialog #uploader .input-path').val(path+user_input);
-    }
-
-    // set default selected file type
-    if (file_type === '') {
-      file_type = $('.change_file_types select').val();
-    }
-
-    // navigate to directory or path when clicked on breadcrumbs
-    $('.file_manager a.breadcrumbs').off().on('click', function() {
-      var curr_path = $(this).attr('data-path'),
-        current_dir = $(this).html(),
-        move_to = curr_path.substring(
-          0, curr_path.lastIndexOf(current_dir)
-        ) + current_dir;
-
-      getFolderInfo(move_to);
-      enab_dis_level_up();
-    });
-
-    // hide select file if we are listing drives in windows.
-    if (pgAdmin.FileUtils.hideButtons()) {
-      $('.allowed_file_types .change_file_types').hide();
-    } else {
-      $('.allowed_file_types .change_file_types').show();
-    }
-
-    var loading_icon_url = url_for(
-      'static', {
-        'filename': 'img/loading.gif',
-      }
-    );
-
-    // Display an activity indicator.
-    $('.fileinfo').find('span.activity').html(
-      '<img src="' + loading_icon_url + '" alt="' + gettext('Loading...') + '/>'
-    );
-
-    var post_data = {
-      'path': path,
-      'mode': 'getfolder',
-      'file_type': file_type || '*',
-      'show_hidden': $('#show_hidden').prop('checked'),
-    };
-
-    $.ajax({
-      type: 'POST',
-      data: JSON.stringify(post_data),
-      url: pgAdmin.FileUtils.fileConnector,
-      dataType: 'json',
-      contentType: 'application/json; charset=utf-8',
-      async: false,
-    })
-      .done(function(resp) {
-        $('.storage_dialog #uploader .input-path').prop('disabled', false);
-        var result = '',
-          data = resp.data.result;
-        let isGridView = false;
-        // hide activity indicator
-        $('.fileinfo').find('span.activity').hide();
-        if (data.Code === 0) {
-          Notify.error(data.Error);
-          return;
-        }
-
-        var $this, orig_value, newvalue;
-
-        // generate HTML for files/folder and render into container
-        if ($('.fileinfo').data('view') == 'grid') {
-          result += getGridView(data, capabilities);
-          isGridView = true;
-        } else {
-          result += getListView(data, capabilities);
-        }
-
-        // Add the new markup to the DOM.
-        $('.fileinfo .file_listing').html(result);
-
-        let $listing_table = $('.fileinfo .file_listing .file_listing_table');
-
-        $listing_table.tablesorter({
-          widgets: [ 'resizable', 'stickyHeaders' ],
-          widgetOptions : {
-            stickyHeaders_attachTo:'.file_listing',
-            stickyHeaders_offset: 0,
-            resizable_widths: ['400px', '100px', '175px'],
-          },
-        });
-
-        /* In order to fit our UI, some things need to be explicitly set
-         * as tablesorter resizable is creating trouble.
-         */
-        $listing_table.on( 'resizableComplete', function() {
-          let wo = this.config.widgetOptions;
-          $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
-        });
-
-        /* Role of this function is to click or double click on element when user is doing keyboard navigation*/
-        var clickOnFileFolderManually = function(event) {
-          let self = this;
-          event.preventDefault();
-          event.stopPropagation();
-          // if file/folder is protected do nothing
-          if ($(this).find('.fa-lock').length)
-            return;
-          if ($(this).find('.fa-file-alt').length || $(this).find('.tbl_folder_rename').length > 0)
-            $(this).click();
-          // If folder then first select and then double click to open folder/drive
-          else if ($(this).find('.fa-folder-open').length || $(this).find('.fa-hdd').length) {
-            $(this).click();
-            setTimeout(() => { $(self).trigger('dblclick'); }, 10);
-          }
-        };
-
-        $listing_table.on( 'tablesorter-ready', function() {
-          let wo = this.config.widgetOptions;
-          if($.tablesorter.storage($listing_table[0], 'tablesorter-table-resized-width') === '') {
-            $.tablesorter.resizable.setWidth($listing_table, $('.fileinfo .file_listing').width());
-          }
-          $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
-          $listing_table.trigger('resizableUpdate');
-
-          // Table Sorter writes table elements randomly so we need to handle some corner cases manually
-          $('#show_hidden').off('keydown').on('keydown', function(event) {
-            if (!isGridView && event.keyCode == 9 && event.shiftKey) {
-              event.preventDefault();
-              $listing_table.find('tbody tr:last').trigger('focus');
-            }
-          });
-
-          $listing_table.find('tbody tr').off('keydown').on('keydown', function(event) {
-            // If key is pressed then we need to trigger click so that it can select file
-            if (event.keyCode == 13 || event.keyCode == 32) {
-              clickOnFileFolderManually.call(this, event);
-            } else if (event.keyCode == 9) {
-              if (event.shiftKey) {
-                // When first tr losses focus and shift + tab > we need to set focus on header
-                if ($(this).prev().length == 0) {
-                  event.preventDefault();
-                  $listing_table.find('th.tablesorter-header:last').trigger('focus');
-                }
-              } else {
-                // When last tr losses focus and Tab was pressed > we need to set focus on checkbox
-                if ($(this).next().length == 0) {
-                  event.preventDefault();
-                  $('#show_hidden').trigger('focus');
-                }
-              }
-            }
-          });
-
-          $listing_table.find('th.tablesorter-header').off('keydown').on('keydown', function(event) {
-            // If key is pressed then we need to trigger click so that it can sort
-            if (event.keyCode == 13 || event.keyCode == 32) {
-              event.preventDefault();
-              event.stopPropagation();
-              $(this).trigger('click');
-            }
-          });
-        });
-
-        if(isGridView) {
-          $('.file_manager').find('#contents li').off('keydown').on('keydown', function(event) {
-            // If key is pressed then we need to trigger click so that it can sort
-            if (event.keyCode == 13 || event.keyCode == 32) {
-              clickOnFileFolderManually.call(this, event);
-            }
-          });
-        }
-
-        // rename file/folder
-        $('.file_manager button.rename').off().on('click', function(e) {
-
-          if ($('.fileinfo').data('view') == 'grid') {
-            e.stopPropagation();
-            $this = $('.file_manager').find('#contents li.selected div');
-            orig_value = decodeURI($this.find('span.less_text').attr('title'));
-            newvalue = orig_value.substring(0, orig_value.indexOf('.'));
-
-            if (newvalue === '') {
-              newvalue = decodeURI(orig_value);
-            }
-
-            $this.find('input').toggle().val(newvalue).trigger('focus');
-            $this.find('span').toggle();
-
-            // Rename folder/file on pressing enter key
-            $('.file_manager').off().on('keyup', function(event) {
-              if (event.keyCode == 13) {
-                event.stopPropagation();
-                $('.fileinfo #contents li.selected div').find(
-                  'input'
-                ).trigger('blur');
-              }
-            });
-          } else if ($('.fileinfo').data('view') == 'list') {
-            e.stopPropagation();
-            $this = $('.fileinfo').find(
-              'table#contents tbody tr.selected td.tbl_file'
-            );
-            if($this.length == 0) {
-              $this = $('.fileinfo').find(
-                'table#contents tbody tr.selected td.tbl_folder'
-              );
-              // putting temporary class to distiguish between folder rename & double click.
-              $this.addClass('tbl_folder_rename');
-            }
-            orig_value = decodeURI($this.find('span.less_text').html());
-            newvalue = orig_value.substring(0, orig_value.lastIndexOf('.'));
-
-            if (orig_value.lastIndexOf('/') == orig_value.length - 1 || (_.isEmpty(newvalue) || _.isUndefined(newvalue) || _.isNull(newvalue))) {
-              newvalue = decodeURI(orig_value);
-            }
-
-            $this.find('.fm_file_rename').toggle().val(newvalue).trigger('focus');
-            $this.find('.fm_file_name').toggle();
-
-            // Rename folder/file on pressing enter key
-            $('.file_manager').off().on('keyup', function(event) {
-              if (event.keyCode == 13) {
-                event.stopPropagation();
-                $this.find('fm_file_rename').trigger('blur');
-              }
-            });
-          }
-        });
-
-        // Rename UI handling
-        $('.fileinfo #contents li div').on('blur dblclick', 'input', function(e) {
-          e.stopPropagation();
-
-          var old_name = decodeURI($(this).siblings('div').find('.less_text').attr('title'));
-          newvalue = old_name.substring(0, old_name.indexOf('.'));
-          var last = getFileExtension(old_name),
-            file_data, new_name, file_path, full_name;
-
-          if (old_name.indexOf('.') == 0) {
-            last = '';
-          }
-
-          if (newvalue == '') {
-            newvalue = decodeURI(old_name);
-          }
-
-          if (e.type == 'keydown') {
-            if (e.which == 13) {
-              full_name = decodeURI($(this).val()) + (
-                last !== '' ? '.' + last : ''
-              );
-
-              $(this).toggle();
-              $(this).siblings('span').toggle().html(full_name);
-
-              new_name = decodeURI($(this).val());
-              file_path = decodeURI($(this).parent().parent().find(
-                'span'
-              ).attr('data-alt'));
-              file_data = {
-                'Filename': old_name,
-                'Path': file_path,
-                'NewFilename': new_name,
-              };
-
-              if (newvalue !== new_name) {
-                renameItem(file_data);
-                var parent = $('.currentpath').val();
-                getFolderInfo(parent);
-              }
-              e.stopPropagation();
-            }
-
-            if (
-              e.which == 38 || e.which == 40 || e.which == 37 ||
-            e.which == 39 || e.keyCode == 32
-            ) {
-              e.stopPropagation();
-            }
-          } else if (e.type == 'focusout') {
-            if ($(this).css('display') == 'inline-block' || $(this).css('display') == 'inline') {
-              full_name = decodeURI(
-                $(this).val()
-              ) + (last !== '' ? '.' + last : '');
-
-              if (newvalue !== new_name) {
-
-                $(this).toggle();
-                $(this).siblings('span').toggle().html(full_name);
-
-                //check if user is trying to rename folder
-                let isFolder = $(this).closest('.tbl_folder').length > 0;
-
-                new_name = decodeURI($(this).val());
-                file_path = decodeURI($(this).parent().parent().find(
-                  'span'
-                ).attr('data-alt'));
-                file_data = {
-                  'Filename': old_name,
-                  'Path': file_path,
-                  'NewFilename': new_name,
-                  'isFolder': isFolder,
-                };
-
-                renameItem(file_data);
-                let current_path = $('.currentpath').val();
-                if(isFolder == true) {
-                  // if its folder rename, remove the temporary added class
-                  $(this).closest('.tbl_folder').removeClass('tbl_folder_rename');
-                  if(current_path.includes('\\')) {
-                    current_path = $('.currentpath').val().split('\\').slice(0, -2).join('\\')+'\\';
-                  }
-                  else {
-                    current_path = $('.currentpath').val().split('/').slice(0, -2).join('/')+'/';
-                  }
-                }
-                getFolderInfo(current_path);
-              }
-            }
-          } else {
-            e.stopPropagation();
-          }
-        });
-
-        $('.fileinfo table#contents tr td div').on(
-          'blur dblclick', 'input',
-          function(e) {
-            var old_name = decodeURI($(this).siblings('div').find('.less_text').attr('title')),
-              new_value = old_name.substring(0, old_name.indexOf('.')),
-              last = getFileExtension(old_name);
-            if (old_name.indexOf('.') == 0) {
-              last = '';
-            }
-
-            if (new_value == '') {
-              new_value = old_name;
-            }
-
-            if (e.type == 'focusout') {
-              if ($(this).css('display') == 'inline-block' || $(this).css('display') == 'inline') {
-                var full_name = decodeURI($(this).val()) + (
-                  last !== '' ? '.' + last : ''
-                );
-
-                if (new_value !== new_name) {
-
-                  $(this).toggle();
-                  $(this).siblings('span').toggle().html(full_name);
-
-                  let isFolder = $(this).closest('.tbl_folder').length > 0;
-
-                  var new_name = decodeURI($(this).val()),
-                    file_path = decodeURI($(this).parent().parent().attr('title')),
-                    file_data = {
-                      'Filename': old_name,
-                      'Path': file_path,
-                      'NewFilename': new_name,
-                      'isFolder': isFolder,
-                    };
-
-                  renameItem(file_data);
-                  let current_path = $('.currentpath').val();
-                  if(isFolder == true) {
-                    // if its folder rename, remove the temporary added class
-                    $(this).closest('.tbl_folder').removeClass('tbl_folder_rename');
-                    if(current_path.includes('\\')) {
-                      current_path = $('.currentpath').val().split('\\').slice(0, -2).join('\\')+'\\';
-                    }
-                    else {
-                      current_path = $('.currentpath').val().split('/').slice(0, -2).join('/')+'/';
-                    }
-                  }
-                  getFolderInfo(current_path);
-                }
-              }
-            } else {
-              e.stopPropagation();
-            }
-          });
-
-        var data_cap = {};
-        data_cap.Capabilities = capabilities;
-        /*
-       * Bind click events
-       * Select items - afolder dblclick
-       */
-        if ($('.fileinfo').data('view') == 'grid') {
-        // Get into folder on dblclick
-          $('.fileinfo').find('#contents li').dblclick(function(e) {
-            e.stopPropagation();
-            // Enable/Disable level up button
-            enab_dis_level_up();
-
-            var file_path = decodeURI($(this).find('span').attr('data-alt'));
-
-            if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) {
-              $('.file_manager_ok').addClass('disabled');
-              $('.file_manager_ok').attr('disabled', true);
-              $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
-              $('.file_manager button.download').attr('disabled', 'disabled');
-
-              getFolderInfo(file_path);
-
-            } else {
-              var is_valid_file = getFileInfo(file_path);
-              if (is_valid_file && check_file_capability(e, data_cap, 'grid')) {
-                $('.file_manager_ok').trigger('click');
-              }
-            }
-          });
-
-          $('.fileinfo').find('#contents li').on('click', function(e) {
-            e.stopPropagation();
-            var file_path = decodeURI($(this).find('.clip span').attr('data-alt')),
-              is_protected = $(this).find(
-                '.clip span.fm_lock_icon'
-              ).attr('data-protected');
-
-            if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) {
-              if (
-                has_capability(data_cap, 'select_folder') &&
-              is_protected == undefined
-              ) {
-                $(this).parent().find('li.selected').removeClass('selected');
-                $(this).addClass('selected');
-
-                $('.file_manager_ok').removeClass('disabled');
-                $('.file_manager_ok').attr('disabled', false);
-                $('.file_manager button.delete, .file_manager button.rename').removeAttr(
-                  'disabled', 'disabled'
-                );
-                $('.file_manager button.download').attr(
-                  'disabled', 'disabled'
-                );
-                // set selected folder name in breadcrums
-                $('.file_manager #uploader .input-path').hide();
-                $('.file_manager #uploader .show_selected_file').remove();
-                $('<span class="show_selected_file">' + file_path + '</span>').appendTo(
-                  '.file_manager #uploader .filemanager-path-group'
-                );
-              }
-              pgAdmin.FileUtils.setUploader(file_path);
-            } else {
-              if (
-                has_capability(data_cap, 'select_file') &&
-              is_protected == undefined
-              ) {
-                $(this).parent().find('li.selected').removeClass('selected');
-                $(this).addClass('selected');
-                $('.file_manager_ok').removeClass('disabled');
-                $('.file_manager_ok').attr('disabled', false);
-                $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr(
-                  'disabled'
-                );
-                // set selected folder name in breadcrums
-                $('.file_manager #uploader .show_selected_file').remove();
-              }
-
-              getFileInfo(file_path);
-            }
-          });
-        } else {
-          $('.fileinfo table#contents tbody tr').on('click', function(e) {
-            e.stopPropagation();
-            var file_path = decodeURI($('td:first-child', this).attr('title')),
-              is_protected = $('td:first-child', this).find(
-                'i.tbl_lock_icon'
-              ).attr('data-protected');
-
-            if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) {
-              if (has_capability(data_cap, 'select_folder') && is_protected == undefined) {
-                $(this).parent().find('tr.selected').removeClass('selected');
-                $('td:first-child', this).parent().addClass('selected');
-                $('.file_manager_ok').removeClass('disabled');
-                $('.file_manager_ok').attr('disabled', false);
-                $('.file_manager button.download').attr('disabled', 'disabled');
-                $('.file_manager button.delete, .file_manager button.rename').removeAttr('disabled');
-
-                // set selected folder name in breadcrums
-                $('.file_manager #uploader .input-path').hide();
-                $('.file_manager #uploader .show_selected_file').remove();
-                $('<span class="show_selected_file">' + file_path + '</span>').appendTo(
-                  '.file_manager #uploader .filemanager-path-group'
-                );
-              }
-              pgAdmin.FileUtils.setUploader(file_path);
-            } else {
-              if (has_capability(data_cap, 'select_file') && is_protected == undefined) {
-                $(this).parent().find('tr.selected').removeClass('selected');
-                $('td:first-child', this).parent().addClass('selected');
-                $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr(
-                  'disabled'
-                );
-                // set selected folder name in breadcrums
-                $('.file_manager #uploader .show_selected_file').remove();
-              }
-
-              getFileInfo(file_path);
-            }
-          });
-
-          $('.fileinfo table#contents tbody tr').on('dblclick', function(e) {
-            e.stopPropagation();
-            // Enable/Disable level up button
-            enab_dis_level_up();
-            var file_path = $('td:first-child', this).attr('title');
-
-            if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) {
-              $('.file_manager_ok').addClass('disabled');
-              $('.file_manager_ok').attr('disabled', true);
-              $('.file_manager button.download').attr('disabled', 'disabled');
-              $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
-              getFolderInfo(file_path);
-            } else {
-              var is_valid_file = getFileInfo(file_path);
-              if (
-                is_valid_file && check_file_capability(e, data_cap, 'table')
-              ) {
-                $('.file_manager_ok').trigger('click');
-              }
-            }
-          });
-
-        }
-      })
-      .fail(function() {
-        $('.storage_dialog #uploader .input-path').prop('disabled', false);
-      });
-  };
-  var homedir='/';
-  // Enable/Disable level up button
-  var enab_dis_level_up = function() {
-    $('.file_manager #uploader .input-path').show();
-    $('.show_selected_file').remove();
-
-    setTimeout(function() {
-      var b = $('.currentpath').val(),
-        $level_up = $('.file_manager').find('button.level-up'),
-        $home_btn = $('.file_manager').find('button.home');
-
-      (b === '/') ? $level_up.attr('disabled', 'disabled') : $level_up.removeAttr('disabled');
-      (b === homedir) ? $home_btn.attr('disabled', 'disabled') : $home_btn.removeAttr('disabled');
-
-    }, 100);
-  };
-
-  // Check if user can Select file
-  var check_file_capability = function(event, data_cap, view_type) {
-    var current_element = event.currentTarget,
-      is_protected;
-
-    if (view_type == 'grid') {
-      is_protected = $(current_element).find(
-        '.clip span.fm_lock_icon'
-      ).attr('data-protected');
-    } else {
-      is_protected = $(current_element).find('td:first-child').find(
-        'i.tbl_lock_icon'
-      ).attr('data-protected');
-    }
-
-    return has_capability(data_cap, 'select_file') &&
-      is_protected == undefined;
-  };
-
-  // Download selected file
-  var download_file = function (path) {
-
-    var data = { 'path': path, 'mode': 'download' },
-      params = {};
-
-    params[pgAdmin.csrf_token_header] = pgAdmin.csrf_token;
-
-    $.ajax({
-      type: 'POST',
-      url: pgAdmin.FileUtils.fileConnector,
-      contentType: false,
-      headers: params,
-      xhrFields: {
-        responseType: 'blob',
-      },
-      cache: false,
-      data: JSON.stringify(data),
-      success: function (blob, status, xhr) {
-        // check for a filename
-        var filename = xhr.getResponseHeader('filename');
-
-        if (typeof window.navigator.msSaveBlob !== 'undefined') {
-          // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
-          window.navigator.msSaveBlob(blob, filename);
-        } else {
-          var URL = window.URL || window.webkitURL;
-          var downloadUrl = URL.createObjectURL(blob);
-
-          if (filename) {
-            // use HTML5 a[download] attribute to specify filename
-            var a = document.createElement('a');
-            // safari doesn't support this yet
-            if (typeof a.download === 'undefined') {
-              window.location.href = downloadUrl;
-            } else {
-              a.href = downloadUrl;
-              a.download = filename;
-              document.body.appendChild(a);
-              a.click();
-            }
-          } else {
-            window.location.href = downloadUrl;
-          }
-
-          setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
-        }
-      },
-      error: function (error) {
-        Notify.error(error);
-      },
-    });
-  };
-
-  /*---------------------------------------------------------
-    Initialization - Entry point
-  ---------------------------------------------------------*/
-  /*
-   * get transaction id to generate request url and
-   * to generate config files on runtime
-   */
-  pgAdmin.FileUtils = {
-    init: function() {
-      var fm_url = url_for('file_manager.get_trans_id'),
-        transId = loadData(fm_url),
-        t_res,
-        t_id;
-
-      if (transId.readyState == 4) {
-        t_res = JSON.parse(transId.responseText);
-      }
-      t_id = _.isUndefined(t_res) ? 0 : t_res.data.fileTransId;
-      var root_url = url_for('file_manager.index'),
-        file_manager_config_json = root_url + t_id + '/file_manager_config.json',
-        fileConnector = root_url + 'filemanager/' + t_id + '/',
-        cfg = loadData(file_manager_config_json),
-        config;
-
-      this.fileConnector = fileConnector;
-      this.transId = t_id;
-      // load user configuration file
-      if (cfg.readyState == 4) {
-        this.config = config = JSON.parse(cfg.responseText);
-        homedir=config.options.homedir;
-      }
-
-      if (_.isUndefined(config))
-        return;
-
-      // set main url to filemanager and its capabilites
-      var fileRoot = config.options.fileRoot,
-        capabilities = config.options.capabilities;
-
-      /*
-       * Get localized messages from file
-       * through culture var or from URL
-       */
-
-      var lg = [],
-        enjson = url_for('file_manager.index') + 'en.json',
-        lgf = loadData(enjson);
-
-      if (lgf.readyState == 4) {
-        this.lg = lg = JSON.parse(lgf.responseText);
-      }
-
-      // create and enable user to create new file
-      if (
-        config.options.dialog_type == 'select_file' ||
-        config.options.dialog_type == 'create_file' ||
-        config.options.dialog_type == 'storage_dialog'
-      ) {
-        // Create file selection dropdown
-        var allowed_types = config.options.allowed_file_types,
-          types_len = allowed_types.length,
-          select_box = '';
-
-        if (types_len > 0) {
-          var i = 0,
-            t,
-            have_all_types = false;
-
-          let fileFormats = '';
-          let response = getFileFormat(config.options.allowed_file_types);
-          let lastSelectedFormat =  response.responseJSON.info;
-
-          while (i < types_len) {
-            t = allowed_types[i];
-            if ((types_len == 1 || t != '*')) {
-              if(t === lastSelectedFormat)
-                fileFormats += '<option value=' + t + ' selected >' + t + '</option>';
-              else
-                fileFormats += '<option value=' + t + ' >' + t + '</option>';
-              have_all_types = (have_all_types || (t == '*'));
-            } else if ((lastSelectedFormat === '*')) {
-              fileFormats += '<option value="' + t + '" selected >' +
-                (t == '*' ? gettext('All Files') : t) + '</option>';
-              have_all_types = (have_all_types || (t == '*'));
-            }
-            i++;
-          }
-
-          if (!have_all_types) {
-            fileFormats += '<option value="*">' + gettext('All Files') + '</option>';
-          }
-
-          select_box = `<div class='change_file_types d-flex align-items-center p-1'>
-          <div>` +
-            gettext('Show hidden files and folders?') +
-            `<input  aria-label="Show hidden files and folders" type='checkbox' id='show_hidden' onclick='pgAdmin.FileUtils.handleClick(this)' tabindex='0'>
-          </div>
-          <div class="ml-auto">
-            <label class="my-auto">` + gettext('Format') + `</label>
-            <select aria-label="select" name='type' tabindex='0'>${fileFormats}</select>
-          <div>`;
-        }
-
-        $('.allowed_file_types').html(select_box);
-
-        $('.allowed_file_types select').on('change', function() {
-          var selected_val = $(this).val(),
-            curr_path = $('.currentpath').val(),
-            user_input_file = null,
-            input_path = $('.storage_dialog #uploader .input-path').val();
-          config.options.selectedFormat = selected_val;
-          $.ajax({
-            url: url_for('settings.save_file_format_setting'),
-            type: 'POST',
-            contentType: 'application/json',
-            data: JSON.stringify(config.options),
-          });
-          if (curr_path.endsWith('/')) {
-            user_input_file = input_path.substring(curr_path.lastIndexOf('/')+1);
-          } else {
-            user_input_file = input_path.substring(curr_path.lastIndexOf('\\')+1);
-          }
-          getFolderInfo(curr_path, selected_val, user_input_file);
-        });
-
-        // If user have preference to show hidden files
-        if (config.options.show_hidden_files) {
-          setTimeout(function() {
-            $('#show_hidden').trigger('click');
-          }, 10);
-        }
-        // handle show hidden files functionality
-        this.handleClick = function(cb) {
-          var tmp_data = {
-            'is_checked': false,
-          };
-
-          if (cb.checked) {
-            $('div.allowed_file_types select').trigger('change');
-            tmp_data['is_checked'] = true;
-          } else {
-            // User wants to hide it again
-            $('div.allowed_file_types select').trigger('change');
-            tmp_data['is_checked'] = false;
-          }
-          // Save it in preference
-          save_show_hidden_file_option(tmp_data['is_checked'], pgAdmin.FileUtils.transId);
-        };
-      }
-
-      /*---------------------------------------------------------
-        Item Actions - Object events
-      ---------------------------------------------------------*/
-
-      $('.file_manager').attr('data-platform', config.options.platform_type);
-
-      // Switch to folder view
-      $('.file_manager .fileinfo').on('click', function() {
-        enable_disable_btn();
-      });
-
-
-
-      // Refresh current directory
-      $('.file_manager .refresh').on('click', function() {
-        enable_disable_btn();
-
-        var curr_path = $('.currentpath').val(),
-          path;
-
-        $('.file_manager #uploader .input-path').val(curr_path);
-        if (curr_path.endsWith('/')) {
-          path = curr_path.substring(0, curr_path.lastIndexOf('/')) + '/';
-        } else {
-          path = curr_path.substring(0, curr_path.lastIndexOf('\\')) + '\\';
-        }
-        getFolderInfo(path);
-      });
-
-      // hide message prompt and dimmer if clicked no
-      $('.delete_item button.btn_no').on('click', function() {
-        $('.delete_item, .fileinfo .fm_dimmer').hide();
-      });
-
-      // Disable button on load
-      $('.file_manager').find('button.rename').attr('disabled', 'disabled');
-
-      // stop click event on dimmer click
-      $('.fileinfo .fm_dimmer').on('click', function(e) {
-        e.stopPropagation();
-      });
-
-      $('.fileinfo .replace_file').not(
-        $(this).find('span.pull-right')
-      ).on(
-        'click',
-        function(e) {
-          $('#uploader .filemanager-btn-group').off().on(
-            'click',
-            function() {
-              $('.fileinfo .delete_item, .fileinfo .replace_file, .fileinfo .fm_dimmer').hide();
-            });
-          e.stopPropagation();
-        });
-
-      // Set initial view state.
-      $('.fileinfo').data('view', config.options.defaultViewMode);
-      setViewButtonsFor(config.options.defaultViewMode);
-
-      // Upload click event
-      $('.file_manager .uploader').on('click', 'a', function(e) {
-        e.preventDefault();
-        var b = $('.currentpath').val(),
-          node_val = $(this).next().text(),
-          parent = b.substring(0, b.slice(0, -1).lastIndexOf(node_val));
-        getFolderInfo(parent);
-      });
-
-      // re-render the home view
-      $('.file_manager .home').on('click', function() {
-        var currentViewMode = $('.fileinfo').data('view');
-        $('.fileinfo').data('view', currentViewMode);
-        getFolderInfo(homedir);
-        enab_dis_level_up();
-      });
-
-      // Go one directory back
-      $('.file_manager .level-up').on('click', function() {
-        var b = $('.currentpath').val();
-        // Enable/Disable level up button
-        enab_dis_level_up();
-
-        if (b.endsWith('\\') || b.endsWith('/')) {
-          b = b.substring(0, b.length - 1);
-        }
-
-        if (b != '/') {
-          var parent;
-          if (b.lastIndexOf('/') > b.lastIndexOf('\\')) {
-            parent = b.substring(0, b.slice(0, -1).lastIndexOf('/')) + '/';
-          } else {
-            parent = b.substring(0, b.slice(0, -1).lastIndexOf('\\')) + '\\';
-          }
-
-          var d = $('.fileinfo').data('view');
-          $('.fileinfo').data('view', d);
-          getFolderInfo(parent);
-        }
-      });
-
-      // set buttons to switch between grid and list views.
-      $('.file_manager .grid').on('click',() => {
-        setViewButtonsFor('grid');
-        $('.fileinfo').data('view', 'grid');
-        enable_disable_btn();
-        getFolderInfo($('.currentpath').val());
-        save_file_dialog_view('grid', pgAdmin.FileUtils.transId);
-      });
-
-      // Show list mode
-      $('.file_manager .list').on('click',() => {
-        setViewButtonsFor('list');
-        $('.fileinfo').data('view', 'list');
-        enable_disable_btn();
-        getFolderInfo($('.currentpath').val());
-        save_file_dialog_view('list', pgAdmin.FileUtils.transId);
-      });
-
-      // Provide initial values for upload form, status, etc.
-      pgAdmin.FileUtils.setUploader(fileRoot);
-
-      var data;
-      this.data = data = {
-        'Capabilities': capabilities,
-      };
-
-      function InputObject() {
-        this.init = function(cap) {
-          var self = this,
-            check_obj = function(path, check) {
-
-              path = decodeURI(path);
-              if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
-                if (
-                  has_capability(self.data_cap, 'select_folder')
-                ) {
-                  $('.file_manager_ok').removeClass('disabled');
-                  $('.file_manager_ok').attr('disabled', false);
-                  $('.file_manager button.delete').removeAttr(
-                    'disabled', 'disabled'
-                  );
-                  $('.file_manager button.download').attr(
-                    'disabled', 'disabled'
-                  );
-                  $('.file_manager button.rename').attr('disabled', 'disabled');
-                  // set selected folder name in breadcrums
-                  $('.file_manager #uploader .show_selected_file').remove();
-                  $('<span class="show_selected_file">' + path + '</span>').appendTo(
-                    '.file_manager #uploader .filemanager-path-group'
-                  );
-                } else {
-                  $('.file_manager_ok').addClass('disabled');
-                  $('.file_manager_ok').attr('disabled', true);
-                  if (check) {
-                    // Enable/Disable level up button
-                    enab_dis_level_up();
-
-                    $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
-                    $('.file_manager button.download').attr('disabled', 'disabled');
-                    getFolderInfo(path);
-                  }
-                }
-              } else {
-                if (has_capability(self.data_cap, 'select_folder')) {
-                  disableSelect();
-                }
-
-                if (
-                  has_capability(self.data_cap, 'select_file')
-                ) {
-                  $('.file_manager_ok').removeClass('disabled');
-                  $('.file_manager_ok').attr('disabled', false);
-                  $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr(
-                    'disabled'
-                  );
-                  // set selected folder name in breadcrumbs
-                  $('.file_manager #uploader .show_selected_file').remove();
-                }
-
-                if (check) {
-                  if (config.options.dialog_type == 'create_file') {
-                    var status = checkPermission(path);
-                    if (status) {
-                      $('.file_manager_ok').trigger('click');
-                    }
-                  } else if (config.options.dialog_type == 'select_file') {
-                    var file_status = getFileInfo(path);
-                    if (file_status) {
-                      $('.file_manager_ok').trigger('click');
-                    }
-                  }
-                }
-              }
-            };
-
-          self.data_cap = cap;
-
-          $('.storage_dialog #uploader .input-path').on('keyup',function(e) {
-            if (e.keyCode == 13) {
-              e.stopPropagation();
-              var path = $(this).val();
-              if (path == '') {
-                path = '/';
-              }
-
-              if (config.options.platform_type === 'win32') {
-                path = path.replace(/\//g, '\\');
-              } else {
-                path = path.replace(/\\/g, '/');
-                if (!path.startsWith('/')) {
-                  path = '/' + path;
-                }
-              }
-
-              $(this).val(path);
-              setTimeout(function() {
-                check_obj(path, true);
-              });
-
-              return;
-            }
-            check_obj($(this).val(), false);
-          });
-        };
-        this.set_cap = function(cap) {
-          this.data_cap = cap;
-        };
-      }
-      var input_object = new InputObject();
-      input_object.init(data);
-
-      // Upload file
-      if (has_capability(data, 'upload')) {
-        Dropzone.autoDiscover = false;
-        // we remove simple file upload element
-        $('.file-input-container').remove();
-        $('.upload').remove();
-        $('.create').before('<button aria-label="Upload" value="Upload" type="button" title="Upload File" name="upload" id="upload" class="btn btn-sm btn-primary-icon upload" tabindex="0"><span class="fa fa-upload sql-icon-lg"></span></button> ');
-
-        $('#uploader .upload').off().on('click', function() {
-          // we create prompt
-          var msg = '<div id="dropzone-container" class="d-flex flex-column flex-grow-1">' +
-            '<button class="fa fa-times fa-lg dz_cross_btn ml-auto" tabindex="0"></button>' +
-            '<div id="multiple-uploads" class="dropzone flex-grow-1 d-flex p-1">'+
-            '<div class="dz-default dz-message d-none"></div>'+
-            '</div>' +
-            '<div class="prompt-info">' + gettext('Drop files here to upload.') + ' ' + lg.file_size_limit +
-            config.upload.fileSizeLimit + ' ' + lg.mb + '.</div>',
-            path = $('.currentpath').val(),
-            filesizelimit = config.upload.fileSizeLimit,
-            // default dropzone value
-            fileSize = (filesizelimit != 'auto') ? filesizelimit : 256,
-            acceptFiles;
-
-          if (config.security.uploadPolicy == 'DISALLOW_ALL') {
-            acceptFiles = '.' + config.security.uploadRestrictions.join(',.');
-          } else {
-            // We allow any extension since we have no easy way to handle the the
-            // built-in `acceptedFiles` params would be handled later by the
-            // connector.
-            acceptFiles = null;
-          }
-
-          $('.file_manager .upload_file').toggleClass('d-none');
-          $('.file_manager .file_listing').toggleClass('d-none');
-          $('.file_manager .upload_file').html(msg);
-
-          var previewTemplate = '<div class="file_upload_main dz-preview dz-file-preview">' +
-            '<div class="show_error">' +
-            '<p class="size dz-size" data-dz-size></p>' +
-            '<p class="name dz-filename" data-dz-name></p>' +
-            '</div>' +
-            '<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>' +
-            '<div class="dz-success-mark"><span></span></div>' +
-            '<div class="dz-error-mark"><span></span></div>' +
-            '<div class="dz-error-message"><span data-dz-errormessage></span></div>' +
-            '<a href="javascript:void(0);" class="fa fa-trash dz_file_remove" data-dz-remove></a>' +
-            '</div>';
-
-          // We need to append our csrf token with dropzone's ajax request header
-          let csrfToken = {};
-          csrfToken[pgAdmin.csrf_token_header] = pgAdmin.csrf_token;
-
-          $('div#multiple-uploads').dropzone({
-            paramName: 'newfile',
-            url: pgAdmin.FileUtils.fileConnector,
-            headers: csrfToken,
-            maxFilesize: fileSize,
-            maxFiles: config.upload.number,
-            addRemoveLinks: true,
-            previewTemplate: previewTemplate,
-            parallelUploads: config.upload.number,
-            dictMaxFilesExceeded: lg.dz_dictMaxFilesExceeded.replace(
-              '%s', config.upload.number
-            ),
-            dictDefaultMessage: lg.dz_dictDefaultMessage,
-            dictInvalidFileType: lg.dz_dictInvalidFileType,
-            dictFileTooBig: lg.file_too_big + ' ' + lg.file_size_limit +
-              config.upload.fileSizeLimit + ' ' + lg.mb,
-            acceptedFiles: acceptFiles,
-            autoProcessQueue: true,
-            init: function() {
-              $('.dz_cross_btn').off().on('click', function() {
-                $('.file_manager .upload_file').toggleClass('d-none');
-                $('.file_manager .file_listing').toggleClass('d-none');
-              });
-            },
-            sending: function(file, xhr, formData) {
-              formData.append('mode', 'add');
-              formData.append('currentpath', path);
-              $('.upload_file .dz_cross_btn').attr('disabled', 'disabled');
-              setTimeout(function() {/*This is intentional (SonarQube)*/}, 10000);
-            },
-            success: function(file, response) {
-              var resp_data = response.data.result,
-                $this = $(file.previewTemplate);
-
-              if (resp_data.Code == 1) {
-                setTimeout(function() {
-                  $this.find('.dz-upload').addClass('success');
-                }, 1000);
-                $this.find('.dz-upload').css('width', '100%').html('100%');
-                Notify.success(lg.upload_success);
-              } else {
-                $this.find('.dz-upload').addClass('error');
-                $this.find('.dz-upload').css('width', '0%').html('0%');
-                Notify.error(resp_data.Error);
-              }
-              getFolderInfo(path);
-            },
-            totaluploadprogress: function() {/*This is intentional (SonarQube)*/},
-            complete: function(file) {
-              if (file.status == 'error') {
-                Notify.error(lg.upload_error);
-              }
-              $('.upload_file .dz_cross_btn').removeAttr('disabled');
-              getFolderInfo(path);
-            },
-          });
-        });
-      }
-
-      this.getDetailView(fileRoot);
-    },
-    /*
-     * Sets the folder status, upload, and new folder functions
-     * to the path specified. Called on initial page load and
-     * whenever a new directory is selected.
-     */
-    setUploader: function(path) {
-      var config = this.config;
-      var lg = this.lg;
-      $('.storage_dialog #uploader').find('a').remove();
-      $('.storage_dialog #uploader').find('b').remove();
-
-      if (config.options.platform_type === 'win32') {
-        path = path.replace(/\//g, '\\');
-      } else {
-        path = path.replace(/\\/g, '/');
-      }
-
-      path = decodeURI(path);
-      if (config.options.platform_type === 'win32') {
-        if (config.options.show_volumes && path == '\\') {
-          $('.storage_dialog #uploader .input-path').val('');
-        } else {
-          $('.storage_dialog #uploader .input-path').val(path);
-        }
-      } else if ((config.options.platform_type !== 'win32') &&
-        (path == '' || !path.startsWith('/'))) {
-        path = '/' + path;
-        $('.storage_dialog #uploader .input-path').val(path);
-      } else {
-        $('.storage_dialog #uploader .input-path').val(path);
-      }
-
-      if (path.lastIndexOf('\\') == -1 && path.lastIndexOf('/') == -1) {
-        $('.currentpath').val(path);
-      } else if (path.lastIndexOf('/') > path.lastIndexOf('\\')) {
-        $('.currentpath').val(path.substr(0, path.lastIndexOf('/') + 1));
-      } else {
-        $('.currentpath').val(path.substr(0, path.lastIndexOf('\\') + 1));
-      }
-
-      enab_dis_level_up();
-      if ($('.storage_dialog #uploader h1 span').length === 0) {
-        $('<span>' + lg.current_folder + '</span>').appendTo($('.storage_dialog #uploader h1'));
-      }
-
-      $('.storage_dialog #uploader .input-path').attr('title', path);
-      $('.storage_dialog #uploader .input-path').attr('data-path', path);
-      enableSelect();
-
-      // create new folder
-      $('.create').off().on('click', function() {
-        var foldername = lg.new_folder;
-        var $file_element,
-          $file_element_list,
-          folder_div;
-
-
-        $('.file_manager button.create').attr('disabled', 'disabled');
-        $('.no_folder_found').addClass('d-none');
-        if ($('.fileinfo').data('view') == 'grid') {
-
-          // template for creating new folder
-          folder_div =
-            '<li tabIndex="0" class=\'cap_download cap_delete cap_select_file cap_select_folder cap_rename cap_create cap_upload\'>' +
-            '<div class=\'clip\'><span data-alt=\'\' class=\'fa fa-folder-open fm_folder_grid\' role="img"></span></div>' +
-            '<div><input type=\'text\' class=\'fm_file_rename\'><span class="less_text" title=\'\'>New_Folder</span></div>' +
-            '<span class=\'meta size\'></span><span class=\'meta created\'></span><span class=\'meta modified\'></span></li>';
-
-          path = $('.currentpath').val();
-          $file_element = $(folder_div);
-          $('.fileinfo #contents.grid').prepend($file_element);
-          $file_element.find('div span.less_text').toggle();
-          $file_element.find('div input').toggle().val(lg.new_folder).select();
-
-          // rename folder/file on pressing enter key
-          $('.file_manager').on('keyup', function(e) {
-            if (e.keyCode == 13) {
-              e.stopPropagation();
-              $file_element.find('div input').trigger('blur');
-            }
-          });
-
-          // rename folder/file on blur
-          $file_element.find('div input').on('blur', function() {
-            $('.file_manager button.create').removeAttr('disabled');
-            var text_value = $file_element.find('div input').val();
-
-            path = $('.currentpath').val();
-
-            $file_element.find('div input').toggle();
-            $file_element.find('div span.less_text').toggle().html(text_value);
-            if (text_value === undefined) {
-              text_value = lg.new_folder;
-            }
-            getFolderName(text_value);
-            getFolderInfo(path);
-          });
-
-        } else if ($('.fileinfo').data('view') == 'list') {
-          // template to create new folder in table view
-          folder_div = $(
-            `<tr class=\'cap_download cap_delete cap_select_file cap_select_folder cap_rename cap_create cap_upload\'>
-              <td title=\'\' class=\' tbl_folder\'>
-                <div>
-                  <input type="text" class="fm_file_rename"/>
-                  <div class="fm_file_name">
-                    <div class="d-flex">
-                      <span class="fa fa-folder-open fm_folder_list" role="img"></span>
-                      <span class="less_text ml-2">${lg.new_folder}</span>
-                    </div>
-                  <div>
-                </div>
-              </td>
-              <td><span title=\'\'></span></td>
-              <td></td>
-            </tr>`
-          );
-
-          $file_element_list = $(folder_div);
-          let tableEl = $('.fileinfo #contents.file_listing_table');
-          tableEl.removeClass('file_listing_table_no_data');
-          tableEl.find('tbody').prepend($file_element_list);
-
-          $file_element_list.find('td .fm_file_name').toggle();
-          $file_element_list.find('td input').toggle().val(lg.new_folder).select();
-
-          // rename folder/file on pressing enter key
-          $('.file_manager').on('keyup', function(e) {
-            if (e.keyCode == 13) {
-              e.stopPropagation();
-              $file_element_list.find('td input').trigger('blur');
-            }
-          });
-
-          // rename folder/file on blur
-          $file_element_list.find('td input').on('blur', function() {
-            $('.file_manager button.create').removeAttr('disabled');
-            var text_value = $file_element_list.find('td input').val();
-            path = $('.currentpath').val();
-            $file_element_list.find('td input').toggle();
-            $file_element_list.find('td .fm_file_name span.less_text').html(text_value);
-            $file_element_list.find('td .fm_file_name').toggle();
-            if (text_value === undefined) {
-              text_value = lg.new_folder;
-            }
-            getFolderName(text_value);
-            getFolderInfo(path);
-          });
-        }
-
-        // create a new folder
-        var getFolderName = function(value) {
-          var fname = value;
-
-          if (fname != '') {
-            foldername = fname;
-            // Add _ variable in URL for avoiding the caching
-            $.getJSON(
-              pgAdmin.FileUtils.fileConnector + '?_=' + Date.now() + '&mode=addfolder&path=' + $('.currentpath').val() + '&name=' + foldername,
-              function(resp) {
-                var result = resp.data.result;
-                if (result.Code === 1) {
-                  Notify.success(lg.successful_added_folder);
-                  getFolderInfo(result.Parent);
-                } else {
-                  Notify.error(result.Error);
-                }
-              }
-            );
-          } else {
-            Notify.error(lg.no_foldername);
-          }
-        };
-
-      });
-    },
-    /* Decides whether to retrieve file or folder info based on
-     * the path provided.
-     */
-    getDetailView: function(path) {
-      if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
-        var allowed_types = this.config.options.allowed_file_types;
-
-        let set_type;
-
-        let response = getFileFormat(this.config.options.allowed_file_types);
-        let lastSelectedFormat =  response.responseJSON.info;
-        if (_.isUndefined(lastSelectedFormat) || allowed_types.indexOf(lastSelectedFormat) < 0)
-          set_type = allowed_types[0];
-        else
-          set_type = lastSelectedFormat;
-        getFolderInfo(path, set_type);
-      }
-    },
-    // helpful in show/hide toolbar button for Windows
-    hideButtons: function() {
-      return (
-        this.config.options.platform_type === 'win32' &&
-        $('.currentpath').val() === ''
-      );
-    },
-
-  };
-  return pgAdmin.FileUtils;
-});
-//@ sourceURL=utility.js
diff --git a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss b/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
deleted file mode 100644
index 4d15c348c..000000000
--- a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
+++ /dev/null
@@ -1,366 +0,0 @@
-#uploader h1 b {
-  font-weight: normal;
-  color:  $color-gray;
-}
-
-.file_listing {
-  min-width: 100%;
-  position: relative;
-  overflow: auto;
-
-  .file_listing_table_no_data {
-    height: auto !important;
-  }
-
-  .file_listing_table {
-    table-layout: fixed;
-    & td, &th {
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-  }
-
-  .file_listing_table thead tr {
-    border-bottom: $panel-border;
-  }
-
-  .file_listing_table tbody tr {
-    max-width: 100%;
-    width: 100%;
-  }
-
-  .file_listing_table tbody tr td:nth-child(1),
-  .file_listing_table thead tr th:nth-child(1) {
-    width: 400px;
-    min-width: 100px;
-  }
-
-  .file_listing_table tbody tr td:nth-child(2),
-  .file_listing_table thead tr th:nth-child(2) {
-    width: 100px;
-    min-width: 100px;
-  }
-
-  .file_listing_table tbody tr td:nth-child(3),
-  .file_listing_table thead tr th:nth-child(3) {
-    width: 200px;
-    min-width: 200px;
-    max-width: 200px;
-  }
-}
-
-.file_listing #contents.grid li:hover,
-.file_listing #contents.grid li.selected {
-  cursor: pointer;
-  border: $table-hover-border;
-  background: $grid-hover-bg-color;
-  color: $grid-hover-fg-color;
-}
-
-.fileinfo #contents li span.less_text {
-  width: 100%;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  text-align: center;
-  white-space: nowrap;
-  display: block;
-}
-
-.fileinfo table#contents tr td {
-  font-family: $font-family-primary;
-
-  & span.less_text {
-    text-overflow: ellipsis;
-    overflow: hidden;
-    white-space: nowrap;
-    display: block;
-  }
-
-  & .fa {
-    line-height: inherit;
-  }
-}
-
-.fm_folder_grid, .fm_file_grid {
-  font-size: xx-large !important;
-}
-
-.fm_folder_list,
-.fm_folder_grid,
-.fm_file_grid,
-.fm_file_list {
-  color: $color-fg;
-}
-
-.fm_drive {
-  font-size: xx-large !important;
-  color:  $color-gray;
-}
-
-.newfile {
-  position: absolute;
-  top:0;
-  left: 3px;
-  right:0;
-  width: 152px;
-  height:23px;
-  opacity:0;  filter: alpha(opacity=0);
-  cursor: pointer;
-  border:1px solid $color-primary;
-}
-
-.file_listing #contents.grid li {
-  display: block;
-  float: left;
-  width: 100px;
-  height: 80px;
-  text-align: center;
-  overflow: hidden;
-  margin: 0.5rem;
-  -webkit-border-radius: 2px;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  border: 1px solid $color-bg;
-}
-
-.file_manager {
-  position: absolute;
-  top: 0px;
-  bottom: 0px;
-  left: 0px;
-  right: 0px;
-}
-
-.file_manager #uploader {
-  border-bottom: $panel-border;
-}
-
-.file_manager #uploader .filemanager-path-group {
-  padding: 0;
-  display: block;
-  border: 1px solid  $border-color;
-  height: 30px;
-  border-radius: 5px;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  float: left;
-  margin-right: 10px;
-  background: $color-gray-lighter;
-}
-
-.file_manager #uploader .btn-group .btn[disabled] {
-  color:  $color-gray-light;
-  background-color: $color-gray-lighter;
-}
-
-.file_manager #uploader .filemanager-btn-group {
-  border: 1px solid  $border-color;
-  border-radius: 5px;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  width: auto;
-  float: left;
-  overflow: hidden;
-}
-
-.file_manager .upload_file #dropzone-container {
-  background: $color-gray-light;
-}
-
-.fileinfo .prompt-info {
-  text-align: center;
-  color: $color-fg;
-}
-
-.allowed_file_types {
-  border-top: $panel-border;
-  background: $color-bg;
-  z-index: 5;
-  padding: 0.25rem;
-}
-
-.upload_file{
-  min-width: 100%;
-}
-
-.upload_file .file_upload_main {
-  height: 127px;
-  width: 120px;
-  display: inline-block;
-  margin: 0 15px 15px 0 !important;
-  border: 1px solid $color-bg;
-  position: relative;
-  border-radius: 5px;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  background: $color-bg;
-  opacity: 1;
-}
-
-.upload_file .file_upload_main .show_error {
-  padding: 10px 0 0 10px;
-  color: $color-fg;
-}
-
-.file_upload_main .dz-progress {
-  float: left;
-  width: 100%;
-  height: 21px !important;
-  border: 1px solid  $border-color;
-  border-radius: 0 !important;
-  -moz-border-radius: 0 !important;
-  -webkit-border-radius: 0 !important;
-}
-
-.file_upload_main .dz-progress .dz-upload {
-  background: $color-primary-light !important;
-  text-align: center;
-}
-
-.file_upload_main .dz-progress .dz-upload.success {
-  background: $color-success-light !important;
-  float: left;
-  width: 100%;
-}
-
-.upload_file .file_upload_main a.dz_file_remove {
-  position: absolute;
-  top: 0;
-  right: 0;
-  color: $color-danger;
-  cursor: pointer;
-  border-radius: 5px;
-  -moz-border-radius: 5px;
-  -webkit-border-radius: 5px;
-  font-size: large;
-}
-
-.upload_file .file_upload_main a.dz_file_remove:hover {
-  border: 1px solid $color-fg;
-}
-
-.dropzone .dz-message {
-  color: $color-gray;
-}
-
-.fileinfo .fm_dimmer {
-  display: none;
-  top: 0;
-  bottom: 0;
-  background: $loading-bg;
-  opacity: 0.5;
-  width: 100%;
-  position: absolute;
-  z-index: 3;
-}
-
-.fileinfo .delete_item, .fileinfo .replace_file {
-  display: none;
-  padding: 1rem;
-  border-bottom: $panel-border;
-  background: $color-bg;
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  z-index: 4;
-}
-
-.upload_file .dz_cross_btn {
-  color: $color-fg;
-  right: 0px;
-  position: absolute;
-  background: transparent;
-  border: none;
-}
-
-.file_manager .fileinfo #contents .fm_lock_icon {
-  color: $color-danger;
-  position: absolute;
-  top: 6px;
-  right: 0;
-  left: 19px;
-  font-size: 16px;
-}
-
-.file_manager .fileinfo #contents .fa-lock.tbl_lock_icon {
-  color: $color-danger;
-  position: relative;
-  left: -5px;
-  top: -5px;
-  font-size: 10px;
-}
-
-.file_manager button.ON {
-  background: $color-primary;
-  color: $color-primary-fg;
-}
-
-.fileinfo .is_file_replace {
-  width: 100%;
-  height: 100%;
-  background: $color-gray-lighter;
-}
-
-.file_selection_ctrl button.select_item {
-  display: inline;
-  background:  $color-bg;
-  padding: 9px 0px 9px 0px;
-  margin-left: 0px;
-  margin-right: -7px;
-  min-width: 30px;
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-
-.cap_select_file {
-  cursor: pointer;
-}
-
-.cap_select_file:hover {
-  color: $grid-hover-fg-color !important;
-  .fm_folder_list,
-  .fm_folder_grid,
-  .fm_file_grid,
-  .fm_file_list {
-    color: $grid-hover-fg-color !important;
-  }
-}
-
-.add-folder-icon {
-  position: relative;
-  top: -8px;
-  left: -6px;
-  font-size: 8px;
-  margin-right: -7px;
-}
-
-table.tablesorter {
-  th:focus,
-  tr:focus {
-    outline: $input-focus-border-color auto 5px !important;
-  }
-}
-
-#contents {
-  li:focus {
-    outline: $input-focus-border-color auto 5px !important;
-  }
-}
-
-/* Specific to IE11 where we want to highlight the focus on grid/row  */
-@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
-  table.tablesorter {
-    th:focus,
-    tr:focus {
-      border: 2px solid $input-focus-border-color !important;
-    }
-  }
-
-  #contents {
-    li:focus {
-      border: 2px solid $input-focus-border-color !important;
-    }
-  }
-}
diff --git a/web/pgadmin/settings/__init__.py b/web/pgadmin/settings/__init__.py
index 178c546a8..688d442a1 100644
--- a/web/pgadmin/settings/__init__.py
+++ b/web/pgadmin/settings/__init__.py
@@ -23,6 +23,7 @@ from pgadmin.utils.menu import MenuItem
 
 from pgadmin.model import db, Setting
 from pgadmin.utils.constants import MIMETYPE_APP_JS
+from .utils import get_dialog_type, get_file_type_setting
 
 MODULE_NAME = 'settings'
 
@@ -223,38 +224,20 @@ def get_browser_tree_state():
                     mimetype="application/json")
 
 
-def _get_dialog_type(file_type):
-    """
-    This function return dialog type
-    :param file_type:
-    :return: dialog type.
-    """
-    if 'pgerd' in file_type:
-        return 'erd_file_type'
-    elif 'backup' in file_type:
-        return 'backup_file_type'
-    elif 'csv' in file_type and 'txt' in file_type:
-        return 'import_export_file_type'
-    elif 'csv' in file_type and 'txt' not in file_type:
-        return 'storage_manager_file_type'
-    else:
-        return 'sqleditor_file_format'
-
-
 @blueprint.route("/save_file_format_setting/",
                  endpoint="save_file_format_setting",
                  methods=['POST'])
 @login_required
 def save_file_format_setting():
     """
-    This function save the selected file format.
+    This function save the selected file format.save_file_format_setting
     :return: save file format response
     """
     data = request.form if request.form else json.loads(
         request.data.decode('utf-8'))
-    file_type = _get_dialog_type(data['allowed_file_types'])
+    file_type = get_dialog_type(data['allowed_file_types'])
 
-    store_setting(file_type, data['selectedFormat'])
+    store_setting(file_type, data['last_selected_format'])
     return make_json_response(success=True,
                               info=data,
                               result=request.form)
@@ -276,11 +259,5 @@ def get_file_format_setting():
         except (ValueError, TypeError, KeyError):
             data[k] = v
 
-    file_type = _get_dialog_type(list(data.values()))
-
-    data = Setting.query.filter_by(
-        user_id=current_user.id, setting=file_type).first()
-    if data is None:
-        return make_json_response(success=True, info='*')
-    else:
-        return make_json_response(success=True, info=data.value)
+    return make_json_response(success=True,
+                              info=get_file_type_setting(list(data.values())))
diff --git a/web/pgadmin/settings/utils.py b/web/pgadmin/settings/utils.py
new file mode 100644
index 000000000..69d8e9792
--- /dev/null
+++ b/web/pgadmin/settings/utils.py
@@ -0,0 +1,36 @@
+from flask_login import current_user
+from pgadmin.model import Setting
+
+
+def get_dialog_type(file_type):
+    """
+    This function return dialog type
+    :param file_type:
+    :return: dialog type.
+    """
+    if 'pgerd' in file_type:
+        return 'erd_file_type'
+    elif 'backup' in file_type:
+        return 'backup_file_type'
+    elif 'csv' in file_type and 'txt' in file_type:
+        return 'import_export_file_type'
+    elif 'csv' in file_type and 'txt' not in file_type:
+        return 'storage_manager_file_type'
+    else:
+        return 'sqleditor_file_format'
+
+
+def get_file_type_setting(file_types):
+    """
+    This function return last file format setting based on file types
+    :param file_types:
+    :return: file format setting.
+    """
+    file_type = get_dialog_type(list(file_types))
+
+    data = Setting.query.filter_by(
+        user_id=current_user.id, setting=file_type).first()
+    if data is None:
+        return '*'
+    else:
+        return data.value
diff --git a/web/pgadmin/static/js/SchemaView/DataGridView.jsx b/web/pgadmin/static/js/SchemaView/DataGridView.jsx
index 914ac5dd3..9d06a5430 100644
--- a/web/pgadmin/static/js/SchemaView/DataGridView.jsx
+++ b/web/pgadmin/static/js/SchemaView/DataGridView.jsx
@@ -25,11 +25,11 @@ import _ from 'lodash';
 import gettext from 'sources/gettext';
 import { SCHEMA_STATE_ACTIONS, StateUtilsContext } from '.';
 import FormView, { getFieldMetaData } from './FormView';
-import { confirmDeleteRow } from '../helpers/legacyConnector';
 import CustomPropTypes from 'sources/custom_prop_types';
 import { evalFunc } from 'sources/utils';
 import { DepListenerContext } from './DepListener';
 import { useIsMounted } from '../custom_hooks';
+import Notify from '../helpers/Notifier';
 
 const useStyles = makeStyles((theme)=>({
   grid: {
@@ -303,15 +303,21 @@ export default function DataGridView({
             return (
               <PgIconButton data-test="delete-row" title={gettext('Delete row')} icon={<DeleteRoundedIcon fontSize="small" />}
                 onClick={()=>{
-                  confirmDeleteRow(()=>{
-                    /* Get the changes on dependent fields as well */
-                    dataDispatch({
-                      type: SCHEMA_STATE_ACTIONS.DELETE_ROW,
-                      path: accessPath,
-                      value: row.index,
-                    });
-
-                  }, ()=>{/*This is intentional (SonarQube)*/}, props.customDeleteTitle, props.customDeleteMsg);
+                  Notify.confirm(
+                    props.customDeleteTitle || gettext('Delete Row'),
+                    props.customDeleteMsg || gettext('Are you sure you wish to delete this row?'),
+                    function() {
+                      dataDispatch({
+                        type: SCHEMA_STATE_ACTIONS.DELETE_ROW,
+                        path: accessPath,
+                        value: row.index,
+                      });
+                      return true;
+                    },
+                    function() {
+                      return true;
+                    }
+                  );
                 }} className={classes.gridRowButton} disabled={!canDeleteRow} />
             );
           }
diff --git a/web/pgadmin/static/js/Theme/index.jsx b/web/pgadmin/static/js/Theme/index.jsx
index 1f6be3d4c..4b966f881 100644
--- a/web/pgadmin/static/js/Theme/index.jsx
+++ b/web/pgadmin/static/js/Theme/index.jsx
@@ -125,6 +125,9 @@ basicSettings = createMuiTheme(basicSettings, {
       },
       adornedEnd: {
         paddingRight: basicSettings.spacing(0.75),
+      },
+      marginDense: {
+        height: '28px',
       }
     },
     MuiAccordion: {
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 0f0a8ab4d..3368111cf 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -2835,106 +2835,6 @@ define([
     ].join('\n')),
   });
 
-  /*
-   * Input File Control: This control is used with Storage Manager Dialog,
-   * It allows user to perform following operations:
-   * - Select File
-   * - Select Folder
-   * - Create File
-   * - Opening Storage Manager Dialog itself.
-   */
-  Backform.FileControl = Backform.InputControl.extend({
-    defaults: {
-      type: 'text',
-      label: '',
-      min: undefined,
-      max: undefined,
-      maxlength: 255,
-      extraClasses: [],
-      dialog_title: '',
-      btn_primary: '',
-      helpMessage: null,
-      dialog_type: 'select_file',
-    },
-    initialize: function() {
-      Backform.InputControl.prototype.initialize.apply(this, arguments);
-    },
-    template: _.template([
-      '<label class="<%=Backform.controlLabelClassName%>" for="<%=cId%>"><%=label%></label>',
-      '<div class="<%=Backform.controlsClassName%>">',
-      '<div class="input-group">',
-      '<input type="<%=type%>" id="<%=cId%>" class="form-control <%=extraClasses.join(\' \')%>" name="<%=name%>" min="<%=min%>" max="<%=max%>"maxlength="<%=maxlength%>" value="<%-value%>" placeholder="<%-placeholder%>" <%=disabled ? "disabled" : ""%> <%=readonly ? "readonly aria-readonly=true" : ""%> <%=required ? "required" : ""%> />',
-      '<div class="input-group-append">',
-      '<button class="btn btn-primary-icon fa fa-ellipsis-h select_item" <%=disabled ? "disabled" : ""%> <%=readonly ? "disabled" : ""%> aria-hidden="true" aria-label="' + gettext('Select file') + '" title="' + gettext('Select file') + '"></button>',
-      '</div>',
-      '</div>',
-      '<% if (helpMessage && helpMessage.length) { %>',
-      '<span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
-      '<% } %>',
-      '</div>',
-    ].join('\n')),
-    events: function() {
-      // Inherit all default events of InputControl
-      return _.extend({}, Backform.InputControl.prototype.events, {
-        'click .select_item': 'onSelect',
-      });
-    },
-    onSelect: function() {
-      var dialog_type = this.field.get('dialog_type'),
-        supp_types = this.field.get('supp_types'),
-        btn_primary = this.field.get('btn_primary'),
-        dialog_title = this.field.get('dialog_title'),
-        params = {
-          supported_types: supp_types,
-          dialog_type: dialog_type,
-          dialog_title: dialog_title,
-          btn_primary: btn_primary,
-        };
-
-      pgAdmin.FileManager.init();
-      pgAdmin.FileManager.show_dialog(params);
-      // Listen click events of Storage Manager dialog buttons
-      this.listen_file_dlg_events();
-    },
-    storage_dlg_hander: function(value) {
-      var attrArr = this.field.get('name').split('.'),
-        name = attrArr.shift();
-
-      this.remove_file_dlg_event_listeners();
-
-      // Set selected value into the model
-      this.model.set(name, decodeURI(value));
-      this.$el.find('input[type=text]').focus();
-    },
-    storage_close_dlg_hander: function() {
-      this.remove_file_dlg_event_listeners();
-    },
-    listen_file_dlg_events: function() {
-      pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:' + this.field.get('dialog_type'), this.storage_dlg_hander, this);
-      pgAdmin.Browser.Events.on('pgadmin-storage:cancel_btn:' + this.field.get('dialog_type'), this.storage_close_dlg_hander, this);
-    },
-    remove_file_dlg_event_listeners: function() {
-      pgAdmin.Browser.Events.off('pgadmin-storage:finish_btn:' + this.field.get('dialog_type'), this.storage_dlg_hander, this);
-      pgAdmin.Browser.Events.off('pgadmin-storage:cancel_btn:' + this.field.get('dialog_type'), this.storage_close_dlg_hander, this);
-    },
-    clearInvalid: function() {
-      Backform.InputControl.prototype.clearInvalid.apply(this, arguments);
-      this.$el.removeClass('pgadmin-file-has-error');
-      return this;
-    },
-    updateInvalid: function() {
-      Backform.InputControl.prototype.updateInvalid.apply(this, arguments);
-      // Introduce a new class to fix the error icon placement on the control
-      this.$el.addClass('pgadmin-file-has-error');
-    },
-    disable_button: function() {
-      this.$el.find('button.select_item').attr('disabled', 'disabled');
-    },
-    enable_button: function() {
-      this.$el.find('button.select_item').removeAttr('disabled');
-    },
-  });
-
   Backform.DatetimepickerControl =
     Backform.InputControl.extend({
       defaults: {
diff --git a/web/pgadmin/static/js/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid.pgadmin.js
index b997a0c69..0eadfa606 100644
--- a/web/pgadmin/static/js/backgrid.pgadmin.js
+++ b/web/pgadmin/static/js/backgrid.pgadmin.js
@@ -12,10 +12,10 @@ import Notify from '../../static/js/helpers/Notifier';
 define([
   'sources/gettext', 'underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify',
   'moment', 'bignumber', 'codemirror', 'sources/utils', 'sources/keyboard_shortcuts', 'sources/select2/configure_show_on_scroll',
-  'sources/window', 'sources/url_for', 'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle',
+  'sources/window', 'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle',
 ], function(
   gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber, CodeMirror,
-  commonUtils, keyboardShortcuts, configure_show_on_scroll, pgWindow, url_for
+  commonUtils, keyboardShortcuts, configure_show_on_scroll, pgWindow
 ) {
   /*
    * Add mechanism in backgrid to render different types of cells in
@@ -2314,125 +2314,5 @@ define([
     },
   });
 
-  Backgrid.Extension.SelectFileCell = Backgrid.Cell.extend({
-    /** @property */
-    className: 'file-cell',
-    defaults: {
-      supported_types: ['*'],
-      dialog_type: 'select_file',
-      dialog_title: gettext('Select file'),
-      type: 'text',
-      value: '',
-      placeholder: gettext('Select file...'),
-      disabled: false,
-      browse_btn_label: gettext('Select file'),
-      check_btn_label: gettext('Validate file'),
-      browse_btn_visible: true,
-      validate_btn_visible: true,
-    },
-
-    initialize: function() {
-      Backgrid.Cell.prototype.initialize.apply(this, arguments);
-      this.data = _.extend(this.defaults, this.column.toJSON());
-    },
-    template: _.template([
-      '<div class="input-group">',
-      '<input type="<%=type%>" id="<%=cId%>" class="form-control" value="<%-value%>" placeholder="<%-placeholder%>" <%=disabled ? "disabled" : ""%> />',
-      '<% if (browse_btn_visible) { %>',
-      '<div class="input-group-append">',
-      '<button class="btn btn-primary-icon fa fa-ellipsis-h select_item" <%=disabled ? "disabled" : ""%>  aria-hidden="true" aria-label=<%=browse_btn_label%> title=<%=browse_btn_label%>></button>',
-      '</div>',
-      '<% } %>',
-      '<% if (validate_btn_visible) { %>',
-      '<div class="input-group-append">',
-      '<button class="btn btn-primary-icon fa fa-clipboard-check validate_item" <%=disabled ? "disabled" : ""%> <%=(value=="" || value==null) ? "disabled" : ""%>  aria-hidden="true" aria-label=<%=check_btn_label%> title=<%=check_btn_label%>></button>',
-      '</div>',
-      '<% } %>',
-      '</div>',
-    ].join('\n')),
-    events: {
-      'change input': 'onChange',
-      'click .select_item': 'onSelect',
-      'click .validate_item': 'onValidate',
-    },
-
-    render: function() {
-      this.$el.empty();
-      this.data = _.extend(this.data, {value: this.model.get(this.column.get('name'))});
-      // Adding unique id
-      this.data['cId'] = _.uniqueId('pgC_');
-      this.$el.append(this.template(this.data));
-
-      this.$input = this.$el.find('input');
-      this.delegateEvents();
-
-      return this;
-    },
-    onChange: function() {
-      var model = this.model,
-        column = this.column,
-        val = this.formatter.toRaw(this.$input.prop('value'), model);
-
-      model.set(column.get('name'), val);
-    },
-    onSelect: function() {
-      let self = this;
-
-      var params = {
-        supported_types: self.data.supported_types,
-        dialog_type: self.data.dialog_type,
-        dialog_title: self.data.dialog_title
-      };
-
-      pgAdmin.FileManager.init();
-      pgAdmin.FileManager.show_dialog(params);
-      // Listen click events of Storage Manager dialog buttons
-      this.listen_file_dlg_events();
-    },
-    storage_dlg_hander: function(value) {
-      var attrArr = this.column.get('name').split('.'),
-        name = attrArr.shift();
-
-      this.remove_file_dlg_event_listeners();
-
-      // Set selected value into the model
-      this.model.set(name, decodeURI(value));
-    },
-    storage_close_dlg_hander: function() {
-      this.remove_file_dlg_event_listeners();
-    },
-    listen_file_dlg_events: function() {
-      pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:' + this.data.dialog_type, this.storage_dlg_hander, this);
-      pgAdmin.Browser.Events.on('pgadmin-storage:cancel_btn:' + this.data.dialog_type, this.storage_close_dlg_hander, this);
-    },
-    remove_file_dlg_event_listeners: function() {
-      pgAdmin.Browser.Events.off('pgadmin-storage:finish_btn:' + this.data.dialog_type, this.storage_dlg_hander, this);
-      pgAdmin.Browser.Events.off('pgadmin-storage:cancel_btn:' + this.data.dialog_type, this.storage_close_dlg_hander, this);
-    },
-    onValidate: function() {
-      var model = this.model,
-        val = this.formatter.toRaw(this.$input.prop('value'), model);
-
-      if (_.isNull(val) || val.trim() === '') {
-        Notify.alert(gettext('Validate Path'), gettext('Path should not be empty.'));
-      }
-
-      $.ajax({
-        url: url_for('misc.validate_binary_path'),
-        method: 'POST',
-        contentType: 'application/json',
-        data: JSON.stringify({
-          'utility_path': val,
-        }),
-      })
-        .done(function(res) {
-          Notify.alert(gettext('Validate binary path'), gettext(res.data));
-        })
-        .fail(function(xhr, error) {
-          Notify.pgNotifier(error, xhr, gettext('Failed to validate binary path.'));
-        });
-    },
-  });
-
   return Backgrid;
 });
diff --git a/web/pgadmin/static/js/components/Buttons.jsx b/web/pgadmin/static/js/components/Buttons.jsx
index c15e313d5..c446926c5 100644
--- a/web/pgadmin/static/js/components/Buttons.jsx
+++ b/web/pgadmin/static/js/components/Buttons.jsx
@@ -199,7 +199,7 @@ PgIconButton.propTypes = {
 export const PgButtonGroup = forwardRef(({children, ...props}, ref)=>{
   /* Tooltip does not work for disabled items */
   return (
-    <ButtonGroup disableElevation innerRef={ref} {...props}>
+    <ButtonGroup innerRef={ref} {...props}>
       {children}
     </ButtonGroup>
   );
diff --git a/web/pgadmin/static/js/components/FormComponents.jsx b/web/pgadmin/static/js/components/FormComponents.jsx
index cb78020b1..2dcd79d69 100644
--- a/web/pgadmin/static/js/components/FormComponents.jsx
+++ b/web/pgadmin/static/js/components/FormComponents.jsx
@@ -35,13 +35,13 @@ import * as DateFns from 'date-fns';
 
 import CodeMirror from './CodeMirror';
 import gettext from 'sources/gettext';
-import { showFileDialog } from '../helpers/legacyConnector';
 import _ from 'lodash';
 import { DefaultButton, PrimaryButton, PgIconButton } from './Buttons';
 import CustomPropTypes from '../custom_prop_types';
 import KeyboardShortcuts from './KeyboardShortcuts';
 import QueryThresholds from './QueryThresholds';
 import SelectThemes from './SelectThemes';
+import { showFileManager } from '../helpers/showFileManager';
 
 
 const useStyles = makeStyles((theme) => ({
@@ -326,11 +326,10 @@ FormInputDateTimePicker.propTypes = {
 
 /* Use forwardRef to pass ref prop to OutlinedInput */
 export const InputText = forwardRef(({
-  cid, helpid, readonly, disabled, value, onChange, controlProps, type, ...props }, ref) => {
+  cid, helpid, readonly, disabled, value, onChange, controlProps, type, size, ...props }, ref) => {
 
   const maxlength = typeof(controlProps?.maxLength) != 'undefined' ? controlProps.maxLength : 255;
 
-  const classes = useStyles();
   const patterns = {
     'numeric': '^-?[0-9]\\d*\\.?\\d*$',
     'int': '^-?[0-9]\\d*$',
@@ -356,12 +355,17 @@ export const InputText = forwardRef(({
     finalValue = controlProps.formatter.fromRaw(finalValue);
   }
 
+  const filteredProps = _.pickBy(props, (_v, key)=>(
+    /* When used in ButtonGroup, following props should be skipped */
+    !['color', 'disableElevation', 'disableFocusRipple', 'disableRipple'].includes(key)
+  ));
+
   return (
     <OutlinedInput
       ref={ref}
       color="primary"
       fullWidth
-      className={classes.formInput}
+      margin={size == 'small' ? 'dense' : 'none'}
       inputProps={{
         id: cid,
         maxLength: controlProps?.multiline ? null : maxlength,
@@ -378,7 +382,7 @@ export const InputText = forwardRef(({
         ...(controlProps?.onKeyDown && { onKeyDown: controlProps.onKeyDown })
       }
       {...controlProps}
-      {...props}
+      {...filteredProps}
       {...(['numeric', 'int'].indexOf(type) > -1 ? { type: 'tel' } : { type: type })}
     />
   );
@@ -394,6 +398,7 @@ InputText.propTypes = {
   onChange: PropTypes.func,
   controlProps: PropTypes.object,
   type: PropTypes.string,
+  size: PropTypes.string,
 };
 
 export function FormInputText({ hasError, required, label, className, helpMessage, testcid, ...props }) {
@@ -412,7 +417,6 @@ FormInputText.propTypes = {
   testcid: PropTypes.string,
 };
 
-/* Using the existing file dialog functions using showFileDialog */
 export function InputFileSelect({ controlProps, onChange, disabled, readonly, isvalidate = false, hideBrowseButton=false,validate, ...props }) {
   const inpRef = useRef();
   let textControlProps = {};
@@ -420,15 +424,24 @@ export function InputFileSelect({ controlProps, onChange, disabled, readonly, is
     const {placeholder} = controlProps;
     textControlProps = {placeholder};
   }
-  const onFileSelect = (value) => {
-    onChange && onChange(decodeURI(value));
-    inpRef.current.focus();
+  const showFileDialog = ()=>{
+    let params = {
+      supported_types: controlProps.supportedTypes || [],
+      dialog_type: controlProps.dialogType || 'select_file',
+      dialog_title: controlProps.dialogTitle || '',
+      btn_primary: controlProps.btnPrimary || '',
+    };
+    showFileManager(params, (fileName)=>{
+      onChange && onChange(decodeURI(fileName));
+      inpRef.current.focus();
+    });
   };
+
   return (
     <InputText ref={inpRef} disabled={disabled} readonly={readonly} onChange={onChange} controlProps={textControlProps} {...props} endAdornment={
       <>
         {!hideBrowseButton &&
-        <IconButton onClick={() => showFileDialog(controlProps, onFileSelect)}
+        <IconButton onClick={showFileDialog}
           disabled={disabled || readonly} aria-label={gettext('Select a file')}><FolderOpenRoundedIcon /></IconButton>
         }
         {isvalidate &&
@@ -1184,6 +1197,9 @@ const useStylesFormFooter = makeStyles((theme) => ({
   message: {
     marginLeft: theme.spacing(0.5),
   },
+  messageCenter: {
+    margin: 'auto',
+  },
   closeButton: {
     marginLeft: 'auto',
   },
@@ -1272,13 +1288,13 @@ FormInputSelectThemes.propTypes = {
 };
 
 
-export function NotifierMessage({ type = MESSAGE_TYPE.SUCCESS, message, closable = true, onClose = () => {/*This is intentional (SonarQube)*/ } }) {
+export function NotifierMessage({ type = MESSAGE_TYPE.SUCCESS, message, closable = true, showIcon=true, textCenter=false, onClose = () => {/*This is intentional (SonarQube)*/ } }) {
   const classes = useStylesFormFooter();
 
   return (
     <Box className={clsx(classes.container, classes[`container${type}`])}>
-      <FormIcon type={type} className={classes[`icon${type}`]} />
-      <Box className={classes.message}>{HTMLReactParse(message || '')}</Box>
+      {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}>
         <FormIcon close={true} />
       </IconButton>}
@@ -1290,6 +1306,8 @@ NotifierMessage.propTypes = {
   type: PropTypes.oneOf(Object.values(MESSAGE_TYPE)).isRequired,
   message: PropTypes.string,
   closable: PropTypes.bool,
+  showIcon: PropTypes.bool,
+  textCenter: PropTypes.bool,
   onClose: PropTypes.func,
 };
 
diff --git a/web/pgadmin/static/js/components/PgReactDataGrid.jsx b/web/pgadmin/static/js/components/PgReactDataGrid.jsx
new file mode 100644
index 000000000..210d8c980
--- /dev/null
+++ b/web/pgadmin/static/js/components/PgReactDataGrid.jsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import ReactDataGrid from 'react-data-grid';
+import { makeStyles } from '@material-ui/core';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import CustomPropTypes from '../custom_prop_types';
+
+const useStyles = makeStyles((theme)=>({
+  root: {
+    height: '100%',
+    color: theme.palette.text.primary,
+    backgroundColor: theme.otherVars.qtDatagridBg,
+    fontSize: '12px',
+    border: 'none',
+    '--rdg-selection-color': theme.palette.primary.main,
+    '& .rdg-cell': {
+      ...theme.mixins.panelBorder.right,
+      ...theme.mixins.panelBorder.bottom,
+      fontWeight: 'abc',
+      '&[aria-colindex="1"]': {
+        padding: 0,
+      },
+      '&[aria-selected=true]:not([role="columnheader"])': {
+        outlineWidth: '0px',
+        outlineOffset: '0px',
+      }
+    },
+    '& .rdg-header-row .rdg-cell': {
+      padding: 0,
+    },
+    '& .rdg-header-row': {
+      backgroundColor: theme.palette.background.default,
+      fontWeight: 'normal',
+    },
+    '& .rdg-row': {
+      backgroundColor: theme.palette.background.default,
+      '&[aria-selected=true]': {
+        backgroundColor: theme.palette.primary.light,
+        color: theme.otherVars.qtDatagridSelectFg,
+      },
+    }
+  },
+  cellSelection: {
+    '& .rdg-cell': {
+      '&[aria-selected=true]:not([role="columnheader"])': {
+        outlineWidth: '1px',
+        outlineOffset: '-1px',
+        backgroundColor: theme.palette.primary.light,
+        color: theme.otherVars.qtDatagridSelectFg,
+      }
+    },
+  },
+  hasSelectColumn: {
+    '& .rdg-cell': {
+      '&[aria-selected=true][aria-colindex="1"]': {
+        outlineWidth: '2px',
+        outlineOffset: '-2px',
+        backgroundColor: theme.otherVars.qtDatagridBg,
+        color: theme.palette.text.primary,
+      }
+    },
+    '& .rdg-row[aria-selected=true] .rdg-cell:nth-child(1)': {
+      backgroundColor: theme.palette.primary.main,
+      color: theme.palette.primary.contrastText,
+    }
+  }
+}));
+
+
+export default function PgReactDataGrid({gridRef, className, hasSelectColumn=true, ...props}) {
+  const classes = useStyles();
+  let finalClassName = [classes.root];
+  hasSelectColumn && finalClassName.push(classes.hasSelectColumn);
+  props.enableCellSelect && finalClassName.push(classes.cellSelection);
+  finalClassName.push(className);
+  return <ReactDataGrid
+    ref={gridRef}
+    className={clsx(finalClassName)}
+    {...props}
+  />;
+}
+
+PgReactDataGrid.propTypes = {
+  gridRef: CustomPropTypes.ref,
+  className: CustomPropTypes.className,
+  hasSelectColumn: PropTypes.bool,
+  enableCellSelect: PropTypes.bool,
+};
diff --git a/web/pgadmin/static/js/helpers/ModalProvider.jsx b/web/pgadmin/static/js/helpers/ModalProvider.jsx
index 80523fe04..510cb96dc 100644
--- a/web/pgadmin/static/js/helpers/ModalProvider.jsx
+++ b/web/pgadmin/static/js/helpers/ModalProvider.jsx
@@ -22,7 +22,7 @@ import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
 import { Rnd } from 'react-rnd';
 import { ExpandDialogIcon, MinimizeDialogIcon } from '../components/ExternalIcon';
 
-const ModalContext = React.createContext({});
+export const ModalContext = React.createContext({});
 const MIN_HEIGHT = 190;
 const MIN_WIDTH = 500;
 
diff --git a/web/pgadmin/static/js/helpers/legacyConnector.js b/web/pgadmin/static/js/helpers/legacyConnector.js
deleted file mode 100644
index adc7c27d6..000000000
--- a/web/pgadmin/static/js/helpers/legacyConnector.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-/* This file will have wrappers and connectors used by React components to
- * re-use any existing non-react components.
- * These functions may not be needed once all are migrated
- */
-
-import gettext from 'sources/gettext';
-import pgAdmin from 'sources/pgadmin';
-import Notify from './Notifier';
-
-export function confirmDeleteRow(onOK, onCancel, title, message) {
-  Notify.confirm(
-    title || gettext('Delete Row'),
-    message || gettext('Are you sure you wish to delete this row?'),
-    function() {
-      onOK();
-      return true;
-    },
-    function() {
-      onCancel();
-      return true;
-    }
-  );
-}
-
-/* Used by file select component to re-use existing logic */
-export function showFileDialog(dialogParams, onFileSelect) {
-  let params = {
-    supported_types: dialogParams.supportedTypes || [],
-    dialog_type: dialogParams.dialogType || 'select_file',
-    dialog_title: dialogParams.dialogTitle || '',
-    btn_primary: dialogParams.btnPrimary || '',
-  };
-  pgAdmin.FileManager.init();
-  pgAdmin.FileManager.show_dialog(params);
-
-  const onFileSelectClose = (value)=>{
-    removeListeners();
-    onFileSelect(value);
-  };
-  const onDialogClose = ()=>removeListeners();
-  pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:' + params.dialog_type, onFileSelectClose);
-  pgAdmin.Browser.Events.on('pgadmin-storage:cancel_btn:' + params.dialog_type, onDialogClose);
-
-  const removeListeners = ()=>{
-    pgAdmin.Browser.Events.off('pgadmin-storage:finish_btn:' + params.dialog_type, onFileSelectClose);
-    pgAdmin.Browser.Events.off('pgadmin-storage:cancel_btn:' + params.dialog_type, onDialogClose);
-  };
-}
-
-export function onPgadminEvent(eventName, handler) {
-  pgAdmin.Browser.Events.on(eventName, handler);
-}
-
-export function offPgadminEvent(eventName, handler) {
-  pgAdmin.Browser.Events.off(eventName, handler);
-}
diff --git a/web/pgadmin/static/js/helpers/showFileManager.js b/web/pgadmin/static/js/helpers/showFileManager.js
new file mode 100644
index 000000000..fc658920c
--- /dev/null
+++ b/web/pgadmin/static/js/helpers/showFileManager.js
@@ -0,0 +1,6 @@
+import pgAdmin from 'sources/pgadmin';
+import 'pgadmin.tools.file_manager';
+
+export function showFileManager(...args) {
+  pgAdmin.Tools.FileManager.show(...args);
+}
diff --git a/web/pgadmin/static/js/tree/tree.js b/web/pgadmin/static/js/tree/tree.js
index 839016adf..467822b9f 100644
--- a/web/pgadmin/static/js/tree/tree.js
+++ b/web/pgadmin/static/js/tree/tree.js
@@ -14,8 +14,6 @@ import pgAdmin from 'sources/pgadmin';
 import { FileType } from 'react-aspen';
 import { TreeNode } from './tree_nodes';
 
-import { isValidData } from 'sources/utils';
-
 function manageTreeEvents(event, eventName, item) {
   let d = item ? item._metadata.data : [];
   let node_metadata = item ? item._metadata : {};
@@ -594,6 +592,6 @@ export function findInTree(rootNode, path) {
   })(rootNode);
 }
 
-let isValidTreeNodeData = isValidData;
+let isValidTreeNodeData = (data) => (!_.isEmpty(data));
 
 export { isValidTreeNodeData };
diff --git a/web/pgadmin/static/js/utils.js b/web/pgadmin/static/js/utils.js
index 0602921d4..5f5134834 100644
--- a/web/pgadmin/static/js/utils.js
+++ b/web/pgadmin/static/js/utils.js
@@ -7,7 +7,7 @@
 //
 //////////////////////////////////////////////////////////////////////////
 
-import _ from 'underscore';
+import _ from 'lodash';
 import $ from 'jquery';
 import gettext from 'sources/gettext';
 import 'wcdocker';
@@ -115,14 +115,6 @@ export function findAndSetFocus(container) {
   }, 200);
 }
 
-let isValidData = (data) => (!_.isUndefined(data) && !_.isNull(data));
-let isFunction = (fn) => (_.isFunction(fn));
-let isString = (str) => (_.isString(str));
-
-export {
-  isValidData, isFunction, isString,
-};
-
 export function getEpoch(inp_date) {
   let date_obj = inp_date ? inp_date : new Date();
   return parseInt(date_obj.getTime()/1000);
@@ -456,6 +448,10 @@ export function getBrowser() {
     tem=/\brv[ :]+(\d+)/g.exec(ua) || [];
     return {name:'IE', version:(tem[1]||'')};
   }
+  if(ua.startsWith('Nwjs')) {
+    let nwjs = ua.split('-')[0]?.split(':');
+    return {name:nwjs[0], version: nwjs[1]};
+  }
 
   if(M[1]==='Chrome') {
     tem=ua.match(/\bOPR|Edge\/(\d+)/);
@@ -480,3 +476,21 @@ export function checkTrojanSource(content, isPasteEvent) {
     Notify.alert(gettext('Trojan Source Warning'), msg);
   }
 }
+
+export function downloadBlob(blob, fileName) {
+  let urlCreator = window.URL || window.webkitURL,
+    downloadUrl = urlCreator.createObjectURL(blob),
+    link = document.createElement('a');
+
+  document.body.appendChild(link);
+
+  if (getBrowser() === 'IE' && window.navigator.msSaveBlob) {
+  // IE10+ : (has Blob, but not a[download] or URL)
+    window.navigator.msSaveBlob(blob, fileName);
+  } else {
+    link.setAttribute('href', downloadUrl);
+    link.setAttribute('download', fileName);
+    link.click();
+  }
+  document.body.removeChild(link);
+}
diff --git a/web/pgadmin/tools/__init__.py b/web/pgadmin/tools/__init__.py
index 711699a89..9ab20d574 100644
--- a/web/pgadmin/tools/__init__.py
+++ b/web/pgadmin/tools/__init__.py
@@ -64,9 +64,6 @@ class ToolsModule(PgAdminModule):
         from .sqleditor import blueprint as module
         app.register_blueprint(module)
 
-        from .storage_manager import blueprint as module
-        app.register_blueprint(module)
-
         from .user_management import blueprint as module
         app.register_blueprint(module)
 
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/index.js b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
index 8563ac562..1c7a10d12 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/index.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/index.js
@@ -17,6 +17,9 @@ import Alertify from 'pgadmin.alertifyjs';
 import pgWindow from 'sources/window';
 import pgAdmin from 'sources/pgadmin';
 
+import ModalProvider from '../../../../../static/js/helpers/ModalProvider';
+import Theme from '../../../../../static/js/Theme';
+
 export default class ERDTool {
   constructor(container, params) {
     this.container = document.querySelector(container);
@@ -37,13 +40,17 @@ export default class ERDTool {
     });
 
     ReactDOM.render(
-      <BodyWidget
-        params={this.params}
-        getDialog={getDialog}
-        pgWindow={pgWindow}
-        pgAdmin={pgAdmin}
-        panel={panel}
-        alertify={Alertify} />,
+      <Theme>
+        <ModalProvider>
+          <BodyWidget
+            params={this.params}
+            getDialog={getDialog}
+            pgWindow={pgWindow}
+            pgAdmin={pgAdmin}
+            panel={panel}
+            alertify={Alertify} />
+        </ModalProvider>
+      </Theme>,
       this.container
     );
   }
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
index 4132ae1e9..6427292d3 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
+++ b/web/pgadmin/tools/erd/static/js/erd_tool/ui_components/BodyWidget.jsx
@@ -27,6 +27,7 @@ import 'wcdocker';
 import Theme from '../../../../../../static/js/Theme';
 import TableSchema from '../../../../../../browser/server_groups/servers/databases/schemas/tables/static/js/table.ui';
 import Notify from '../../../../../../static/js/helpers/Notifier';
+import { ModalContext } from '../../../../../../static/js/helpers/ModalProvider';
 
 /* Custom react-diagram action for keyboard events */
 export class KeyboardShortcutAction extends Action {
@@ -61,6 +62,7 @@ export class KeyboardShortcutAction extends Action {
 
 /* The main body container for the ERD */
 export default class BodyWidget extends React.Component {
+  static contextType = ModalContext;
   constructor() {
     super();
     this.state = {
@@ -214,8 +216,6 @@ export default class BodyWidget extends React.Component {
       backgroundPosition: '0px 0px',
     });
 
-    this.props.pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:select_file', this.openFile, this);
-    this.props.pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:create_file', this.saveFile, this);
     this.props.pgAdmin.Browser.onPreferencesChange('erd', () => {
       this.setState({
         preferences: this.props.pgWindow.pgAdmin.Browser.get_preferences_for_module('erd'),
@@ -468,11 +468,10 @@ export default class BodyWidget extends React.Component {
 
   onLoadDiagram() {
     var params = {
-      'supported_types': ['pgerd'], // file types allowed
+      'supported_types': ['*','pgerd'], // file types allowed
       'dialog_type': 'select_file', // open select file dialog
     };
-    this.props.pgAdmin.FileManager.init();
-    this.props.pgAdmin.FileManager.show_dialog(params);
+    this.props.pgAdmin.Tools.FileManager.show(params, this.openFile.bind(this), null, this.context);
   }
 
   openFile(fileName) {
@@ -501,13 +500,12 @@ export default class BodyWidget extends React.Component {
       this.saveFile(this.state.current_file);
     } else {
       var params = {
-        'supported_types': ['pgerd'],
+        'supported_types': ['*','pgerd'],
         'dialog_type': 'create_file',
         'dialog_title': 'Save File',
         'btn_primary': 'Save',
       };
-      this.props.pgAdmin.FileManager.init();
-      this.props.pgAdmin.FileManager.show_dialog(params);
+      this.props.pgAdmin.Tools.FileManager.show(params, this.saveFile.bind(this), null, this.context);
     }
   }
 
diff --git a/web/pgadmin/tools/erd/static/js/erd_tool_hook.js b/web/pgadmin/tools/erd/static/js/erd_tool_hook.js
index 9fa0a2e3a..dafc69afd 100644
--- a/web/pgadmin/tools/erd/static/js/erd_tool_hook.js
+++ b/web/pgadmin/tools/erd/static/js/erd_tool_hook.js
@@ -10,7 +10,7 @@
 define([
   'sources/pgadmin', 'pgadmin.tools.erd/erd_tool', 'pgadmin.browser',
   'pgadmin.browser.server.privilege', 'pgadmin.node.database', 'pgadmin.node.primary_key',
-  'pgadmin.node.foreign_key', 'pgadmin.browser.datamodel', 'pgadmin.file_manager',
+  'pgadmin.node.foreign_key', 'pgadmin.browser.datamodel', 'pgadmin.tools.file_manager',
 ], function(
   pgAdmin, ERDToolModule
 ) {
diff --git a/web/pgadmin/tools/import_export_servers/static/js/import_export_servers.js b/web/pgadmin/tools/import_export_servers/static/js/import_export_servers.js
index d2953a3d2..b436b79cf 100644
--- a/web/pgadmin/tools/import_export_servers/static/js/import_export_servers.js
+++ b/web/pgadmin/tools/import_export_servers/static/js/import_export_servers.js
@@ -9,7 +9,6 @@
 
 import React from 'react';
 import ReactDOM from 'react-dom';
-import 'pgadmin.file_manager';
 import gettext from 'sources/gettext';
 import Alertify from 'pgadmin.alertifyjs';
 import Theme from 'sources/Theme';
diff --git a/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js b/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js
index fcf606254..33587d7e5 100644
--- a/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js
+++ b/web/pgadmin/tools/sqleditor/static/js/SQLEditorModule.js
@@ -20,8 +20,8 @@ var wcDocker = window.wcDocker;
 import pgWindow from 'sources/window';
 import pgAdmin from 'sources/pgadmin';
 import pgBrowser from 'pgadmin.browser';
-import 'pgadmin.file_manager';
 import 'pgadmin.tools.user_management';
+import 'pgadmin.tools.file_manager';
 import gettext from 'sources/gettext';
 import React from 'react';
 import ReactDOM from 'react-dom';
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
index 71b5bb16c..86966c73b 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
@@ -332,15 +332,6 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
         }
       }
     });
-
-    pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:select_file', (fileName)=>{
-      eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE, fileName);
-    }, pgAdmin);
-
-    pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:create_file', (fileName)=>{
-      eventBus.current.fireEvent(QUERY_TOOL_EVENTS.SAVE_FILE, fileName);
-    }, pgAdmin);
-
     window.addEventListener('beforeunload', onBeforeUnload);
   }, []);
 
@@ -428,8 +419,9 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
           'supported_types': ['*', 'sql'], // file types allowed
           'dialog_type': 'select_file', // open select file dialog
         };
-        pgAdmin.FileManager.init();
-        pgAdmin.FileManager.show_dialog(fileParams);
+        pgAdmin.Tools.FileManager.show(fileParams, (fileName)=>{
+          eventBus.current.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE, fileName);
+        }, null, modal);
       }],
       [QUERY_TOOL_EVENTS.TRIGGER_SAVE_FILE, (isSaveAs=false)=>{
         if(!isSaveAs && qtState.current_file) {
@@ -441,8 +433,9 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
             'dialog_title': 'Save File',
             'btn_primary': 'Save',
           };
-          pgAdmin.FileManager.init();
-          pgAdmin.FileManager.show_dialog(fileParams);
+          pgAdmin.Tools.FileManager.show(fileParams, (fileName)=>{
+            eventBus.current.fireEvent(QUERY_TOOL_EVENTS.SAVE_FILE, fileName);
+          }, null, modal);
         }
       }],
       [QUERY_TOOL_EVENTS.LOAD_FILE_DONE, fileDone],
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
index 5e51c6b4b..23c42a711 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
@@ -9,7 +9,7 @@
 import { Box, makeStyles } from '@material-ui/core';
 import _ from 'lodash';
 import React, {useState, useEffect, useContext, useRef, useLayoutEffect} from 'react';
-import ReactDataGrid, {Row, useRowSelection} from 'react-data-grid';
+import {Row, useRowSelection} from 'react-data-grid';
 import LockIcon from '@material-ui/icons/Lock';
 import EditIcon from '@material-ui/icons/Edit';
 import { QUERY_TOOL_EVENTS } from '../QueryToolConstants';
@@ -21,51 +21,12 @@ import MapIcon from '@material-ui/icons/Map';
 import { QueryToolEventsContext } from '../QueryToolComponent';
 import PropTypes from 'prop-types';
 import gettext from 'sources/gettext';
+import PgReactDataGrid from '../../../../../../static/js/components/PgReactDataGrid';
 
 export const ROWNUM_KEY = '$_pgadmin_rownum_key_$';
 export const GRID_ROW_SELECT_KEY = '$_pgadmin_gridrowselect_key_$';
 
 const useStyles = makeStyles((theme)=>({
-  root: {
-    height: '100%',
-    color: theme.palette.text.primary,
-    backgroundColor: theme.otherVars.qtDatagridBg,
-    fontSize: '12px',
-    border: 'none',
-    '--rdg-selection-color': theme.palette.primary.main,
-    '& .rdg-cell': {
-      ...theme.mixins.panelBorder.right,
-      ...theme.mixins.panelBorder.bottom,
-      fontWeight: 'abc',
-      '&[aria-colindex="1"]': {
-        padding: 0,
-      },
-      '&[aria-selected=true]:not([role="columnheader"]):not([aria-colindex="1"])': {
-        outlineWidth: '1px',
-        outlineOffset: '-1px',
-        backgroundColor: theme.palette.primary.light,
-        color: theme.otherVars.qtDatagridSelectFg,
-      }
-    },
-    '& .rdg-header-row .rdg-cell': {
-      padding: 0,
-    },
-    '& .rdg-header-row': {
-      backgroundColor: theme.palette.background.default,
-      fontWeight: 'normal',
-    },
-    '& .rdg-row': {
-      backgroundColor: theme.palette.background.default,
-      '&[aria-selected=true]': {
-        backgroundColor: theme.palette.primary.light,
-        color: theme.otherVars.qtDatagridSelectFg,
-        '& .rdg-cell:nth-child(1)': {
-          backgroundColor: theme.palette.primary.main,
-          color: theme.palette.primary.contrastText,
-        }
-      },
-    }
-  },
   columnHeader: {
     padding: '3px 6px',
     height: '100%',
@@ -408,11 +369,10 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha
 
   return (
     <DataGridExtrasContext.Provider value={{onSelectedCellChange, handleCopy}}>
-      <ReactDataGrid
+      <PgReactDataGrid
         id="datagrid"
         columns={readyColumns}
         rows={rows}
-        className={classes.root}
         headerRowHeight={40}
         rowHeight={25}
         mincolumnWidthBy={50}
diff --git a/web/pgadmin/tools/storage_manager/__init__.py b/web/pgadmin/tools/storage_manager/__init__.py
deleted file mode 100644
index 7850f6f95..000000000
--- a/web/pgadmin/tools/storage_manager/__init__.py
+++ /dev/null
@@ -1,51 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2022, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-"""A blueprint module implementing the storage manager functionality"""
-
-from flask import url_for, Response, render_template
-from flask_babel import gettext as _
-from flask_security import login_required
-
-from pgadmin.utils import PgAdminModule
-from pgadmin.utils.ajax import bad_request
-from pgadmin.utils.constants import MIMETYPE_APP_JS
-
-MODULE_NAME = 'storage_manager'
-
-
-class StorageManagerModule(PgAdminModule):
-    """
-    class StorageManagerModule(PgAdminModule)
-
-        A module class for manipulating file operation which is derived from
-        PgAdminModule.
-    """
-
-    LABEL = _('Storage Manager')
-
-
-blueprint = StorageManagerModule(MODULE_NAME, __name__)
-
-
-@blueprint.route("/")
-@login_required
-def index():
-    return bad_request(errormsg=_("This URL cannot be called directly."))
-
-
-@blueprint.route("/js/storage_manager.js")
-@login_required
-def script():
-    """render the import/export javascript file"""
-    return Response(
-        response=render_template("storage_manager/js/storage_manager.js", _=_),
-        status=200,
-        mimetype=MIMETYPE_APP_JS
-    )
diff --git a/web/pgadmin/tools/storage_manager/static/js/storage_manager.js b/web/pgadmin/tools/storage_manager/static/js/storage_manager.js
deleted file mode 100644
index cba26d288..000000000
--- a/web/pgadmin/tools/storage_manager/static/js/storage_manager.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2022, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-import { set_last_traversed_dir, getTransId } from '../../../../misc/file_manager/static/js/helpers';
-
-define([
-  'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'pgadmin.alertifyjs',
-  'sources/pgadmin', 'pgadmin.browser', 'sources/csrf', 'pgadmin.file_manager',
-], function (
-  gettext, url_for, $, _, alertify, pgAdmin, pgBrowser, csrfToken
-) {
-
-  pgAdmin = pgAdmin || window.pgAdmin || {};
-  var isServerMode = (function() { return pgAdmin.server_mode == 'True'; })();
-
-  var pgTools = pgAdmin.Tools = pgAdmin.Tools || {};
-
-  if(!isServerMode) {
-    return;
-  }
-
-  // Return back, this has been called more than once
-  if (pgAdmin.Tools.storage_manager)
-    return pgAdmin.Tools.storage_manager;
-
-  pgTools.storage_manager = {
-    init: function () {
-      // We do not want to initialize the module multiple times.
-      if (this.initialized)
-        return;
-
-      this.initialized = true;
-      csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
-
-      var storage_manager = this.callback_storage_manager.bind(this);
-
-      pgBrowser.Events.on(
-        'pgadmin:tools:storage_manager', storage_manager
-      );
-
-      // Define the nodes on which the menus to be appear
-      var menus = [{
-        name: 'storage_manager',
-        module: this,
-        applies: ['tools'],
-        callback: 'callback_storage_manager',
-        priority: 11,
-        label: gettext('Storage Manager...'),
-        enable: true,
-      }];
-
-      pgBrowser.add_menus(menus);
-    },
-
-    /*
-      Open the dialog for the storage functionality
-    */
-    callback_storage_manager: function (path) {
-
-      var params = {
-        supported_types: ['sql', 'csv', 'json', '*'],
-        dialog_type: 'storage_dialog',
-        dialog_title: 'Storage Manager',
-        btn_primary: undefined,
-      };
-
-      if (!_.isUndefined(path) && !_.isNull(path) && !_.isEmpty(path)) {
-
-        var transId = getTransId(JSON.stringify(params));
-        var t_res;
-        if (transId.readyState == 4) {
-          t_res = JSON.parse(transId.responseText);
-        }
-        var trans_id = _.isUndefined(t_res) ? 0 : t_res.data.fileTransId;
-
-        set_last_traversed_dir({'path': path}, trans_id);
-        pgAdmin.FileManager.init();
-        pgAdmin.FileManager.show_dialog(params);
-      }
-      else {
-        pgAdmin.FileManager.init();
-        pgAdmin.FileManager.show_dialog(params);
-      }
-    },
-  };
-
-  return pgAdmin.Tools.storage_manager;
-});
diff --git a/web/regression/javascript/SchemaView/SchemaView.spec.js b/web/regression/javascript/SchemaView/SchemaView.spec.js
index 36757abba..aea2c1d40 100644
--- a/web/regression/javascript/SchemaView/SchemaView.spec.js
+++ b/web/regression/javascript/SchemaView/SchemaView.spec.js
@@ -15,7 +15,6 @@ import {TestSchema, TestSchemaAllTypes} from './TestSchema.ui';
 import pgAdmin from 'sources/pgadmin';
 import {messages} from '../fake_messages';
 import SchemaView from '../../../pgadmin/static/js/SchemaView';
-import * as legacyConnector from 'sources/helpers/legacyConnector';
 import Notify from '../../../pgadmin/static/js/helpers/Notifier';
 import Theme from '../../../pgadmin/static/js/Theme';
 
@@ -191,18 +190,17 @@ describe('SchemaView', ()=>{
           simulateValidData();
 
           /* Press OK */
-          let confirmSpy = spyOn(legacyConnector, 'confirmDeleteRow').and.callFake((yesFn)=>{
-            yesFn();
-          });
+          let confirmSpy = spyOn(Notify, 'confirm').and.callThrough();
           ctrl.find('DataGridView').find('PgIconButton[data-test="delete-row"]').at(0).find('button').simulate('click');
-          expect(confirmSpy.calls.argsFor(0)[2]).toBe('Custom delete title');
-          expect(confirmSpy.calls.argsFor(0)[3]).toBe('Custom delete message');
+          confirmSpy.calls.argsFor(0)[2]();
 
+          expect(confirmSpy.calls.argsFor(0)[0]).toBe('Custom delete title');
+          expect(confirmSpy.calls.argsFor(0)[1]).toBe('Custom delete message');
           /* Press Cancel */
-          spyOn(legacyConnector, 'confirmDeleteRow').and.callFake((yesFn, cancelFn)=>{
-            cancelFn();
-          });
+          confirmSpy.calls.reset();
           ctrl.find('DataGridView').find('PgIconButton[data-test="delete-row"]').at(0).find('button').simulate('click');
+          confirmSpy.calls.argsFor(0)[3]();
+
           setTimeout(()=>{
             ctrlUpdate(done);
           }, 0);
@@ -297,7 +295,7 @@ describe('SchemaView', ()=>{
       }, 0);
     });
 
-    let onRestAction = (done, data)=> {
+    let onResetAction = (done, data)=> {
       ctrl.update();
       expect(ctrl.find('DefaultButton[data-test="Reset"]').prop('disabled')).toBeTrue();
       expect(ctrl.find('PrimaryButton[data-test="Save"]').prop('disabled')).toBeTrue();
@@ -316,7 +314,7 @@ describe('SchemaView', ()=>{
           /* Press OK */
           confirmSpy.calls.argsFor(0)[2]();
           setTimeout(()=>{
-            onRestAction(done, { id: undefined, field1: null, field2: null, fieldcoll: null });
+            onResetAction(done, { id: undefined, field1: null, field2: null, fieldcoll: null });
           }, 0);
         }, 0);
       });
@@ -390,7 +388,9 @@ describe('SchemaView', ()=>{
         ctrl.find('MappedCellControl[id="field5"]').at(2).find('input').simulate('change', {target: {value: 'rval53'}});
 
         /* Remove the 1st row */
+        let confirmSpy = spyOn(Notify, 'confirm').and.callThrough();
         ctrl.find('DataTableRow').find('PgIconButton[data-test="delete-row"]').at(0).find('button').simulate('click');
+        confirmSpy.calls.argsFor(0)[2]();
 
         /* Edit the 2nd row which is first now*/
         ctrl.find('MappedCellControl[id="field5"]').at(0).find('input').simulate('change', {target: {value: 'rvalnew'}});
@@ -403,11 +403,6 @@ describe('SchemaView', ()=>{
             mode: 'edit',
           }
         });
-
-        /* Press OK */
-        spyOn(legacyConnector, 'confirmDeleteRow').and.callFake((yesFn)=>{
-          yesFn();
-        });
       });
       it('init', (done)=>{
         setTimeout(()=>{
@@ -463,9 +458,9 @@ describe('SchemaView', ()=>{
           let confirmSpy = spyOn(Notify, 'confirm').and.callThrough();
           ctrl.find('DefaultButton[data-test="Reset"]').simulate('click');
           /* Press OK */
-          confirmSpy.calls.argsFor(0)[2]();
+          confirmSpy.calls.mostRecent().args[2]();
           setTimeout(()=>{
-            onRestAction(done, {});
+            onResetAction(done, {});
           }, 0);
         }, 0);
       });
diff --git a/web/regression/javascript/components/FormComponents.spec.js b/web/regression/javascript/components/FormComponents.spec.js
index be70cb272..635e09756 100644
--- a/web/regression/javascript/components/FormComponents.spec.js
+++ b/web/regression/javascript/components/FormComponents.spec.js
@@ -28,10 +28,10 @@ import {FormInputText, FormInputFileSelect, FormInputSQL,
   FormInputColor,
   FormFooterMessage,
   MESSAGE_TYPE} from '../../../pgadmin/static/js/components/FormComponents';
-import * as legacyConnector from '../../../pgadmin/static/js/helpers/legacyConnector';
 import CodeMirror from '../../../pgadmin/static/js/components/CodeMirror';
 import { ToggleButton } from '@material-ui/lab';
 import { DefaultButton, PrimaryButton } from '../../../pgadmin/static/js/components/Buttons';
+import * as showFileManager from '../../../pgadmin/static/js/helpers/showFileManager';
 
 /* MUI Components need to be wrapped in Theme for theme vars */
 describe('FormComponents', ()=>{
@@ -118,7 +118,7 @@ describe('FormComponents', ()=>{
     let ThemedFormInputFileSelect = withTheme(FormInputFileSelect), ctrl;
 
     beforeEach(()=>{
-      spyOn(legacyConnector, 'showFileDialog').and.callFake((controlProps, onFileSelect)=>{
+      spyOn(showFileManager, 'showFileManager').and.callFake((controlProps, onFileSelect)=>{
         onFileSelect('selected/file');
       });
       ctrl = mount(
diff --git a/web/regression/javascript/erd/ui_components/body_widget_spec.js b/web/regression/javascript/erd/ui_components/body_widget_spec.js
index 74afced32..04f9fa13c 100644
--- a/web/regression/javascript/erd/ui_components/body_widget_spec.js
+++ b/web/regression/javascript/erd/ui_components/body_widget_spec.js
@@ -38,12 +38,11 @@ let pgAdmin = {
       app_version_int: 1234,
     },
   },
-  FileManager: {
-    init: jasmine.createSpy(),
-    show_dialog: jasmine.createSpy(),
-  },
   Tools: {
     SQLEditor: {},
+    FileManager: {
+      show: jasmine.createSpy(),
+    },
   }
 };
 
@@ -360,7 +359,7 @@ describe('ERD BodyWidget', ()=>{
 
   it('onLoadDiagram', ()=>{
     bodyInstance.onLoadDiagram();
-    expect(pgAdmin.FileManager.show_dialog).toHaveBeenCalled();
+    expect(pgAdmin.Tools.FileManager.show).toHaveBeenCalled();
   });
 
   it('openFile', (done)=>{
@@ -389,9 +388,10 @@ describe('ERD BodyWidget', ()=>{
       done();
     });
 
+    pgAdmin.Tools.FileManager.show.calls.reset();
     bodyInstance.onSaveDiagram(true);
-    expect(pgAdmin.FileManager.show_dialog).toHaveBeenCalledWith({
-      'supported_types': ['pgerd'],
+    expect(pgAdmin.Tools.FileManager.show.calls.argsFor(0)[0]).toEqual({
+      'supported_types': ['*','pgerd'],
       'dialog_type': 'create_file',
       'dialog_title': 'Save File',
       'btn_primary': 'Save',
diff --git a/web/regression/javascript/fake_endpoints.js b/web/regression/javascript/fake_endpoints.js
index fd5ec175f..79686fe55 100644
--- a/web/regression/javascript/fake_endpoints.js
+++ b/web/regression/javascript/fake_endpoints.js
@@ -28,5 +28,13 @@ define(function () {
     'erd.sql': '/erd/sql/<int:trans_id>/<int:sgid>/<int:sid>/<int:did>',
     'erd.prequisite': '/erd/prequisite/<int:trans_id>/<int:sgid>/<int:sid>/<int:did>',
     'erd.tables': '/erd/tables/<int:trans_id>/<int:sgid>/<int:sid>/<int:did>',
+    'file_manager.init': '/file_manager/init',
+    'file_manager.filemanager': '/file_manager/init',
+    'file_manager.index': '/file_manager/',
+    'file_manager.delete_trans_id': '/file_manager/delete_trans_id/<int:trans_id>',
+    'file_manager.save_last_dir': '/file_manager/save_last_dir/<int:trans_id>',
+    '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/',
   };
 });
diff --git a/web/regression/javascript/file_manager/FileManager.spec.js b/web/regression/javascript/file_manager/FileManager.spec.js
new file mode 100644
index 000000000..c41136796
--- /dev/null
+++ b/web/regression/javascript/file_manager/FileManager.spec.js
@@ -0,0 +1,324 @@
+/////////////////////////////////////////////////////////////
+//
+// 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 FileManager, { FileManagerUtils, getComparator } from '../../../pgadmin/misc/file_manager/static/js/components/FileManager';
+import MockAdapter from 'axios-mock-adapter';
+import axios from 'axios/index';
+import getApiInstance from '../../../pgadmin/static/js/api_instance';
+import * as pgUtils from '../../../pgadmin/static/js/utils';
+
+const files = [
+  {
+    'Filename': 'file1.sql',
+    'Path': '/home/file1',
+    'file_type': 'sql',
+    'Protected': 0,
+    'Properties': {
+      'Date Created': 'Fri Oct 22 16:59:24 2021',
+      'Date Modified': 'Tue Oct 12 14:08:00 2021',
+      'Size': '1.4 MB'
+    }
+  },
+  {
+    'Filename': 'folder1',
+    'Path': '/home/folder1',
+    'file_type': 'dir',
+    'Protected': 0,
+    'Properties': {
+      'Date Created': 'Fri Oct 22 16:59:24 2021',
+      'Date Modified': 'Tue Oct 12 14:08:00 2021',
+      'Size': '1.4 MB'
+    }
+  }
+];
+
+const transId = 140391;
+const configData = {
+  'transId': transId,
+  'options': {
+    'culture': 'en',
+    'lang': 'py',
+    'defaultViewMode':'list',
+    'autoload': true,
+    'showFullPath': false,
+    'dialog_type': 'select_folder',
+    'show_hidden_files': false,
+    'fileRoot': '/home/current',
+    'capabilities': [
+      'select_folder', 'select_file', 'download',
+      'rename', 'delete', 'upload', 'create'
+    ],
+    'allowed_file_types': [
+      '*',
+      'sql',
+      'backup'
+    ],
+    'platform_type': 'darwin',
+    'show_volumes': true,
+    'homedir': '/home/',
+    'last_selected_format': '*'
+  },
+  'security': {
+    'uploadPolicy': '',
+    'uploadRestrictions': [
+      '*',
+      'sql',
+      'backup'
+    ]
+  },
+  'upload': {
+    'multiple': true,
+    'number': 20,
+    'fileSizeLimit': 50,
+    'imagesOnly': false
+  }
+};
+
+const params={
+  dialog_type: 'select_file',
+};
+
+describe('FileManger', ()=>{
+  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);
+    networkMock.onPost('/file_manager/init').reply(200, {'data': configData});
+    networkMock.onPost(`/file_manager/filemanager/${transId}/`).reply(200, {data: {result: files}});
+    networkMock.onDelete(`/file_manager/delete_trans_id/${transId}`).reply(200, {});
+  });
+
+  afterAll(() => {
+    mount.cleanUp();
+    networkMock.restore();
+  });
+
+  beforeEach(()=>{
+    jasmineEnzyme();
+  });
+
+  describe('FileManger', ()=>{
+    let closeModal=jasmine.createSpy('closeModal'),
+      onOK=jasmine.createSpy('onOK'),
+      onCancel=jasmine.createSpy('onCancel'),
+      ctrlMount = (props)=>{
+        return mount(<Theme>
+          <FileManager
+            params={params}
+            closeModal={closeModal}
+            onOK={onOK}
+            onCancel={onCancel}
+            {...props}
+          />
+        </Theme>);
+      };
+
+    it('init', (done)=>{
+      let ctrl = ctrlMount({});
+      setTimeout(()=>{
+        ctrl.update();
+        expect(ctrl.find('ListView').length).toBe(1);
+        expect(ctrl.find('GridView').length).toBe(0);
+        expect(ctrl.find('InputText[data-label="file-path"]').prop('value')).toBe('/home/current');
+        ctrl?.unmount();
+        let config = {...configData};
+        config.options.defaultViewMode = 'grid';
+        networkMock.onPost('/file_manager/init').reply(200, {'data': config});
+        ctrl = ctrlMount({});
+        setTimeout(()=>{
+          ctrl.update();
+          expect(ctrl.find('ListView').length).toBe(0);
+          expect(ctrl.find('GridView').length).toBe(1);
+          ctrl?.unmount();
+          done();
+        }, 0);
+      }, 500);
+    });
+
+    describe('getComparator', ()=>{
+      it('Filename', ()=>{
+        expect(getComparator({columnKey: 'Filename', direction: 'ASC'})({Filename:'a'}, {Filename:'b'})).toBe(-1);
+        expect(getComparator({columnKey: 'Filename', direction: 'DESC'})({Filename:'a'}, {Filename:'b'})).toBe(1);
+        expect(getComparator({columnKey: 'Filename', direction: 'ASC'})({Filename:'a'}, {Filename:'A'})).toBe(-1);
+      });
+
+      it('Properties.DateModified', ()=>{
+        expect(getComparator({columnKey: 'Properties.DateModified', direction: 'ASC'})(
+          {Properties:{'Date Modified':'Tue Feb 25 11:36:28 2020'}}, {Properties:{'Date Modified':'Tue Feb 26 11:36:28 2020'}})
+        ).toBe(-1);
+        expect(getComparator({columnKey: 'Properties.DateModified', direction: 'DESC'})(
+          {Properties:{'Date Modified':'Tue Feb 25 11:36:28 2020'}}, {Properties:{'Date Modified':'Tue Feb 26 11:36:28 2020'}})
+        ).toBe(1);
+        expect(getComparator({columnKey: 'Properties.DateModified', direction: 'ASC'})(
+          {Properties:{'Date Modified':'Tue Feb 25 11:36:28 2020'}}, {Properties:{'Date Modified':'Tue Feb 25 11:36:28 2020'}})
+        ).toBe(0);
+      });
+
+      it('Properties.Size', ()=>{
+        expect(getComparator({columnKey: 'Properties.Size', direction: 'ASC'})(
+          {Properties:{'Size':'1 KB'}}, {Properties:{'Size':'1 MB'}})
+        ).toBe(-1);
+        expect(getComparator({columnKey: 'Properties.Size', direction: 'DESC'})(
+          {Properties:{'Size':'1 MB'}}, {Properties:{'Size':'1 GB'}})
+        ).toBe(1);
+        expect(getComparator({columnKey: 'Properties.Size', direction: 'ASC'})(
+          {Properties:{'Size':'1 MB'}}, {Properties:{'Size':'1 MB'}})
+        ).toBe(0);
+      });
+    });
+  });
+});
+
+describe('FileManagerUtils', ()=>{
+  let api, fmObj, networkMock;
+  beforeEach(()=>{
+    networkMock = new MockAdapter(axios);
+    networkMock.onDelete(`/file_manager/delete_trans_id/${transId}`).reply(200, {});
+    networkMock.onPost(`/file_manager/filemanager/${transId}/`).reply((config)=>{
+      let retVal = {};
+      let apiData = JSON.parse(config.data);
+      let headers = {};
+      if(apiData.mode == 'addfolder') {
+        retVal = {data: {result: {
+          Name: apiData.name,
+          Path: '/home/'+apiData.name,
+          'Date Modified': 'Tue Feb 25 11:36:28 2020',
+        }}};
+      } else if(apiData.mode == 'rename') {
+        retVal = {data: {result: {
+          'New Path': '/home/'+apiData.new,
+          'New Name': apiData.new,
+        }}};
+      } else if(apiData.mode == 'download') {
+        retVal = 'blobdata';
+        headers = {filename: 'newfile1'};
+      } else if(apiData.mode == 'is_file_exist') {
+        retVal = {data: {result: {Code: 1}}};
+      }
+      return [200, retVal, headers];
+    });
+
+    api = getApiInstance();
+    fmObj = new FileManagerUtils(api, params);
+    fmObj.config = configData;
+  });
+
+  afterEach(()=>{
+    networkMock.restore();
+  });
+
+  it('showHiddenFiles', ()=>{
+    expect(fmObj.showHiddenFiles).toBe(false);
+    networkMock.onPut(`/file_manager/save_show_hidden_file_option/${transId}`).reply(200, {});
+    fmObj.showHiddenFiles = true;
+    expect(fmObj.config.options?.show_hidden_files).toBe(true);
+  });
+
+  it('setLastVisitedDir', async ()=>{
+    let calledPath = null;
+    networkMock.onPost(`/file_manager/save_last_dir/${transId}`).reply((config)=>{
+      calledPath = JSON.parse(config.data).path;
+      return [200, {}];
+    });
+    await fmObj.setLastVisitedDir('/home/xyz');
+    expect(calledPath).toBe('/home/xyz');
+  });
+
+  it('setDialogView', async ()=>{
+    networkMock.onPost(`/file_manager/save_file_dialog_view/${transId}`).reply(200, {});
+    await fmObj.setDialogView('grid');
+    expect(fmObj.config.options.defaultViewMode).toBe('grid');
+  });
+
+  it('setFileType', async ()=>{
+    networkMock.onPost('/settings/save_file_format_setting/').reply(200, {});
+    await fmObj.setFileType('pgerd');
+    expect(fmObj.config.options.last_selected_format).toBe('pgerd');
+  });
+
+  it('join', ()=>{
+    expect(fmObj.join('/dir1/dir2', 'file1')).toBe('/dir1/dir2/file1');
+    expect(fmObj.join('/dir1/dir2/', 'file1')).toBe('/dir1/dir2/file1');
+  });
+
+  it('addFolder', async ()=>{
+    let res = await fmObj.addFolder({Filename: 'newfolder'});
+    expect(res).toEqual({
+      Filename: 'newfolder',
+      Path: '/home/newfolder',
+      file_type: 'dir',
+      Properties: {
+        'Date Modified': 'Tue Feb 25 11:36:28 2020',
+      }
+    });
+  });
+
+  it('rename', async ()=>{
+    let row = {Filename: 'newfolder1', Path: '/home/newfolder'};
+    let res = await fmObj.renameItem(row);
+    expect(res).toEqual({
+      Filename: 'newfolder1',
+      Path: '/home/newfolder1',
+    });
+  });
+
+  it('deleteItem', async ()=>{
+    let row = {Filename: 'newfolder', Path: '/home/newfolder'};
+    let path = await fmObj.deleteItem(row);
+    expect(path).toBe('/home/newfolder');
+
+    path = await fmObj.deleteItem(row, 'file1');
+    expect(path).toBe('/home/newfolder/file1');
+  });
+
+  it('checkPermission', async ()=>{
+    networkMock.reset();
+    networkMock.onPost(`/file_manager/filemanager/${transId}/`).reply(200, {
+      data: {
+        result: {
+          Code: 1,
+        }
+      }
+    });
+    let res = await fmObj.checkPermission('/home/newfolder');
+    expect(res).toEqual(null);
+
+    networkMock.onPost(`/file_manager/filemanager/${transId}/`).reply(200, {
+      data: {
+        result: {
+          Code: 0,
+          Error: 'file error'
+        }
+      }
+    });
+    res = await fmObj.checkPermission('/home/newfolder');
+    expect(res).toEqual('file error');
+  });
+
+  it('isFileExists', async ()=>{
+    let res = await fmObj.isFileExists('/home/newfolder', 'newfile1');
+    expect(res).toBe(true);
+  });
+
+  it('downloadFile', async ()=>{
+    spyOn(pgUtils, 'downloadBlob');
+    let row = {Filename: 'newfile1', Path: '/home/newfile1'};
+    await fmObj.downloadFile(row);
+    expect(pgUtils.downloadBlob).toHaveBeenCalledWith('blobdata', 'newfile1');
+  });
+});
diff --git a/web/regression/javascript/file_manager/GridView.spec.js b/web/regression/javascript/file_manager/GridView.spec.js
new file mode 100644
index 000000000..b2bb7483e
--- /dev/null
+++ b/web/regression/javascript/file_manager/GridView.spec.js
@@ -0,0 +1,62 @@
+/////////////////////////////////////////////////////////////
+//
+// 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 { ItemView } from '../../../pgadmin/misc/file_manager/static/js/components/GridView';
+
+describe('GridView', ()=>{
+  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();
+  });
+
+  describe('ItemView', ()=>{
+    let row = {'Filename': 'test.sql', 'Size': '1KB', 'file_type': 'dir'},
+      ctrlMount = (props)=>{
+        return mount(<Theme>
+          <ItemView
+            idx={0}
+            selected={false}
+            row={row}
+            {...props}
+          />
+        </Theme>);
+      };
+
+    it('keydown Escape', (done)=>{
+      const onEditComplete = jasmine.createSpy('onEditComplete');
+      let ctrl = ctrlMount({
+        onEditComplete: onEditComplete,
+      });
+      setTimeout(()=>{
+        ctrl.update();
+        ctrl.find('div[data-test="filename-div"]').simulate('keydown', { code: 'Escape'});
+        setTimeout(()=>{
+          expect(onEditComplete).toHaveBeenCalled();
+          done();
+        });
+      }, 0);
+    });
+  });
+});
diff --git a/web/regression/javascript/file_manager/ListView.spec.js b/web/regression/javascript/file_manager/ListView.spec.js
new file mode 100644
index 000000000..8036579ae
--- /dev/null
+++ b/web/regression/javascript/file_manager/ListView.spec.js
@@ -0,0 +1,110 @@
+/////////////////////////////////////////////////////////////
+//
+// 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 { CustomRow, FileNameEditor, GridContextUtils } from '../../../pgadmin/misc/file_manager/static/js/components/ListView';
+
+describe('ListView', ()=>{
+  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();
+  });
+
+  describe('FileNameEditor', ()=>{
+    let row = {'Filename': 'test.sql', 'Size': '1KB'},
+      column = {
+        key: 'Filename'
+      },
+      ctrlMount = (props)=>{
+        return mount(<Theme>
+          <FileNameEditor
+            row={row}
+            column={column}
+            {...props}
+          />
+        </Theme>);
+      };
+
+    it('init', (done)=>{
+      let ctrl = ctrlMount({
+        onRowChange: ()=>{/* test func */},
+        onClose: ()=>{/* test func */},
+      });
+      setTimeout(()=>{
+        ctrl.update();
+        expect(ctrl.find('input').props()).toEqual(jasmine.objectContaining({value: 'test.sql'}));
+        done();
+      }, 0);
+    });
+
+    it('keydown Tab', (done)=>{
+      let onCloseSpy = jasmine.createSpy('onClose');
+      let ctrl = ctrlMount({
+        onRowChange: ()=>{/* test func */},
+        onClose: onCloseSpy,
+      });
+      setTimeout(()=>{
+        ctrl.update();
+        expect(ctrl.find('input').props()).toEqual(jasmine.objectContaining({value: 'test.sql'}));
+        ctrl.find('input').simulate('keydown', { code: 'Tab'});
+        setTimeout(()=>{
+          expect(onCloseSpy).toHaveBeenCalled();
+          done();
+        });
+      }, 0);
+    });
+  });
+
+  describe('CustomRow', ()=>{
+    let row = {'Filename': 'test.sql', 'Size': '1KB'},
+      ctrlMount = (onItemSelect, onItemEnter)=>{
+        return mount(<Theme>
+          <GridContextUtils.Provider value={{onItemSelect, onItemEnter}}>
+            <CustomRow
+              row={row}
+              selectedCellIdx={0}
+              rowIdx={0}
+              inTest={true}
+            />
+          </GridContextUtils.Provider>
+        </Theme>);
+      };
+
+    it('init', (done)=>{
+      let onItemSelect = jasmine.createSpy('onItemSelect');
+      let onItemEnter = jasmine.createSpy('onItemEnter');
+      let ctrl = ctrlMount(onItemSelect, onItemEnter);
+      setTimeout(()=>{
+        ctrl.update();
+        ctrl.find('div[data-test="test-div"]').simulate('keydown', { code: 'Enter'});
+        setTimeout(()=>{
+          ctrl.update();
+          expect(onItemEnter).toHaveBeenCalled();
+          ctrl?.unmount();
+          done();
+        }, 0);
+      }, 0);
+    });
+  });
+});
diff --git a/web/regression/javascript/file_manager/Uploader.spec.js b/web/regression/javascript/file_manager/Uploader.spec.js
new file mode 100644
index 000000000..4f6cb5fad
--- /dev/null
+++ b/web/regression/javascript/file_manager/Uploader.spec.js
@@ -0,0 +1,254 @@
+/////////////////////////////////////////////////////////////
+//
+// 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 Uploader, { filesReducer, getFileSize, UploadedFile } from '../../../pgadmin/misc/file_manager/static/js/components/Uploader';
+import { MESSAGE_TYPE } from '../../../pgadmin/static/js/components/FormComponents';
+
+describe('GridView', ()=>{
+  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();
+  });
+
+  describe('Uploader', ()=>{
+    let fmUtilsObj = jasmine.createSpyObj('fmUtilsObj', ['uploadItem', 'deleteItem'], ['currPath']);
+    let onClose = jasmine.createSpy('onClose');
+    let ctrlMount = (props)=>{
+      return mount(<Theme>
+        <Uploader
+          fmUtilsObj={fmUtilsObj}
+          onClose={onClose}
+          {...props}
+        />
+      </Theme>);
+    };
+
+    it('init', (done)=>{
+      let ctrl = ctrlMount();
+      setTimeout(()=>{
+        ctrl.update();
+        done();
+      }, 0);
+    });
+
+    describe('filesReducer', ()=>{
+      let state;
+
+      beforeEach(()=>{
+        state = [
+          {
+            id: 1,
+            file: 'file1',
+            progress: 0,
+            started: false,
+            failed: false,
+            done: false,
+            deleting: false,
+          }
+        ];
+      });
+
+      it('add', ()=>{
+        let newState = filesReducer(state, {
+          type: 'add',
+          files: ['new1'],
+        });
+        expect(newState.length).toBe(2);
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'new1',
+          progress: 0,
+          started: false,
+          failed: false,
+          done: false,
+          deleting: false,
+        }));
+      });
+
+
+      it('started', ()=>{
+        let newState = filesReducer(state, {
+          type: 'started',
+          id: 1,
+        });
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'file1',
+          progress: 0,
+          started: true,
+          failed: false,
+          done: false,
+          deleting: false,
+        }));
+      });
+
+      it('started', ()=>{
+        let newState = filesReducer(state, {
+          type: 'progress',
+          id: 1,
+          value: 14,
+        });
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'file1',
+          progress: 14,
+          started: false,
+          failed: false,
+          done: false,
+          deleting: false,
+        }));
+      });
+
+      it('failed', ()=>{
+        let newState = filesReducer(state, {
+          type: 'failed',
+          id: 1,
+        });
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'file1',
+          progress: 0,
+          started: false,
+          failed: true,
+          done: false,
+          deleting: false,
+        }));
+      });
+
+      it('done', ()=>{
+        let newState = filesReducer(state, {
+          type: 'done',
+          id: 1,
+        });
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'file1',
+          progress: 0,
+          started: false,
+          failed: false,
+          done: true,
+          deleting: false,
+        }));
+      });
+
+      it('deleting', ()=>{
+        let newState = filesReducer(state, {
+          type: 'deleting',
+          id: 1,
+        });
+        expect(newState[0]).toEqual(jasmine.objectContaining({
+          file: 'file1',
+          progress: 0,
+          started: false,
+          failed: false,
+          done: false,
+          deleting: true,
+        }));
+      });
+
+      it('delete', ()=>{
+        let newState = filesReducer(state, {
+          type: 'delete',
+          id: 1,
+        });
+        expect(newState.length).toBe(0);
+      });
+    });
+
+    it('getFileSize', ()=>{
+      expect(getFileSize(1024)).toBe('1 KB');
+    });
+
+    describe('UploadedFile', ()=>{
+      let upCtrlMount = (props)=>{
+        return mount(<Theme>
+          <UploadedFile
+            deleteFile={()=>{/*dummy*/}}
+            onClose={onClose}
+            {...props}
+          />
+        </Theme>);
+      };
+
+      it('uploading', (done)=>{
+        let ctrl = upCtrlMount({upfile: {
+          file: {
+            name: 'file1',
+            size: '1KB',
+          },
+          done: false,
+          failed: false,
+          progress: 14,
+        }});
+
+        setTimeout(()=>{
+          ctrl.update();
+          expect(ctrl.find('FormFooterMessage').props()).toEqual(jasmine.objectContaining({
+            type: MESSAGE_TYPE.INFO,
+            message: 'Uploading... 14%',
+          }));
+          done();
+        }, 0);
+      });
+
+      it('done', (done)=>{
+        let ctrl = upCtrlMount({upfile: {
+          file: {
+            name: 'file1',
+            size: '1KB',
+          },
+          done: true,
+          failed: false,
+          progress: 14,
+        }});
+
+        setTimeout(()=>{
+          ctrl.update();
+          expect(ctrl.find('FormFooterMessage').props()).toEqual(jasmine.objectContaining({
+            type: MESSAGE_TYPE.SUCCESS,
+            message: 'Uploaded!',
+          }));
+          done();
+        }, 0);
+      });
+
+      it('failed', (done)=>{
+        let ctrl = upCtrlMount({upfile: {
+          file: {
+            name: 'file1',
+            size: '1KB',
+          },
+          done: false,
+          failed: true,
+          progress: 14,
+        }});
+
+        setTimeout(()=>{
+          ctrl.update();
+          expect(ctrl.find('FormFooterMessage').props()).toEqual(jasmine.objectContaining({
+            type: MESSAGE_TYPE.ERROR,
+            message: 'Failed!',
+          }));
+          done();
+        }, 0);
+      });
+    });
+  });
+});
diff --git a/web/regression/javascript/file_manager/file_manager_specs.js b/web/regression/javascript/file_manager/file_manager_specs.js
deleted file mode 100644
index fd860817e..000000000
--- a/web/regression/javascript/file_manager/file_manager_specs.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// 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 Alertify from 'pgadmin.alertifyjs';
-import '../../../pgadmin/misc/file_manager/static/js/file_manager';
-import '../../../pgadmin/misc/file_manager/static/js/select_dialogue.js';
-
-
-describe('fileSelectDialog', function () {
-
-  let params;
-  let calcWidth = (passed_width)=>{
-    let iw = window.innerWidth;
-    if (iw > passed_width){
-      return passed_width;
-    } else {
-      if (iw > pgAdmin.Browser.stdW.lg)
-        return pgAdmin.Browser.stdW.lg;
-      else if (iw > pgAdmin.Browser.stdW.md)
-        return pgAdmin.Browser.stdW.md;
-      else if (iw > pgAdmin.Browser.stdW.sm)
-        return pgAdmin.Browser.stdW.sm;
-      else
-        // if available screen resolution is still
-        // less then return the width value as it
-        return iw;
-    }
-  };
-
-  let calcHeight = (passed_height)=>{
-    // We are excluding sm as it is too small for dialog
-    let ih = window.innerHeight;
-    if (ih > passed_height){
-      return passed_height;
-    }else{
-      if (ih > pgAdmin.Browser.stdH.lg)
-        return pgAdmin.Browser.stdH.lg;
-      else if (ih > pgAdmin.Browser.stdH.md)
-        return pgAdmin.Browser.stdH.md;
-      else
-        // if available screen resolution is still
-        // less then return the height value as it
-        return ih;
-    }
-  };
-
-  beforeAll(() => {
-    pgAdmin.Browser = {
-      stdW: {
-        sm: 500,
-        md: 700,
-        lg: 900,
-        default: 500,
-        calc: (passed_width) => {
-          calcWidth(passed_width);
-        },
-      },
-      stdH: {
-        sm: 200,
-        md: 400,
-        lg: 550,
-        default: 550,
-        calc: (passed_height) => {
-          calcHeight(passed_height);
-        },
-      },
-    };
-  });
-
-  describe('When dialog is called for', () => {
-    it('Select file', function() {
-      params = {
-        'dialog_title': 'Select file',
-        'dialog_type': 'select_file',
-      };
-
-      spyOn(Alertify, 'fileSelectionDlg').and.callFake(function() {
-        this.resizeTo = function() {/*This is intentional (SonarQube)*/};
-        return this;
-      });
-
-      pgAdmin.FileManager.show_dialog(params);
-
-      expect(Alertify.fileSelectionDlg).toHaveBeenCalled();
-    });
-
-    it('create file', function() {
-      params = {
-        'dialog_title': 'Create file',
-        'dialog_type': 'create_file',
-      };
-
-      spyOn(Alertify, 'createModeDlg').and.callFake(function() {
-        this.resizeTo = function() {/*This is intentional (SonarQube)*/};
-        return this;
-      });
-
-      pgAdmin.FileManager.show_dialog(params);
-
-      expect(Alertify.createModeDlg).toHaveBeenCalled();
-    });
-  });
-
-  describe('When dialog is called for storage file', () => {
-    it('Storage file dialog', function() {
-      params = {
-        'dialog_title': 'Storage Manager',
-        'dialog_type': 'storage_dialog',
-      };
-
-      spyOn(Alertify, 'fileStorageDlg').and.callFake(function() {
-        this.resizeTo = function() {/*This is intentional (SonarQube)*/};
-        return this;
-      });
-
-      pgAdmin.FileManager.show_dialog(params);
-
-      expect(Alertify.fileStorageDlg).toHaveBeenCalled();
-    });
-  });
-});
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 210627608..8873198a4 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -381,7 +381,6 @@ module.exports = [{
     schema_diff: './pgadmin/tools/schema_diff/static/js/schema_diff_hook.js',
     erd_tool: './pgadmin/tools/erd/static/js/erd_tool_hook.js',
     psql_tool: './pgadmin/tools/psql/static/js/index.js',
-    file_utils: './pgadmin/misc/file_manager/static/js/utility.js',
     debugger: './pgadmin/tools/debugger/static/js/index.js',
     'pgadmin.style': pgadminCssStyles,
     pgadmin: pgadminScssStyles,
@@ -535,7 +534,6 @@ module.exports = [{
           imports: [
             'pure|pgadmin.about',
             'pure|pgadmin.preferences',
-            'pure|pgadmin.file_manager',
             'pure|pgadmin.settings',
             'pure|pgadmin.tools.backup',
             'pure|pgadmin.tools.restore',
@@ -546,7 +544,7 @@ module.exports = [{
             'pure|pgadmin.tools.debugger',
             'pure|pgadmin.node.pga_job',
             'pure|pgadmin.tools.schema_diff',
-            'pure|pgadmin.tools.storage_manager',
+            'pure|pgadmin.tools.file_manager',
             'pure|pgadmin.tools.search_objects',
             'pure|pgadmin.tools.erd_module',
             'pure|pgadmin.tools.psql_module',
diff --git a/web/webpack.shim.js b/web/webpack.shim.js
index 4d5d13d9b..14cc6ef91 100644
--- a/web/webpack.shim.js
+++ b/web/webpack.shim.js
@@ -144,7 +144,6 @@ var webpackShimConfig = {
     'snap.svg': path.join(__dirname, './node_modules/snapsvg-cjs/dist/snap.svg-cjs'),
     'color-picker': path.join(__dirname, './node_modules/@simonwep/pickr/dist/pickr.es5.min'),
     'mousetrap': path.join(__dirname, './node_modules/mousetrap'),
-    'tablesorter-metric': path.join(__dirname, './node_modules/tablesorter/dist/js/parsers/parser-metric.min'),
     'pathfinding':  path.join(__dirname, 'node_modules/pathfinding'),
     'dagre':  path.join(__dirname, 'node_modules/dagre'),
     'graphlib': path.join(__dirname, 'node_modules/graphlib'),
@@ -205,8 +204,6 @@ var webpackShimConfig = {
     'pgadmin.browser.utils': '/browser/js/utils',
     'pgadmin.browser.wizard': path.join(__dirname, './pgadmin/browser/static/js/wizard'),
     'pgadmin.dashboard': path.join(__dirname, './pgadmin/dashboard/static/js/Dashboard'),
-    'pgadmin.file_manager': path.join(__dirname, './pgadmin/misc/file_manager/static/js/file_manager'),
-    'pgadmin.file_utility': path.join(__dirname, './pgadmin/misc/file_manager/static/js/utility'),
     'pgadmin.help': path.join(__dirname, './pgadmin/help/static/js/help'),
     'pgadmin.misc.explain': path.join(__dirname, './pgadmin/misc/static/explain/js/explain'),
     'pgadmin.misc.cloud': path.join(__dirname, './pgadmin/misc/cloud/static/js/cloud'),
@@ -278,6 +275,7 @@ var webpackShimConfig = {
     'pgadmin.tools.debugger': path.join(__dirname, './pgadmin/tools/debugger/static/js/'),
     'pgadmin.tools.debugger.ui': path.join(__dirname, './pgadmin/tools/debugger/static/js/debugger_ui'),
     'pgadmin.tools.debugger.utils': path.join(__dirname, './pgadmin/tools/debugger/static/js/debugger_utils'),
+    'pgadmin.tools.file_manager': path.join(__dirname, './pgadmin/misc/file_manager/static/js'),
     'pgadmin.tools.grant_wizard': path.join(__dirname, './pgadmin/tools/grant_wizard/static/js/grant_wizard'),
     'pgadmin.tools.import_export': path.join(__dirname, './pgadmin/tools/import_export/static/js/import_export'),
     'pgadmin.tools.import_export_servers': path.join(__dirname, './pgadmin/tools/import_export_servers/static/js/'),
@@ -286,7 +284,6 @@ var webpackShimConfig = {
     'pgadmin.tools.schema_diff': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff'),
     'pgadmin.tools.schema_diff_ui': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff_ui'),
     'pgadmin.tools.search_objects': path.join(__dirname, './pgadmin/tools/search_objects/static/js/search_objects'),
-    'pgadmin.tools.storage_manager': path.join(__dirname, './pgadmin/tools/storage_manager/static/js/storage_manager'),
     'pgadmin.tools.erd_module': path.join(__dirname, './pgadmin/tools/erd/static/js/erd_module'),
     'pgadmin.tools.erd': path.join(__dirname, './pgadmin/tools/erd/static/js'),
     'pgadmin.tools.psql_module': path.join(__dirname, './pgadmin/tools/psql/static/js/psql_module'),
@@ -315,8 +312,8 @@ var webpackShimConfig = {
     'pgadmin.browser.server.variable', 'pgadmin.browser.collection', 'pgadmin.browser.node.ui',
     'pgadmin.browser.datamodel', 'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin',
     'pgadmin.browser.frame', 'slick.pgadmin.editors', 'slick.pgadmin.formatters',
-    'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser', 'pgadmin.file_manager',
-    'pgadmin.file_utility', 'pgadmin.browser.node',
+    'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser',
+    'pgadmin.browser.node',
     'pgadmin.alertifyjs', 'pgadmin.settings', 'pgadmin.preferences', 'pgadmin.sqlfoldcode',
   ],
   // Checks whether JS module is npm module or not
diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js
index 438f6ded4..9a2add644 100644
--- a/web/webpack.test.config.js
+++ b/web/webpack.test.config.js
@@ -212,6 +212,7 @@ module.exports = {
       'pgadmin.tools.erd': path.join(__dirname, './pgadmin/tools/erd/static/js'),
       'pgadmin.tools.psql': path.join(__dirname, './pgadmin/tools/psql/static/js'),
       'pgadmin.tools.sqleditor': path.join(__dirname, './pgadmin/tools/sqleditor/static/js'),
+      'pgadmin.tools.file_manager': path.join(__dirname, './pgadmin/misc/file_manager/static/js'),
       'pgadmin.authenticate.kerberos': path.join(__dirname, './pgadmin/authenticate/static/js/kerberos'),
       'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'),
       'tools': path.join(__dirname, './pgadmin/tools/'),
diff --git a/web/yarn.lock b/web/yarn.lock
index 182e681f9..8d7d1e110 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -3200,6 +3200,11 @@ async@^3.2.0:
   resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd"
   integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==
 
+attr-accept@^2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b"
+  integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==
+
 autoprefixer@^10.2.4:
   version "10.4.0"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.0.tgz#c3577eb32a1079a440ec253e404eaf1eb21388c8"
@@ -4221,6 +4226,14 @@ convert-source-map@~1.1.0:
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
   integrity sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=
 
+convert-units@^2.3.4:
+  version "2.3.4"
+  resolved "https://registry.yarnpkg.com/convert-units/-/convert-units-2.3.4.tgz#a279f4b3cb9b5d5094beba61abc742dcb46a180d"
+  integrity sha512-ERHfdA0UhHJp1IpwE6PnFJx8LqG7B1ZjJ20UvVCmopEnVCfER68Tbe3kvN63dLbYXDA2xFWRE6zd4Wsf0w7POg==
+  dependencies:
+    lodash.foreach "2.3.x"
+    lodash.keys "2.3.x"
+
 cookie@~0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
@@ -4787,11 +4800,6 @@ domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0:
     domelementtype "^2.2.0"
     domhandler "^4.2.0"
 
-dropzone@^5.9.3:
-  version "5.9.3"
-  resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-5.9.3.tgz#b3070ae090fa48cbc04c17535635537ca72d70d6"
-  integrity sha512-Azk8kD/2/nJIuVPK+zQ9sjKMRIpRvNyqn9XwbBHNq+iNuSccbJS6hwm1Woy0pMST0erSo0u4j+KJaodndDk4vA==
-
 duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -5343,6 +5351,13 @@ file-entry-cache@^6.0.1:
   dependencies:
     flat-cache "^3.0.4"
 
+file-selector@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc"
+  integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==
+  dependencies:
+    tslib "^2.4.0"
+
 file-type@^12.0.0:
   version "12.4.2"
   resolved "https://registry.yarnpkg.com/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9"
@@ -6493,7 +6508,7 @@ jquery-ui@>=1.8.0, jquery-ui@^1.13.0:
   dependencies:
     jquery ">=1.8.0 <4.0.0"
 
-jquery@>=1.2.6, "jquery@>=1.7.1 <4.0.0", jquery@>=1.8.0, "jquery@>=1.8.0 <4.0.0", jquery@^3.3.1, jquery@^3.5.0, jquery@^3.5.1, jquery@^3.6.0:
+"jquery@>=1.7.1 <4.0.0", jquery@>=1.8.0, "jquery@>=1.8.0 <4.0.0", jquery@^3.3.1, jquery@^3.5.0, jquery@^3.5.1, jquery@^3.6.0:
   version "3.6.0"
   resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
   integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
@@ -6910,6 +6925,44 @@ locate-path@^6.0.0:
   dependencies:
     p-locate "^5.0.0"
 
+lodash._basebind@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248"
+  integrity sha512-SHqM7YCuJ+BeGTs7lqpWnmdHEeF4MWxS3dksJctHFNxR81FXPOzA4bS5Vs5CpcGTkBpM8FCl+YEbQEblRw8ABg==
+  dependencies:
+    lodash._basecreate "~2.3.0"
+    lodash._setbinddata "~2.3.0"
+    lodash.isobject "~2.3.0"
+
+lodash._basecreate@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0"
+  integrity sha512-vwZaWldZwS2y9b99D8i9+WtgiZXbHKsBsMrpxJEqTsNW20NhJo5W8PBQkeQO9CmxuqEYn8UkMnfEM2MMT4cVrw==
+  dependencies:
+    lodash._renative "~2.3.0"
+    lodash.isobject "~2.3.0"
+    lodash.noop "~2.3.0"
+
+lodash._basecreatecallback@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362"
+  integrity sha512-Ev+pDzzfVfgbiucpXijconLGRBar7/+KNCf05kSnk4CmdDVhAy1RdbU9efCJ/o9GXI08JdUGwZ+5QJ3QX3kj0g==
+  dependencies:
+    lodash._setbinddata "~2.3.0"
+    lodash.bind "~2.3.0"
+    lodash.identity "~2.3.0"
+    lodash.support "~2.3.0"
+
+lodash._basecreatewrapper@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247"
+  integrity sha512-YLycQ7k8AB9Wc1EOvLNxuRWcqipDkMXq2GCgnLWQR6qtgTb3gY3LELzEpnFshrEO4LOLs+R2EpcY+uCOZaLQ8Q==
+  dependencies:
+    lodash._basecreate "~2.3.0"
+    lodash._setbinddata "~2.3.0"
+    lodash._slice "~2.3.0"
+    lodash.isobject "~2.3.0"
+
 lodash._baseisequal@^3.0.0:
   version "3.0.7"
   resolved "https://registry.yarnpkg.com/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1"
@@ -6924,11 +6977,59 @@ lodash._bindcallback@^3.0.0:
   resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
   integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
 
+lodash._createwrapper@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075"
+  integrity sha512-XjaI/rzg9W+WO4WJDQ+PRlHD5sAMJ1RhJLuT65cBxLCb1kIYs4U20jqvTDGAWyVT3c34GYiLd9AreHYuB/8yJA==
+  dependencies:
+    lodash._basebind "~2.3.0"
+    lodash._basecreatewrapper "~2.3.0"
+    lodash.isfunction "~2.3.0"
+
 lodash._getnative@^3.0.0:
   version "3.9.1"
   resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
   integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
 
+lodash._objecttypes@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e"
+  integrity sha512-jbA6QyHt9cw3BzvbWzIcnU3Z12jSneT6xBgz3Y782CJsN1tV5aTBKrFo2B4AkeHBNaxSrbPYZZpi1Lwj3xjdtg==
+
+lodash._renative@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3"
+  integrity sha512-v44MRirqYqZGK/h5UKoVqXWF2L+LUiLTU+Ogu5rHRVWJUA1uWIlHaMpG8f/OA8j++BzPMQij9+erXHtgFcbuwg==
+
+lodash._setbinddata@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04"
+  integrity sha512-xMFfbF7dL+sFtrdE49uHFmfpBAEwlFtfgMp86nQRlAF6aizYL+3MTbnYMKJSkP1W501PhsgiBED5kBbZd8kR2g==
+  dependencies:
+    lodash._renative "~2.3.0"
+    lodash.noop "~2.3.0"
+
+lodash._shimkeys@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9"
+  integrity sha512-9Iuyi7TiWMGa/9+2rqEE+Zwye4b/U2w7Saw6UX1h6Xs88mEER+uz9FZcEBPKMVKsad9Pw5GNAcIBRnW2jNpneQ==
+  dependencies:
+    lodash._objecttypes "~2.3.0"
+
+lodash._slice@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c"
+  integrity sha512-7C61GhzRUv36gTafr+RIb+AomCAYsSATEoK4OP0VkNBcwvsM022Z22AVgqjjzikeNO1U29LzsJZDvLbiNPUYvA==
+
+lodash.bind@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc"
+  integrity sha512-goakyOo+FMN8lttMPnZ0UNlr5RlzX4IrUXyTJPT2A0tGCMXySupond9wzvDqTvVmYTcQjIKGrj8naJDS2xWAlQ==
+  dependencies:
+    lodash._createwrapper "~2.3.0"
+    lodash._renative "~2.3.0"
+    lodash._slice "~2.3.0"
+
 lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -6944,6 +7045,28 @@ lodash.flattendeep@^4.4.0:
   resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
   integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
 
+lodash.foreach@2.3.x:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168"
+  integrity sha512-yLnyptVRJd0//AbGp480grgQG9iaDIV5uOgSbpurRy1dYybPbjNTLQ3FyLEQ84buVLPG7jyaiyvpzgfOutRB3Q==
+  dependencies:
+    lodash._basecreatecallback "~2.3.0"
+    lodash.forown "~2.3.0"
+
+lodash.forown@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f"
+  integrity sha512-dUnCsuQTtq3Y7bxPNoEEqjJjPL2ftLtcz2PTeRKvhbpdM514AvnqCjewHGsm/W+dwspIwa14KoWEZeizJ7smxA==
+  dependencies:
+    lodash._basecreatecallback "~2.3.0"
+    lodash._objecttypes "~2.3.0"
+    lodash.keys "~2.3.0"
+
+lodash.identity@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded"
+  integrity sha512-NYJ2r2cwy3tkx/saqbIZEX6oQUzjWTnGRu7d/zmBjMCZos3eHBxCpbvWFWSetv8jFVrptsp6EbWjzNgBKhUoOA==
+
 lodash.isarguments@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
@@ -6967,11 +7090,32 @@ lodash.isequal@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
   integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
 
+lodash.isfunction@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267"
+  integrity sha512-X5lteBYlCrVO7Qc00fxP8W90fzRp6Ax9XcHANmU3OsZHdSyIVZ9ZlX5QTTpRq8aGY+9I5Rmd0UTzTIIyWPugEQ==
+
+lodash.isobject@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799"
+  integrity sha512-jo1pfV61C4TE8BfEzqaHj6EIKiSkFANJrB6yscwuCJMSRw5tbqjk4Gv7nJzk4Z6nFKobZjGZ8Qd41vmnwgeQqQ==
+  dependencies:
+    lodash._objecttypes "~2.3.0"
+
 lodash.istypedarray@^3.0.0:
   version "3.0.6"
   resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62"
   integrity sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=
 
+lodash.keys@2.3.x, lodash.keys@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253"
+  integrity sha512-c0UW0ffqMxSCtoVbmVt2lERJLkEqgoOn2ejPsWXzr0ZrqRbl3uruGgwHzhtqXxi6K/ei3Ey7zimOqSwXgzazPg==
+  dependencies:
+    lodash._renative "~2.3.0"
+    lodash._shimkeys "~2.3.0"
+    lodash.isobject "~2.3.0"
+
 lodash.keys@^3.0.0:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
@@ -6996,6 +7140,18 @@ lodash.merge@^4.6.2:
   resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
   integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
 
+lodash.noop@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c"
+  integrity sha512-NpSm8HRm1WkBBWHUveDukLF4Kfb5P5E3fjHc9Qre9A11nNubozLWD2wH3UBTZbu+KSuX8aSUvy9b+PUyEceJ8g==
+
+lodash.support@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd"
+  integrity sha512-etc7VWbB0U3Iya8ixj2xy4sDBN3jvPX7ODi8iXtn4KkkjNpdngrdc7Vlt5jub/Vgqx6/dWtp7Ml9awhCQPYKGQ==
+  dependencies:
+    lodash._renative "~2.3.0"
+
 lodash.truncate@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
@@ -8245,6 +8401,15 @@ prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
     object-assign "^4.1.1"
     react-is "^16.8.1"
 
+prop-types@^15.8.1:
+  version "15.8.1"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+  integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+  dependencies:
+    loose-envify "^1.4.0"
+    object-assign "^4.1.1"
+    react-is "^16.13.1"
+
 public-encrypt@^4.0.0:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
@@ -8554,6 +8719,15 @@ react-draggable@^4.4.4:
     clsx "^1.1.1"
     prop-types "^15.6.0"
 
+react-dropzone@^14.2.1:
+  version "14.2.1"
+  resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.1.tgz#aad17e06290723358398a7be76fb38ecf6d77c1a"
+  integrity sha512-jzX6wDtAjlfwZ+Fbg+G17EszWUkQVxhMTWMfAC9qSUq7II2pKglHA8aarbFKl0mLpRPDaNUcy+HD/Sf4gkf76Q==
+  dependencies:
+    attr-accept "^2.2.2"
+    file-selector "^0.6.0"
+    prop-types "^15.8.1"
+
 react-input-autosize@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85"
@@ -9775,13 +9949,6 @@ table@^6.0.9:
     string-width "^4.2.3"
     strip-ansi "^6.0.1"
 
-tablesorter@^2.31.2:
-  version "2.31.3"
-  resolved "https://registry.yarnpkg.com/tablesorter/-/tablesorter-2.31.3.tgz#94c33234ba0e5d9efc5ba4e48651010a396c8b64"
-  integrity sha512-ueEzeKiMajDcCWnUoT1dOeNEaS1OmPh9+8J0O2Sjp3TTijMygH74EA9QNJiNkLJqULyNU0RhbKY26UMUq9iurA==
-  dependencies:
-    jquery ">=1.2.6"
-
 tapable@^2.1.1, tapable@^2.2.0:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
@@ -9948,6 +10115,11 @@ tslib@^2.2.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
   integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
 
+tslib@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
+  integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
+
 ttf2eot@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ttf2eot/-/ttf2eot-2.0.0.tgz#8e6337a585abd1608a0c84958ab483ce69f6654b"
