diff --git a/pgmanage/app/migrations/0031_userdetails_show_system_catalogs.py b/pgmanage/app/migrations/0031_userdetails_show_system_catalogs.py
new file mode 100644
index 000000000..10f59a1ff
--- /dev/null
+++ b/pgmanage/app/migrations/0031_userdetails_show_system_catalogs.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.23 on 2025-11-14 12:09
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('app', '0030_populate_mssql-technology'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='userdetails',
+ name='show_system_catalogs',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/pgmanage/app/models/main.py b/pgmanage/app/models/main.py
index e37b81590..b7122e040 100644
--- a/pgmanage/app/models/main.py
+++ b/pgmanage/app/models/main.py
@@ -22,6 +22,7 @@ class UserDetails(models.Model):
pigz_path = models.CharField(max_length=256, null=True)
restore_tabs = models.BooleanField(default=True)
scroll_tree = models.BooleanField(default=True)
+ show_system_catalogs = models.BooleanField(default=False)
def get_pigz_path(self):
diff --git a/pgmanage/app/static/pgmanage_frontend/src/components/SettingsModal.vue b/pgmanage/app/static/pgmanage_frontend/src/components/SettingsModal.vue
index 31c04be29..99bbe364a 100644
--- a/pgmanage/app/static/pgmanage_frontend/src/components/SettingsModal.vue
+++ b/pgmanage/app/static/pgmanage_frontend/src/components/SettingsModal.vue
@@ -102,6 +102,15 @@
+
@@ -358,6 +367,14 @@ export default {
settingsStore.setScrollTree(value)
}
},
+ showSystemCatalogs: {
+ get() {
+ return settingsStore.showSystemCatalogs
+ },
+ set(value) {
+ settingsStore.setShowSystemCatalogs(value)
+ }
+ },
shortcuts() {
return settingsStore.shortcuts
},
diff --git a/pgmanage/app/static/pgmanage_frontend/src/stores/settings.js b/pgmanage/app/static/pgmanage_frontend/src/stores/settings.js
index b1a8a7445..e3c6965b8 100644
--- a/pgmanage/app/static/pgmanage_frontend/src/stores/settings.js
+++ b/pgmanage/app/static/pgmanage_frontend/src/stores/settings.js
@@ -22,6 +22,7 @@ const useSettingsStore = defineStore("settings", {
shortcuts: {},
currentOS: "Unknown OS",
max_upload_size: "",
+ showSystemCatalogs: "",
}),
actions: {
async getSettings() {
@@ -43,6 +44,7 @@ const useSettingsStore = defineStore("settings", {
? "YYYY-MM-DD, HH:mm:ss"
: userSettings.date_format,
max_upload_size: userSettings.max_upload_size,
+ showSystemCatalogs: userSettings.show_system_catalogs,
});
this.shortcuts = Object.assign(
@@ -74,6 +76,7 @@ const useSettingsStore = defineStore("settings", {
pigz_path: this.pigzPath,
restore_tabs: this.restoreTabs,
scroll_tree: this.scrollTree,
+ show_system_catalogs: this.showSystemCatalogs,
},
});
@@ -121,6 +124,9 @@ const useSettingsStore = defineStore("settings", {
setScrollTree(value) {
this.scrollTree = value;
},
+ setShowSystemCatalogs(value) {
+ this.showSystemCatalogs = value;
+ },
showModal() {
Modal.getOrCreateInstance("#modal_settings", {
backdrop: "static",
diff --git a/pgmanage/app/tests/test_postgresql12.py b/pgmanage/app/tests/test_postgresql12.py
index 3453c9431..9b9aa41fa 100644
--- a/pgmanage/app/tests/test_postgresql12.py
+++ b/pgmanage/app/tests/test_postgresql12.py
@@ -987,15 +987,34 @@ def test_get_schemas_postgresql_nosession(self):
response = self.client_nosession.post('/get_schemas_postgresql/')
assert 401 == response.status_code
- def test_get_schemas_postgresql_session(self):
+ def test_get_schemas_postgresql_session_with_system_catalogs(self):
+ user = User.objects.get(username="admin")
+ user.userdetails.show_system_catalogs = True
+ user.userdetails.save()
+
response = self.client_session.post('/get_schemas_postgresql/', {'data': '{"database_index": 0, "workspace_id": 0}'})
assert 200 == response.status_code
- data = json.loads(response.content.decode())
+ data = response.json()
assert self.lists_equal([a['name'] for a in data], [
'public',
'pg_catalog',
'information_schema'
])
+
+ def test_get_schemas_postgresql_session_without_system_catalogs(self):
+ user = User.objects.get(username="admin")
+ user.userdetails.show_system_catalogs = False
+ user.userdetails.save()
+
+ response = self.client_session.post('/get_schemas_postgresql/', {'data': '{"database_index": 0, "workspace_id": 0}'})
+ assert response.status_code == 200
+
+ data = json.loads(response.content.decode())
+
+ assert self.lists_equal(
+ [a['name'] for a in data],
+ ['public']
+ )
def test_get_columns_postgresql_nosession(self):
response = self.client_nosession.post('/get_columns_postgresql/')
diff --git a/pgmanage/app/views/tree_mariadb.py b/pgmanage/app/views/tree_mariadb.py
index 8ce7a355d..147e9d034 100644
--- a/pgmanage/app/views/tree_mariadb.py
+++ b/pgmanage/app/views/tree_mariadb.py
@@ -253,6 +253,7 @@ def get_indexes_columns(request, database):
def get_databases(request, database):
try:
conn_object = Connection.objects.get(id=database.conn_id)
+ system_dbs = {"mysql", "information_schema", "performance_schema", "sys"}
databases = database.QueryDatabases()
list_databases = [
@@ -261,6 +262,7 @@ def get_databases(request, database):
"pinned": db[0] in conn_object.pinned_databases,
}
for db in databases.Rows
+ if request.user.userdetails.show_system_catalogs or db[0] not in system_dbs
]
except Exception as exc:
return JsonResponse(data={"data": str(exc)}, status=400)
diff --git a/pgmanage/app/views/tree_mssql.py b/pgmanage/app/views/tree_mssql.py
index 99e5cd404..24ce42550 100644
--- a/pgmanage/app/views/tree_mssql.py
+++ b/pgmanage/app/views/tree_mssql.py
@@ -55,11 +55,14 @@ def get_tree_info(request, database):
@database_required(check_timeout=True, open_connection=True)
def get_databases(request, database):
list_databases = []
+ system_dbs = {"master", "model", "msdb", "tempdb"}
try:
conn_object = Connection.objects.get(id=database.conn_id)
databases = database.QueryDatabases()
for database_object in databases.Rows:
+ if not request.user.userdetails.show_system_catalogs and database_object[0] in system_dbs:
+ continue
database_data = {
"name": database_object[0],
"pinned": database_object[0] in conn_object.pinned_databases,
@@ -75,10 +78,13 @@ def get_databases(request, database):
@database_required(check_timeout=True, open_connection=True)
def get_schemas(request, database):
schemas_list = []
+ system_schemas = {"sys", "INFORMATION_SCHEMA"}
try:
schemas = database.QuerySchemas()
for schema in schemas.Rows:
+ if not request.user.userdetails.show_system_catalogs and schema["schema_name"] in system_schemas:
+ continue
schema_data = {
"name": schema["schema_name"],
}
diff --git a/pgmanage/app/views/tree_mysql.py b/pgmanage/app/views/tree_mysql.py
index be15704b1..6fc4193f9 100644
--- a/pgmanage/app/views/tree_mysql.py
+++ b/pgmanage/app/views/tree_mysql.py
@@ -282,6 +282,7 @@ def get_indexes_columns(request, database):
def get_databases(request, database):
try:
conn_object = Connection.objects.get(id=database.conn_id)
+ system_dbs = {"mysql", "information_schema", "performance_schema", "sys"}
databases = database.QueryDatabases()
list_databases = [
@@ -290,6 +291,7 @@ def get_databases(request, database):
"pinned": db[0] in conn_object.pinned_databases,
}
for db in databases.Rows
+ if request.user.userdetails.show_system_catalogs or db[0] not in system_dbs
]
except Exception as exc:
return JsonResponse(data={"data": str(exc)}, status=400)
diff --git a/pgmanage/app/views/tree_postgresql.py b/pgmanage/app/views/tree_postgresql.py
index 3231a9583..4942199a0 100644
--- a/pgmanage/app/views/tree_postgresql.py
+++ b/pgmanage/app/views/tree_postgresql.py
@@ -817,10 +817,12 @@ def get_mview_definition(request, database):
@database_required(check_timeout=True, open_connection=True)
def get_schemas(request, database):
schemas_list = []
-
+ system_schemas = {"information_schema", "pg_catalog"}
try:
schemas = database.QuerySchemas()
for schema in schemas.Rows:
+ if not request.user.userdetails.show_system_catalogs and schema["schema_name"] in system_schemas:
+ continue
schema_data = {
"name": schema["schema_name"],
"oid": schema["oid"],