Show object breadcrumbs path along with its comment on object hover. #2078
After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 217 KiB |
|
@ -88,6 +88,30 @@ displayed in the *Browser* tree control:
|
|||
catalogs, you can reduce the number of object types displayed to increase
|
||||
speed.
|
||||
|
||||
Use the fields on the *Object Breadcrumbs* panel to change object breadcrumbs
|
||||
related settings:
|
||||
|
||||
.. image:: images/preferences_browser_breadcrumbs.png
|
||||
:alt: Preferences dialog object breadcrumbs section
|
||||
:align: center
|
||||
|
||||
* Use *Enable object breadcrumbs?* to enable or disable object breadcrumbs
|
||||
displayed on on object mouse hover.
|
||||
|
||||
* Use *Show comment with object breadcrumbs?* to enable or disable the
|
||||
comment visibility which comes displayed with object breadcrumbs.
|
||||
|
||||
|
||||
Use the fields on the *Processes* panel to change processes tab
|
||||
related settings:
|
||||
|
||||
.. image:: images/preferences_browser_processes.png
|
||||
:alt: Preferences dialog processes section
|
||||
:align: center
|
||||
|
||||
* Change *Process details/logs retention days* to the number of days,
|
||||
the process info and logs will be automatically cleared.
|
||||
|
||||
Use fields on the *Properties* panel to specify browser properties:
|
||||
|
||||
.. image:: images/preferences_browser_properties.png
|
||||
|
|
|
@ -10,7 +10,8 @@ import sys
|
|||
from flask_babel import gettext
|
||||
from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\
|
||||
PREF_LABEL_KEYBOARD_SHORTCUTS, PREF_LABEL_TABS_SETTINGS, \
|
||||
PREF_LABEL_OPTIONS, QT_DEFAULT_PLACEHOLDER, VW_EDT_DEFAULT_PLACEHOLDER
|
||||
PREF_LABEL_OPTIONS, QT_DEFAULT_PLACEHOLDER, VW_EDT_DEFAULT_PLACEHOLDER, \
|
||||
PREF_LABEL_BREADCRUMBS
|
||||
from flask import current_app
|
||||
import config
|
||||
|
||||
|
@ -557,3 +558,25 @@ def register_browser_preferences(self):
|
|||
' back to the default title with placeholders.'
|
||||
)
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'breadcrumbs', 'breadcrumbs_enable',
|
||||
gettext("Enable object breadcrumbs?"),
|
||||
'boolean',
|
||||
True, category_label=PREF_LABEL_BREADCRUMBS,
|
||||
help_str=gettext(
|
||||
'Enable breadcrumbs to show the complete path of an object in the '
|
||||
'object explorer. The breadcrumbs are displayed on object mouse '
|
||||
'hover.'
|
||||
)
|
||||
)
|
||||
|
||||
self.preference.register(
|
||||
'breadcrumbs', 'breadcrumbs_show_comment',
|
||||
gettext("Show comment with object breadcrumbs?"),
|
||||
'boolean',
|
||||
True, category_label=PREF_LABEL_BREADCRUMBS,
|
||||
help_str=gettext(
|
||||
'Show object comment along with breadcrumbs.'
|
||||
)
|
||||
)
|
||||
|
|
|
@ -271,7 +271,8 @@ class ServerModule(sg.ServerGroupPluginModule):
|
|||
shared=server.shared,
|
||||
is_kerberos_conn=bool(server.kerberos_conn),
|
||||
gss_authenticated=manager.gss_authenticated,
|
||||
cloud_status=server.cloud_status
|
||||
cloud_status=server.cloud_status,
|
||||
description=server.comment
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -595,7 +596,8 @@ class ServerNode(PGChildNodeView):
|
|||
username=server.username,
|
||||
shared=server.shared,
|
||||
is_kerberos_conn=bool(server.kerberos_conn),
|
||||
gss_authenticated=manager.gss_authenticated
|
||||
gss_authenticated=manager.gss_authenticated,
|
||||
description=server.comment
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -846,7 +848,8 @@ class ServerNode(PGChildNodeView):
|
|||
server_type='pg', # default server type
|
||||
username=server.username,
|
||||
role=server.role,
|
||||
is_password_saved=bool(server.save_password)
|
||||
is_password_saved=bool(server.save_password),
|
||||
description=server.comment
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -386,7 +386,8 @@ class DatabaseView(PGChildNodeView):
|
|||
canDisconn=can_dis_conn,
|
||||
canDrop=can_drop,
|
||||
isTemplate=row['is_template'],
|
||||
inode=True if row['datallowconn'] else False
|
||||
inode=True if row['datallowconn'] else False,
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -282,7 +282,8 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-cast"
|
||||
icon="icon-cast",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -449,12 +450,17 @@ class CastView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
cid,
|
||||
did,
|
||||
name,
|
||||
"icon-{0}".format(self.node_type)
|
||||
"icon-{0}".format(self.node_type),
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
SELECT
|
||||
ca.oid,
|
||||
pg_catalog.concat(pg_catalog.format_type(st.oid,NULL),'->',pg_catalog.format_type(tt.oid,tt.typtypmod)) as name
|
||||
pg_catalog.concat(pg_catalog.format_type(st.oid,NULL),'->',pg_catalog.format_type(tt.oid,tt.typtypmod)) as name,
|
||||
des.description
|
||||
FROM pg_catalog.pg_cast ca
|
||||
JOIN pg_catalog.pg_type st ON st.oid=castsource
|
||||
JOIN pg_catalog.pg_namespace ns ON ns.oid=st.typnamespace
|
||||
|
|
|
@ -264,7 +264,8 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
self.node_icon
|
||||
self.node_icon,
|
||||
description=row['comment']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -481,12 +482,17 @@ class EventTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
)
|
||||
status, etid = self.conn.execute_scalar(sql)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
etid,
|
||||
did,
|
||||
data['name'],
|
||||
self.node_icon
|
||||
self.node_icon,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
SELECT e.oid, e.evtname AS name
|
||||
SELECT e.oid, e.evtname AS name,
|
||||
pg_catalog.obj_description(e.oid, 'pg_event_trigger') AS comment
|
||||
FROM pg_catalog.pg_event_trigger e
|
||||
{% if etid %}
|
||||
WHERE e.oid={{etid}}::oid
|
||||
|
|
|
@ -188,7 +188,8 @@ class ExtensionView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
'icon-extension'
|
||||
'icon-extension',
|
||||
description=row['comment']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -327,12 +328,17 @@ class ExtensionView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
eid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -299,7 +299,8 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-foreign_data_wrapper"
|
||||
icon="icon-foreign_data_wrapper",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -505,12 +506,17 @@ class ForeignDataWrapperView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
fid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -290,7 +290,8 @@ class ForeignServerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
fid,
|
||||
row['name'],
|
||||
icon="icon-foreign_server"
|
||||
icon="icon-foreign_server",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -503,12 +504,17 @@ class ForeignServerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
fsid,
|
||||
fid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -296,7 +296,8 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
did,
|
||||
row['name'],
|
||||
icon="icon-language"
|
||||
icon="icon-language",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -434,12 +435,17 @@ class LanguageView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
lid,
|
||||
did,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -540,7 +540,8 @@ class SchemaView(PGChildNodeView):
|
|||
row['name'],
|
||||
icon=self.node_icon,
|
||||
can_create=row['can_create'],
|
||||
has_usage=row['has_usage']
|
||||
has_usage=row['has_usage'],
|
||||
description=row['description']
|
||||
),
|
||||
status=200
|
||||
)
|
||||
|
@ -553,7 +554,8 @@ class SchemaView(PGChildNodeView):
|
|||
row['name'],
|
||||
icon=self.node_icon,
|
||||
can_create=row['can_create'],
|
||||
has_usage=row['has_usage']
|
||||
has_usage=row['has_usage'],
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -750,12 +752,17 @@ It may have been removed by another user.
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
scid,
|
||||
did,
|
||||
name,
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -231,7 +231,8 @@ class AggregateView(PGChildNodeView):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-aggregate"
|
||||
icon="icon-aggregate",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
SELECT aggfnoid::oid as oid,
|
||||
proname || '(' || COALESCE(pg_catalog.pg_get_function_arguments(aggfnoid::oid), '') || ')' AS name,
|
||||
pg_catalog.pg_get_userbyid(proowner) AS owner
|
||||
pg_catalog.pg_get_userbyid(proowner) AS owner,
|
||||
description
|
||||
FROM pg_aggregate ag
|
||||
LEFT OUTER JOIN pg_catalog.pg_proc pr ON pr.oid = ag.aggfnoid
|
||||
LEFT OUTER JOIN pg_catalog.pg_type tt on tt.oid=aggtranstype
|
||||
|
|
|
@ -235,7 +235,8 @@ class CatalogObjectView(PGChildNodeView):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-catalog_object"
|
||||
icon="icon-catalog_object",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
|
|
@ -246,7 +246,8 @@ class CatalogObjectColumnsView(PGChildNodeView):
|
|||
row['attnum'],
|
||||
coid,
|
||||
row['attname'],
|
||||
icon="icon-catalog_object_column"
|
||||
icon="icon-catalog_object_column",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
SELECT
|
||||
attnum, attname
|
||||
attnum, attname, des.description
|
||||
FROM pg_catalog.pg_attribute att
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
|
||||
WHERE att.attrelid = {{coid}}::oid
|
||||
AND att.attnum > 0
|
||||
AND att.attisdropped IS FALSE
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
SELECT
|
||||
c.oid, c.relname as name
|
||||
c.oid, c.relname as name, description
|
||||
FROM
|
||||
pg_catalog.pg_class c
|
||||
LEFT OUTER JOIN pg_catalog.pg_description d
|
||||
ON d.objoid=c.oid AND d.classoid='pg_class'::regclass
|
||||
{% if scid %}
|
||||
WHERE relnamespace = {{scid}}::oid
|
||||
{% elif coid %}
|
||||
|
|
|
@ -268,7 +268,8 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-collation"
|
||||
icon="icon-collation",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -604,12 +605,17 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
|
||||
scid = res['rows'][0]['scid']
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
coid,
|
||||
scid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
SELECT c.oid, c.collname AS name
|
||||
SELECT c.oid, c.collname AS name, des.description
|
||||
FROM pg_catalog.pg_collation c
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid AND des.classoid='pg_collation'::regclass)
|
||||
{% if scid %}
|
||||
WHERE c.collnamespace = {{scid}}::oid
|
||||
{% elif coid %}
|
||||
|
|
|
@ -358,7 +358,8 @@ class DomainView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-domain"
|
||||
icon="icon-domain",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -713,12 +714,17 @@ AND relkind != 'c'))"""
|
|||
if not status:
|
||||
return internal_server_error(errormsg=scid)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in self.request:
|
||||
other_node_info['description'] = self.request['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
doid,
|
||||
scid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -333,7 +333,8 @@ class DomainConstraintView(PGChildNodeView):
|
|||
row['oid'],
|
||||
doid,
|
||||
row['name'],
|
||||
icon=icon
|
||||
icon=icon,
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -559,12 +560,17 @@ class DomainConstraintView(PGChildNodeView):
|
|||
else:
|
||||
icon = ''
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
coid,
|
||||
doid,
|
||||
name,
|
||||
icon=icon
|
||||
icon=icon,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
SELECT
|
||||
d.oid, d.typname as name, pg_catalog.pg_get_userbyid(d.typowner) as owner,
|
||||
bn.nspname as basensp
|
||||
bn.nspname as basensp, des.description
|
||||
FROM
|
||||
pg_catalog.pg_type d
|
||||
JOIN
|
||||
pg_catalog.pg_type b ON b.oid = d.typbasetype
|
||||
JOIN
|
||||
pg_catalog.pg_namespace bn ON bn.oid=d.typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_catalog.pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)
|
||||
{% if scid is defined %}
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
|
|
|
@ -447,7 +447,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-foreign_table"
|
||||
icon="icon-foreign_table",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -835,12 +836,17 @@ class ForeignTableView(PGChildNodeView, DataTypeReader,
|
|||
|
||||
scid = res['rows'][0]['scid']
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in self.request:
|
||||
other_node_info['description'] = self.request['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
foid,
|
||||
scid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -296,7 +296,8 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-fts_configuration"
|
||||
icon="icon-fts_configuration",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -539,12 +540,17 @@ class FtsConfigurationView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
_("Could not find the FTS Configuration node to update.")
|
||||
)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
cfgid,
|
||||
data['schema'] if 'schema' in data else scid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
{# FETCH FTS CONFIGURATION NAME statement #}
|
||||
SELECT
|
||||
oid, cfgname as name
|
||||
cfg.oid, cfgname as name, des.description
|
||||
FROM
|
||||
pg_catalog.pg_ts_config cfg
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des
|
||||
ON (des.objoid=cfg.oid AND des.classoid='pg_ts_config'::regclass)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
cfg.cfgnamespace = {{scid}}::OID
|
||||
|
|
|
@ -308,7 +308,8 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-fts_dictionary"
|
||||
icon="icon-fts_dictionary",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -530,12 +531,17 @@ class FtsDictionaryView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
_("Could not find the FTS Dictionary node to update.")
|
||||
)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
dcid,
|
||||
res['rows'][0]['schema'],
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{# Fetch FTS DICTIONARY name statement #}
|
||||
SELECT
|
||||
oid, dictname as name,
|
||||
dictnamespace as schema
|
||||
dict.oid, dictname as name,
|
||||
dictnamespace as schema,
|
||||
des.description
|
||||
FROM
|
||||
pg_catalog.pg_ts_dict dict
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=dict.oid AND des.classoid='pg_ts_dict'::regclass)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
dict.dictnamespace = {{scid}}::OID
|
||||
|
|
|
@ -279,7 +279,8 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-fts_parser"
|
||||
icon="icon-fts_parser",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -477,12 +478,17 @@ class FtsParserView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
_("Could not find the FTS Parser node to update.")
|
||||
)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
pid,
|
||||
data['schema'] if 'schema' in data else scid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
{# FETCH FTS PARSER name statement #}
|
||||
SELECT
|
||||
oid, prsname as name, prs.prsnamespace AS schema
|
||||
prs.oid, prsname as name, prs.prsnamespace AS schema, des.description
|
||||
FROM
|
||||
pg_catalog.pg_ts_parser prs
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des
|
||||
ON
|
||||
(
|
||||
des.objoid=prs.oid
|
||||
AND des.classoid='pg_ts_parser'::regclass
|
||||
)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
prs.prsnamespace = {{scid}}::OID
|
||||
|
|
|
@ -257,7 +257,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-fts_template"
|
||||
icon="icon-fts_template",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -445,7 +446,8 @@ class FtsTemplateView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
tid,
|
||||
rset['schema'],
|
||||
rset['name'],
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
description=rset['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
SELECT
|
||||
oid, tmplname as name, tmpl.tmplnamespace AS schema
|
||||
tmpl.oid, tmplname as name, tmpl.tmplnamespace AS schema, des.description
|
||||
FROM
|
||||
pg_catalog.pg_ts_template tmpl
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des
|
||||
ON
|
||||
(
|
||||
des.objoid=tmpl.oid
|
||||
AND des.classoid='pg_ts_template'::regclass
|
||||
)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
tmpl.tmplnamespace = {{scid}}::OID
|
||||
|
|
|
@ -435,7 +435,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
row['name'],
|
||||
icon="icon-" + self.node_type,
|
||||
funcowner=row['funcowner'],
|
||||
language=row['lanname']
|
||||
language=row['lanname'],
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -447,7 +448,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
row['name'],
|
||||
icon="icon-" + self.node_type,
|
||||
funcowner=row['funcowner'],
|
||||
language=row['lanname']
|
||||
language=row['lanname'],
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -977,7 +979,8 @@ class FunctionView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
obj_name,
|
||||
icon="icon-" + self.node_type,
|
||||
language=resp_data['lanname'],
|
||||
funcowner=resp_data['funcowner']
|
||||
funcowner=resp_data['funcowner'],
|
||||
description=resp_data['description']
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
|
|
@ -230,7 +230,8 @@ class OperatorView(PGChildNodeView):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-operator"
|
||||
icon="icon-operator",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
|
|
@ -7,7 +7,7 @@ SELECT op.oid, pg_catalog.pg_get_userbyid(op.oprowner) as owner,
|
|||
op.oprname || ' (' || pg_catalog.format_type(lt.oid, NULL) || ')'
|
||||
ELSE op.oprname || '()'
|
||||
END as name,
|
||||
lt.typname as lefttype, rt.typname as righttype
|
||||
lt.typname as lefttype, rt.typname as righttype, description
|
||||
FROM pg_catalog.pg_operator op
|
||||
LEFT OUTER JOIN pg_catalog.pg_type lt ON lt.oid=op.oprleft
|
||||
LEFT OUTER JOIN pg_catalog.pg_type rt ON rt.oid=op.oprright
|
||||
|
|
|
@ -239,7 +239,8 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -249,7 +250,8 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -527,12 +529,17 @@ class PackageView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
pkgid,
|
||||
scid,
|
||||
name,
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
SELECT
|
||||
nsp.oid, nspname AS name
|
||||
nsp.oid, nspname AS name, des.description
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
|
||||
WHERE nspparent = {{scid}}::oid
|
||||
{% if pkgid %}
|
||||
AND nsp.oid = {{pkgid}}::oid
|
||||
|
|
|
@ -229,7 +229,9 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['comment']
|
||||
|
||||
),
|
||||
status=200
|
||||
)
|
||||
|
@ -240,7 +242,8 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -563,7 +566,8 @@ class SequenceView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
seid,
|
||||
row['schema'],
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['comment']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
SELECT cl.oid as oid, relname as name, relnamespace as schema
|
||||
SELECT cl.oid as oid, relname as name, relnamespace as schema, description as comment
|
||||
FROM pg_catalog.pg_class cl
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=cl.oid
|
||||
AND des.classoid='pg_class'::regclass)
|
||||
{% if show_internal %}
|
||||
LEFT JOIN pg_catalog.pg_depend d1 ON d1.refobjid = cl.oid AND d1.deptype = 'i'
|
||||
{% endif %}
|
||||
|
|
|
@ -438,7 +438,8 @@ class TableView(BaseTableView, DataTypeReader, SchemaDiffTableCompare):
|
|||
icon=icon,
|
||||
tigger_count=row['triggercount'],
|
||||
has_enable_triggers=row['has_enable_triggers'],
|
||||
is_partitioned=self.is_table_partitioned(row)
|
||||
is_partitioned=self.is_table_partitioned(row),
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
|
|
@ -291,7 +291,8 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
|||
tid,
|
||||
row['name'],
|
||||
icon="icon-column",
|
||||
datatype=row['datatype'] # We need datatype somewhere in
|
||||
datatype=row['datatype'], # We need datatype somewhere in,
|
||||
description=row['description']
|
||||
),
|
||||
status=200
|
||||
)
|
||||
|
@ -303,7 +304,8 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
|||
tid,
|
||||
row['name'],
|
||||
icon="icon-column",
|
||||
datatype=row['datatype'] # We need datatype somewhere in
|
||||
datatype=row['datatype'], # We need datatype somewhere in
|
||||
description=row['description']
|
||||
)) # exclusion constraint.
|
||||
|
||||
return make_json_response(
|
||||
|
@ -535,12 +537,17 @@ class ColumnsView(PGChildNodeView, DataTypeReader):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
clid,
|
||||
tid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -398,7 +398,8 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['name'],
|
||||
icon="icon-compound_trigger-bad"
|
||||
if row['is_enable_trigger'] == 'D'
|
||||
else "icon-compound_trigger"
|
||||
else "icon-compound_trigger",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -671,7 +672,8 @@ class CompoundTriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
name,
|
||||
icon="icon-%s-bad" % self.node_type if
|
||||
data['is_enable_trigger'] == 'D' else
|
||||
"icon-%s" % self.node_type
|
||||
"icon-%s" % self.node_type,
|
||||
description=data['description']
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -359,7 +359,8 @@ class CheckConstraintView(PGChildNodeView):
|
|||
tid,
|
||||
row['name'],
|
||||
icon=icon,
|
||||
valid=valid
|
||||
valid=valid,
|
||||
description=row['comment']
|
||||
))
|
||||
return make_json_response(
|
||||
data=res,
|
||||
|
@ -699,13 +700,18 @@ class CheckConstraintView(PGChildNodeView):
|
|||
icon = 'icon-check_constraint'
|
||||
valid = True
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
cid,
|
||||
tid,
|
||||
name,
|
||||
icon=icon,
|
||||
valid=valid
|
||||
valid=valid,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -419,7 +419,8 @@ class ExclusionConstraintView(PGChildNodeView):
|
|||
row['oid'],
|
||||
tid,
|
||||
row['name'],
|
||||
icon="icon-exclusion_constraint"
|
||||
icon="icon-exclusion_constraint",
|
||||
description=row['comment']
|
||||
))
|
||||
return make_json_response(
|
||||
data=res,
|
||||
|
@ -639,12 +640,17 @@ class ExclusionConstraintView(PGChildNodeView):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
exid,
|
||||
tid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -442,7 +442,8 @@ class ForeignKeyConstraintView(PGChildNodeView):
|
|||
tid,
|
||||
row['name'],
|
||||
icon=icon,
|
||||
valid=valid
|
||||
valid=valid,
|
||||
description=row['comment']
|
||||
))
|
||||
return make_json_response(
|
||||
data=res,
|
||||
|
@ -702,6 +703,10 @@ class ForeignKeyConstraintView(PGChildNodeView):
|
|||
icon = "icon-foreign_key"
|
||||
valid = True
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
fkid,
|
||||
|
|
|
@ -442,7 +442,8 @@ class IndexConstraintView(PGChildNodeView):
|
|||
row['oid'],
|
||||
tid,
|
||||
row['name'],
|
||||
icon=self.node_icon
|
||||
icon=self.node_icon,
|
||||
description=row['comment']
|
||||
)
|
||||
)
|
||||
return make_json_response(
|
||||
|
@ -686,6 +687,10 @@ class IndexConstraintView(PGChildNodeView):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
cid,
|
||||
|
|
|
@ -462,7 +462,8 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
tid,
|
||||
row['name'],
|
||||
icon="icon-index"
|
||||
icon="icon-index",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -770,12 +771,17 @@ class IndexesView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
idx,
|
||||
tid,
|
||||
name,
|
||||
icon="icon-%s" % self.node_type
|
||||
icon="icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -306,7 +306,8 @@ class PartitionsView(BaseTableView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
is_partitioned=row['is_partitioned'],
|
||||
parent_schema_id=scid,
|
||||
schema_id=row['schema_id'],
|
||||
schema_name=row['schema_name']
|
||||
schema_name=row['schema_name'],
|
||||
description=row['description']
|
||||
)
|
||||
|
||||
if ptid is not None:
|
||||
|
|
|
@ -274,7 +274,8 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
row['name'],
|
||||
icon="icon-rule-bad"
|
||||
if 'is_enable_rule' in row and
|
||||
row['is_enable_rule'] == 'D' else "icon-rule"
|
||||
row['is_enable_rule'] == 'D' else "icon-rule",
|
||||
description=row['comment']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -381,6 +382,11 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'comment' in data:
|
||||
other_node_info['description'] = data['comment']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
rid,
|
||||
|
@ -389,7 +395,8 @@ class RuleView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
icon="icon-%s-bad" % self.node_type
|
||||
if 'is_enable_rule' in data and
|
||||
data['is_enable_rule'] == 'D'
|
||||
else "icon-%s" % self.node_type
|
||||
else "icon-%s" % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
SELECT c.oid, conname as name,
|
||||
NOT convalidated as convalidated, conislocal
|
||||
NOT convalidated as convalidated, conislocal, description as comment
|
||||
FROM pg_catalog.pg_constraint c
|
||||
LEFT OUTER JOIN
|
||||
pg_catalog.pg_description des ON (des.objoid=c.oid AND
|
||||
des.classoid='pg_constraint'::regclass)
|
||||
WHERE contype = 'c'
|
||||
AND conrelid = {{ tid }}::oid
|
||||
{% if cid %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SELECT DISTINCT att.attname as name, att.attnum as OID, pg_catalog.format_type(ty.oid,NULL) AS datatype,
|
||||
att.attnotnull as not_null, att.atthasdef as has_default_val
|
||||
att.attnotnull as not_null, att.atthasdef as has_default_val, des.description
|
||||
FROM pg_catalog.pg_attribute att
|
||||
JOIN pg_catalog.pg_type ty ON ty.oid=atttypid
|
||||
JOIN pg_catalog.pg_namespace tn ON tn.oid=ty.typnamespace
|
||||
|
@ -10,6 +10,7 @@ FROM pg_catalog.pg_attribute att
|
|||
LEFT OUTER JOIN (pg_catalog.pg_depend JOIN pg_catalog.pg_class cs ON classid='pg_class'::regclass AND objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum
|
||||
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=cs.relnamespace
|
||||
LEFT OUTER JOIN pg_catalog.pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
|
||||
WHERE
|
||||
att.attrelid = {{ tid|qtLiteral(conn) }}::oid
|
||||
{% if clid %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
|
||||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger, des.description
|
||||
FROM pg_catalog.pg_trigger t
|
||||
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
AND tgpackageoid != 0
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
SELECT conindid as oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
NOT convalidated as convalidated,
|
||||
desp.description AS comment
|
||||
FROM pg_catalog.pg_constraint ct
|
||||
LEFT OUTER JOIN pg_catalog.pg_description desp ON (desp.objoid=ct.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
|
||||
WHERE contype='x' AND
|
||||
conrelid = {{tid}}::oid
|
||||
{% if exid %}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
SELECT ct.oid,
|
||||
conname as name,
|
||||
NOT convalidated as convalidated
|
||||
NOT convalidated as convalidated,
|
||||
description as comment
|
||||
FROM pg_catalog.pg_constraint ct
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=ct.oid AND des.classoid='pg_constraint'::regclass)
|
||||
WHERE contype='f' AND
|
||||
conrelid = {{tid}}::oid
|
||||
ORDER BY conname
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
SELECT cls.oid, cls.relname as name
|
||||
SELECT cls.oid, cls.relname as name,
|
||||
CASE contype
|
||||
WHEN 'p' THEN desp.description
|
||||
WHEN 'u' THEN desp.description
|
||||
WHEN 'x' THEN desp.description
|
||||
ELSE des.description
|
||||
END AS comment
|
||||
FROM pg_catalog.pg_index idx
|
||||
JOIN pg_catalog.pg_class cls ON cls.oid=indexrelid
|
||||
LEFT JOIN pg_catalog.pg_depend dep ON (dep.classid = cls.tableoid AND
|
||||
|
@ -10,6 +16,8 @@ LEFT JOIN pg_catalog.pg_depend dep ON (dep.classid = cls.tableoid AND
|
|||
dep.deptype='i')
|
||||
LEFT OUTER JOIN pg_catalog.pg_constraint con ON (con.tableoid = dep.refclassid AND
|
||||
con.oid = dep.refobjid)
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=cls.oid AND des.classoid='pg_class'::regclass)
|
||||
LEFT OUTER JOIN pg_catalog.pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0 AND desp.classoid='pg_constraint'::regclass)
|
||||
WHERE indrelid = {{tid}}::oid
|
||||
AND contype='{{constraint_type}}'
|
||||
{% if cid %}
|
||||
|
|
|
@ -2,10 +2,11 @@ SELECT
|
|||
rw.oid AS oid,
|
||||
rw.rulename AS name,
|
||||
CASE WHEN rw.ev_enabled != 'D' THEN True ELSE False END AS enabled,
|
||||
rw.ev_enabled AS is_enable_rule
|
||||
|
||||
rw.ev_enabled AS is_enable_rule,
|
||||
description AS comment
|
||||
FROM
|
||||
pg_catalog.pg_rewrite rw
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rw.oid AND des.classoid='pg_rewrite'::regclass)
|
||||
WHERE
|
||||
{% if tid %}
|
||||
rw.ev_class = {{ tid }}
|
||||
|
|
|
@ -3,8 +3,10 @@ SELECT rel.oid, rel.relname AS name,
|
|||
(SELECT count(*) FROM pg_catalog.pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
|
||||
(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
|
||||
(SELECT count(1) FROM pg_catalog.pg_inherits WHERE inhrelid=rel.oid LIMIT 1) as is_inherits,
|
||||
(SELECT count(1) FROM pg_catalog.pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited
|
||||
(SELECT count(1) FROM pg_catalog.pg_inherits WHERE inhparent=rel.oid LIMIT 1) as is_inherited,
|
||||
des.description
|
||||
FROM pg_catalog.pg_class rel
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)
|
||||
WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
|
||||
AND NOT rel.relispartition
|
||||
{% if tid %} AND rel.oid = {{tid}}::OID {% endif %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
|
||||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger, des.description
|
||||
FROM pg_catalog.pg_trigger t
|
||||
WHERE NOT tgisinternal
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger
|
||||
SELECT t.oid, t.tgname as name, t.tgenabled AS is_enable_trigger, des.description
|
||||
FROM pg_catalog.pg_trigger t
|
||||
WHERE NOT tgisinternal
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_trigger'::regclass)
|
||||
WHERE NOT tgisinternal
|
||||
AND tgrelid = {{tid}}::OID
|
||||
{% if trid %}
|
||||
AND t.oid = {{trid}}::OID
|
||||
|
|
|
@ -488,7 +488,8 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
tid,
|
||||
row['name'],
|
||||
icon="icon-trigger-bad" if row['is_enable_trigger'] == 'D'
|
||||
else "icon-trigger"
|
||||
else "icon-trigger",
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -763,7 +764,8 @@ class TriggerView(PGChildNodeView, SchemaDiffObjectCompare):
|
|||
name,
|
||||
icon="icon-%s-bad" % self.node_type if
|
||||
data['is_enable_trigger'] == 'D' else
|
||||
"icon-%s" % self.node_type
|
||||
"icon-%s" % self.node_type,
|
||||
description=data['description']
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -1628,6 +1628,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
|||
else:
|
||||
icon = self.get_icon_css_class(res['rows'][0])
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
tid,
|
||||
|
@ -1638,7 +1642,8 @@ class BaseTableView(PGChildNodeView, BasePartitionTable, VacuumSettings):
|
|||
parent_schema_id=scid,
|
||||
schema_id=rest['rows'][0]['scid'],
|
||||
schema_name=rest['rows'][0]['nspname'],
|
||||
affected_partitions=partitions_oid
|
||||
affected_partitions=partitions_oid,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -3,9 +3,12 @@ SELECT
|
|||
nsp.oid,
|
||||
{{ CATALOGS.LABELS('nsp', _) }},
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'CREATE') as can_create,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage,
|
||||
des.description
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON
|
||||
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
nsp.oid={{scid}}::oid AND
|
||||
|
|
|
@ -3,9 +3,12 @@ SELECT
|
|||
nsp.oid,
|
||||
{{ CATALOGS.LABELS('nsp', _) }},
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'CREATE') as can_create,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage,
|
||||
des.description
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON
|
||||
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
nsp.oid={{scid}}::oid AND
|
||||
|
|
|
@ -3,9 +3,12 @@ SELECT
|
|||
nsp.oid,
|
||||
nsp.nspname as name,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'CREATE') as can_create,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage,
|
||||
des.description
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON
|
||||
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
|
||||
WHERE
|
||||
{% if scid %}
|
||||
nsp.oid={{scid}}::oid AND
|
||||
|
|
|
@ -3,9 +3,12 @@ SELECT
|
|||
nsp.oid,
|
||||
nsp.nspname as name,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'CREATE') as can_create,
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage
|
||||
pg_catalog.has_schema_privilege(nsp.oid, 'USAGE') as has_usage,
|
||||
des.description
|
||||
FROM
|
||||
pg_catalog.pg_namespace nsp
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON
|
||||
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
|
||||
WHERE
|
||||
nsp.nspparent = 0 AND
|
||||
{% if scid %}
|
||||
|
|
|
@ -358,7 +358,8 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon=self.icon_str % self.node_type
|
||||
icon=self.icon_str % self.node_type,
|
||||
description=row['description']
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
|
@ -1101,12 +1102,17 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare):
|
|||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
other_node_info = {}
|
||||
if 'description' in data:
|
||||
other_node_info['description'] = data['description']
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
tid,
|
||||
scid,
|
||||
name,
|
||||
icon=self.icon_str % self.node_type
|
||||
icon=self.icon_str % self.node_type,
|
||||
**other_node_info
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
SELECT t.oid, t.typname AS name
|
||||
SELECT t.oid, t.typname AS name, des.description
|
||||
FROM pg_catalog.pg_type t
|
||||
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
|
||||
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
|
||||
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
|
||||
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
|
||||
{% if tid %}
|
||||
AND t.oid = {{tid}}::oid
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
SELECT t.oid, t.typname AS name
|
||||
SELECT t.oid, t.typname AS name, des.description
|
||||
FROM pg_catalog.pg_type t
|
||||
LEFT OUTER JOIN pg_catalog.pg_type e ON e.oid=t.typelem
|
||||
LEFT OUTER JOIN pg_catalog.pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
|
||||
LEFT OUTER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = t.typnamespace
|
||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=t.oid AND des.classoid='pg_type'::regclass)
|
||||
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%' AND t.typnamespace = {{scid}}::oid
|
||||
{% if tid %}
|
||||
AND t.oid = {{tid}}::oid
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
SELECT
|
||||
db.oid as did, db.datname as name, ta.spcname as spcname, db.datallowconn,
|
||||
db.datistemplate AS is_template,
|
||||
pg_catalog.has_database_privilege(db.oid, 'CREATE') as cancreate, datdba as owner
|
||||
pg_catalog.has_database_privilege(db.oid, 'CREATE') as cancreate, datdba as owner,
|
||||
descr.description
|
||||
FROM
|
||||
pg_catalog.pg_database db
|
||||
LEFT OUTER JOIN pg_catalog.pg_tablespace ta ON db.dattablespace = ta.oid
|
||||
LEFT OUTER JOIN pg_catalog.pg_shdescription descr ON (
|
||||
db.oid=descr.objoid AND descr.classoid='pg_database'::regclass
|
||||
)
|
||||
WHERE {% if did %}
|
||||
db.oid = {{ did|qtLiteral(conn) }}::OID
|
||||
{% endif %}
|
||||
|
|
|
@ -209,7 +209,8 @@ SELECT EXISTS(
|
|||
sid,
|
||||
rset['rows'][0]['jobname'],
|
||||
"icon-pga_job" if rset['rows'][0]['jobenabled'] else
|
||||
"icon-pga_job-disabled"
|
||||
"icon-pga_job-disabled",
|
||||
description=rset['rows'][0]['jobdesc']
|
||||
),
|
||||
status=200
|
||||
)
|
||||
|
@ -222,7 +223,8 @@ SELECT EXISTS(
|
|||
sid,
|
||||
row['jobname'],
|
||||
"icon-pga_job" if row['jobenabled'] else
|
||||
"icon-pga_job-disabled"
|
||||
"icon-pga_job-disabled",
|
||||
description=row['jobdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -397,7 +399,8 @@ SELECT EXISTS(
|
|||
sid,
|
||||
row['jobname'],
|
||||
icon="icon-pga_job" if row['jobenabled']
|
||||
else "icon-pga_job-disabled"
|
||||
else "icon-pga_job-disabled",
|
||||
description=row['jobdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -265,7 +265,8 @@ class JobScheduleView(PGChildNodeView):
|
|||
row['jscname'],
|
||||
icon="icon-pga_schedule" if row['jscenabled'] else
|
||||
"icon-pga_schedule-disabled",
|
||||
enabled=row['jscenabled']
|
||||
enabled=row['jscenabled'],
|
||||
description=row['jscdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -277,7 +278,8 @@ class JobScheduleView(PGChildNodeView):
|
|||
row['jscname'],
|
||||
icon="icon-pga_schedule" if row['jscenabled'] else
|
||||
"icon-pga_schedule-disabled",
|
||||
enabled=row['jscenabled']
|
||||
enabled=row['jscenabled'],
|
||||
description=row['jscdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -455,7 +457,8 @@ class JobScheduleView(PGChildNodeView):
|
|||
row['jscname'],
|
||||
icon="icon-pga_schedule" if row['jscenabled'] else
|
||||
"icon-pga_schedule-disabled",
|
||||
enabled=row['jscenabled']
|
||||
enabled=row['jscenabled'],
|
||||
description=row['jscdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -280,7 +280,8 @@ SELECT EXISTS(
|
|||
icon="icon-pga_jobstep" if row['jstenabled'] else
|
||||
"icon-pga_jobstep-disabled",
|
||||
enabled=row['jstenabled'],
|
||||
kind=row['jstkind']
|
||||
kind=row['jstkind'],
|
||||
description=row['jstdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -293,7 +294,8 @@ SELECT EXISTS(
|
|||
icon="icon-pga_jobstep" if row['jstenabled'] else
|
||||
"icon-pga_jobstep-disabled",
|
||||
enabled=row['jstenabled'],
|
||||
kind=row['jstkind']
|
||||
kind=row['jstkind'],
|
||||
description=row['jstdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -478,7 +480,8 @@ SELECT EXISTS(
|
|||
jid,
|
||||
row['jstname'],
|
||||
icon="icon-pga_jobstep" if row['jstenabled']
|
||||
else "icon-pga_jobstep-disabled"
|
||||
else "icon-pga_jobstep-disabled",
|
||||
description=row['jstdesc']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SELECT
|
||||
jobid, jobname, jobenabled
|
||||
jobid, jobname, jobenabled, jobdesc
|
||||
FROM
|
||||
pgagent.pga_job
|
||||
{% if jid %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SELECT
|
||||
jstid, jstjobid, jstname, jstenabled, jstkind = 's'::bpchar AS jstkind
|
||||
jstid, jstjobid, jstname, jstenabled, jstkind = 's'::bpchar AS jstkind, jstdesc
|
||||
FROM
|
||||
pgagent.pga_jobstep
|
||||
WHERE
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
SELECT
|
||||
jscid, jscjobid, jscname, jscenabled
|
||||
jscid, jscjobid, jscname, jscenabled, jscdesc
|
||||
FROM
|
||||
pgagent.pga_schedule
|
||||
WHERE
|
||||
|
|
|
@ -741,7 +741,8 @@ rolmembership:{
|
|||
row['rolname'],
|
||||
'icon-role' if row['rolcanlogin'] else 'icon-group',
|
||||
can_login=row['rolcanlogin'],
|
||||
is_superuser=row['rolsuper']
|
||||
is_superuser=row['rolsuper'],
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1005,7 +1006,8 @@ rolmembership:{
|
|||
row['rolname'],
|
||||
'icon-role' if row['rolcanlogin'] else 'icon-group',
|
||||
can_login=row['rolcanlogin'],
|
||||
is_superuser=row['rolsuper']
|
||||
is_superuser=row['rolsuper'],
|
||||
description=row['description']
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
SELECT
|
||||
r.oid, r.rolname, r.rolcanlogin, r.rolsuper
|
||||
r.oid, r.rolname, r.rolcanlogin, r.rolsuper,
|
||||
pg_catalog.shobj_description(r.oid, 'pg_authid') AS description
|
||||
FROM
|
||||
pg_catalog.pg_roles r
|
||||
{% if rid %}
|
||||
|
|
|
@ -1384,12 +1384,8 @@ define('pgadmin.browser', [
|
|||
}
|
||||
if (this.new._id == _id) {
|
||||
// Found the current
|
||||
_.extend(this.d, {
|
||||
'_id': this.new._id,
|
||||
'_label': this.new._label,
|
||||
'label': this.new.label,
|
||||
});
|
||||
this.t.update(ctx.i, this.new);
|
||||
_.extend(this.d, this.new);
|
||||
this.t.update(ctx.i, this.d);
|
||||
this.t.setLabel(ctx.i, {label: this.new.label});
|
||||
this.t.addIcon(ctx.i, {icon: this.new.icon});
|
||||
this.t.setId(ctx.i, {id: this.new.id});
|
||||
|
@ -1632,11 +1628,8 @@ define('pgadmin.browser', [
|
|||
// If server icon/background changes then also we need to re-create it
|
||||
if ((
|
||||
_old._type == 'server' && _new._type == 'server' && (
|
||||
_old._pid != _new._pid ||
|
||||
_old._label != _new._label ||
|
||||
_old.icon != _new.icon
|
||||
)) || _old._pid != _new._pid || _old._label != _new._label ||
|
||||
_old._id != _new._id
|
||||
_old._pid != _new._pid || _old.icon != _new.icon
|
||||
)) || _old._pid != _new._pid || _old._id != _new._id
|
||||
) {
|
||||
ctx.op = 'RECREATE';
|
||||
traversePath();
|
||||
|
|
|
@ -833,7 +833,7 @@ define('pgadmin.browser.node', [
|
|||
background: ${bgcolor} !important;
|
||||
}
|
||||
${fgcolor ? `
|
||||
.${dynamic_class} span.file-name {
|
||||
.${dynamic_class} span.file-name, .${dynamic_class} span.file-name:hover, .${dynamic_class} span.file-name.pseudo-active {
|
||||
color: ${fgcolor} !important;
|
||||
}
|
||||
`:''}
|
||||
|
|
|
@ -53,8 +53,8 @@ samp,
|
|||
border-width: 1px;
|
||||
font-size: 1.15em;
|
||||
|
||||
color: $color-fg !important;
|
||||
border-color: $border-color !important;
|
||||
color: $color-fg;
|
||||
border-color: $border-color;
|
||||
background-color: $color-secondary;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ require.onResourceLoad = function (context, map, depMaps) {
|
|||
{% else %}
|
||||
<div id="dockerContainer" class="pg-docker pg-docker-native"></div>
|
||||
{% endif %}
|
||||
<div id="object-breadcrumbs"></div>
|
||||
|
||||
{% include 'browser/messages.html' %}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import React from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import MainMenuFactory from '../../browser/static/js/MainMenuFactory';
|
||||
import AppMenuBar from '../js/AppMenuBar';
|
||||
import ObjectBreadcrumbs from '../js/components/ObjectBreadcrumbs';
|
||||
import Theme from '../js/Theme';
|
||||
|
||||
define('app', [
|
||||
|
@ -52,6 +53,16 @@ define('app', [
|
|||
|
||||
const menuContainerEle = document.querySelector('#main-menu-container');
|
||||
if(menuContainerEle) {
|
||||
ReactDOM.render(<Theme><AppMenuBar /></Theme>, document.querySelector('#main-menu-container'));
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<AppMenuBar />
|
||||
</Theme>, menuContainerEle
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<ObjectBreadcrumbs pgAdmin={pgAdmin} />
|
||||
</Theme>, document.querySelector('#object-breadcrumbs')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import AccountTreeIcon from '@material-ui/icons/AccountTree';
|
||||
import CommentIcon from '@material-ui/icons/Comment';
|
||||
import ArrowForwardIosRoundedIcon from '@material-ui/icons/ArrowForwardIosRounded';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIsMounted } from '../custom_hooks';
|
||||
|
||||
const useStyles = makeStyles((theme)=>({
|
||||
root: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
width: 'auto',
|
||||
maxWidth: '99%',
|
||||
zIndex: 9999,
|
||||
padding: '0.25rem 0.5rem',
|
||||
fontSize: '0.95em',
|
||||
color: theme.palette.background.default,
|
||||
backgroundColor: theme.palette.text.primary,
|
||||
borderTopRightRadius: theme.shape.borderRadius,
|
||||
},
|
||||
row: {
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
},
|
||||
overflow: {
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
export default function ObjectBreadcrumbs({pgAdmin}) {
|
||||
const classes = useStyles();
|
||||
const checkIsMounted = useIsMounted();
|
||||
const [preferences, setPreferences] = useState({
|
||||
breadcrumbs_enable: false,
|
||||
breadcrumbs_show_comment: true,
|
||||
});
|
||||
const [objectData, setObjectData] = useState({
|
||||
path: null,
|
||||
description: null,
|
||||
});
|
||||
const onItemHover = (item, _data)=>{
|
||||
// if(!checkIsMounted) return;
|
||||
if(item && !_data?._type.startsWith('coll-')) {
|
||||
setObjectData({
|
||||
path: pgAdmin.Browser.tree.getNodeDisplayPath(item, false),
|
||||
description: item?._metadata?.data.description
|
||||
});
|
||||
} else {
|
||||
setObjectData({
|
||||
path: null,
|
||||
description: null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
const setPrefs = ()=>{
|
||||
if(!checkIsMounted()) return;
|
||||
let pref = pgAdmin.Browser.get_preferences_for_module('browser');
|
||||
setPreferences({
|
||||
breadcrumbs_enable: pref.breadcrumbs_enable,
|
||||
breadcrumbs_show_comment: pref.breadcrumbs_show_comment,
|
||||
});
|
||||
};
|
||||
let cacheIntervalId = setInterval(function() {
|
||||
if(pgAdmin.Browser.preference_version() > 0) {
|
||||
clearInterval(cacheIntervalId);
|
||||
setPrefs();
|
||||
}
|
||||
},0);
|
||||
|
||||
pgAdmin.Browser.onPreferencesChange('browser', function() {
|
||||
setPrefs();
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(()=>{
|
||||
if(preferences.breadcrumbs_enable) {
|
||||
pgAdmin.Browser.Events.on('pgadmin-browser:tree:hovered', onItemHover);
|
||||
}
|
||||
return ()=>{
|
||||
pgAdmin.Browser.Events.off('pgadmin-browser:tree:hovered', onItemHover);
|
||||
};
|
||||
}, [preferences.breadcrumbs_enable]);
|
||||
|
||||
if(!objectData.path) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<Box className={classes.root}>
|
||||
<div className={classes.row}>
|
||||
<AccountTreeIcon style={{height: '1rem', marginRight: '0.125rem'}} />
|
||||
<div className={classes.overflow}>
|
||||
{
|
||||
objectData.path?.reduce((res, item)=>(
|
||||
res.concat(<span key={item}>{item}</span>, <ArrowForwardIosRoundedIcon key={item+'-arrow'} style={{height: '0.8rem', width: '1.25rem'}} />)
|
||||
), []).slice(0, -1)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{preferences.breadcrumbs_show_comment && objectData.description &&
|
||||
<div className={classes.row}>
|
||||
<CommentIcon style={{height: '1rem', marginRight: '0.125rem'}} />
|
||||
<div className={classes.overflow}>{objectData.description}</div>
|
||||
</div>}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ObjectBreadcrumbs.propTypes = {
|
||||
pgAdmin: PropTypes.object,
|
||||
};
|
|
@ -18,6 +18,9 @@ interface IItemRendererXProps {
|
|||
decorations: ClasslistComposite
|
||||
onClick: (ev: React.MouseEvent, item: FileEntry | Directory, type: ItemType) => void
|
||||
onContextMenu: (ev: React.MouseEvent, item: FileEntry | Directory) => void
|
||||
onMouseEnter: (ev: React.MouseEvent, item: FileEntry | Directory) => void
|
||||
onMouseLeave: (ev: React.MouseEvent, item: FileEntry | Directory) => void
|
||||
onItemHovered: (ev: React.MouseEvent, item: FileEntry | Directory, type: ItemType) => void
|
||||
events: Notificar<FileTreeXEvent>
|
||||
}
|
||||
|
||||
|
@ -81,6 +84,8 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
onClick={this.handleClick}
|
||||
onDoubleClick={this.handleDoubleClick}
|
||||
onDragStart={this.handleDragStartItem}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
// required for rendering context menus when opened through context menu button on keyboard
|
||||
ref={this.handleDivRef}
|
||||
draggable={true}>
|
||||
|
@ -166,6 +171,20 @@ export class FileTreeItem extends React.Component<IItemRendererXProps & IItemRen
|
|||
}
|
||||
};
|
||||
|
||||
private handleMouseEnter = (ev: React.MouseEvent) => {
|
||||
const { item, itemType, onMouseEnter } = this.props;
|
||||
if (itemType === ItemType.File || itemType === ItemType.Directory) {
|
||||
onMouseEnter?.(ev, item as FileEntry);
|
||||
}
|
||||
};
|
||||
|
||||
private handleMouseLeave = (ev: React.MouseEvent) => {
|
||||
const { item, itemType, onMouseLeave } = this.props;
|
||||
if (itemType === ItemType.File || itemType === ItemType.Directory) {
|
||||
onMouseLeave?.(ev, item as FileEntry);
|
||||
}
|
||||
};
|
||||
|
||||
private handleDragStartItem = (e: React.DragEvent) => {
|
||||
const { item, itemType, events } = this.props;
|
||||
if (itemType === ItemType.File || itemType === ItemType.Directory) {
|
||||
|
|
|
@ -29,6 +29,8 @@ export class FileTreeX extends React.Component<IFileTreeXProps> {
|
|||
private disposables: DisposablesComposite;
|
||||
private keyboardHotkeys: KeyboardHotkeys;
|
||||
private fileTreeEvent: IFileTreeXTriggerEvents;
|
||||
private hoverTimeoutId: React.RefObject<number|null> = React.createRef<number|null>();
|
||||
private hoverDispatchId: React.RefObject<number|null> = React.createRef<number|null>();
|
||||
constructor(props: IFileTreeXProps) {
|
||||
super(props);
|
||||
this.events = new Notificar();
|
||||
|
@ -73,6 +75,8 @@ export class FileTreeX extends React.Component<IFileTreeXProps> {
|
|||
onClick={this.handleItemClicked}
|
||||
onDoubleClick={this.handleItemDoubleClicked}
|
||||
onContextMenu={this.handleItemCtxMenu}
|
||||
onMouseEnter={this.onItemMouseEnter}
|
||||
onMouseLeave={this.onItemMouseLeave}
|
||||
changeDirectoryCount={this.changeDirectoryCount}
|
||||
events={this.events}/>}
|
||||
</FileTree>
|
||||
|
@ -166,6 +170,22 @@ export class FileTreeX extends React.Component<IFileTreeXProps> {
|
|||
}
|
||||
};
|
||||
|
||||
private onItemMouseEnter = (ev: React.MouseEvent, item: FileEntry | Directory) => {
|
||||
clearTimeout(this.hoverDispatchId.current??undefined);
|
||||
(this.hoverDispatchId as any).current = setTimeout(()=>{
|
||||
clearTimeout(this.hoverTimeoutId.current??undefined);
|
||||
this.events.dispatch(FileTreeXEvent.onTreeEvents, ev, 'hovered', item);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
private onItemMouseLeave = (ev: React.MouseEvent) => {
|
||||
clearTimeout(this.hoverTimeoutId.current??undefined);
|
||||
clearTimeout(this.hoverDispatchId.current??undefined);
|
||||
(this.hoverTimeoutId as any).current = setTimeout(()=>{
|
||||
this.events.dispatch(FileTreeXEvent.onTreeEvents, ev, 'hovered', null);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
private setActiveFile = async (fileOrDirOrPath: FileOrDir | string, ensureVisible, align): Promise<void> => {
|
||||
const fileH = typeof fileOrDirOrPath === 'string'
|
||||
? await this.fileTreeHandle.getFileHandle(fileOrDirOrPath)
|
||||
|
|
|
@ -171,7 +171,7 @@
|
|||
|
||||
&:hover,
|
||||
&.pseudo-active {
|
||||
color: $tree-fg-hover !important;
|
||||
color: $tree-fg-hover;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,14 +184,14 @@
|
|||
font: inherit;
|
||||
flex-grow: 1;
|
||||
user-select: none;
|
||||
color: $tree-text-fg !important;
|
||||
color: $tree-text-fg;
|
||||
margin-left: 3px;
|
||||
cursor: pointer !important;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover,
|
||||
&.pseudo-active {
|
||||
color: $tree-fg-hover !important;
|
||||
color: $tree-fg-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,7 @@
|
|||
flex-grow: 1;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
color: #c1c1c1;
|
||||
color: $color-fg;
|
||||
margin-left: 3px;
|
||||
|
||||
& input[type='text'] {
|
||||
|
|
|
@ -29,6 +29,16 @@ function manageTreeEvents(event, eventName, item) {
|
|||
console.warn(e.stack || e);
|
||||
return false;
|
||||
}
|
||||
} else if(eventName == 'hovered') {
|
||||
/* Raise tree events for the nodes */
|
||||
try {
|
||||
obj.Events.trigger(
|
||||
'pgadmin-browser:tree:' + eventName, item, d, node
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Events for browser tree.
|
||||
if (d && obj.Nodes[d._type]) {
|
||||
|
@ -384,6 +394,23 @@ export class Tree {
|
|||
})(tree.tree.getModel().root);
|
||||
}
|
||||
|
||||
getNodeDisplayPath(item, separator='/', skip_coll=false) {
|
||||
let retStack = [];
|
||||
let currItem = item;
|
||||
while(currItem?.fileName) {
|
||||
const data = currItem._metadata?.data;
|
||||
if(data._type.startsWith('coll-') && skip_coll) {
|
||||
/* Skip collection */
|
||||
} else {
|
||||
retStack.push(data._label);
|
||||
}
|
||||
currItem = currItem.parent;
|
||||
}
|
||||
retStack = retStack.reverse();
|
||||
if(separator == false) return retStack;
|
||||
return retStack.join(separator);
|
||||
}
|
||||
|
||||
findNodeByDomElement(domElement) {
|
||||
const path = domElement.path;
|
||||
if (!path || !path[0]) {
|
||||
|
|
|
@ -305,6 +305,9 @@ $card-header-fg: $color-fg !default;
|
|||
$card-header-border-color: $border-color !default;
|
||||
$no-border-radius: 0px !important;
|
||||
|
||||
$tooltip-color: $color-bg;
|
||||
$tooltip-bg: $color-fg;
|
||||
|
||||
$btn-checkbox-padding: $input-btn-padding-y $input-btn-padding-x;
|
||||
|
||||
$scrollbar-base-color: #bac1cd !default;
|
||||
|
|
|
@ -18,6 +18,7 @@ MIMETYPE_APP_JSON = 'application/json'
|
|||
# Preference labels
|
||||
PREF_LABEL_KEYBOARD_SHORTCUTS = gettext('Keyboard shortcuts')
|
||||
PREF_LABEL_DISPLAY = gettext('Display')
|
||||
PREF_LABEL_BREADCRUMBS = gettext('Object Breadcrumbs')
|
||||
PREF_LABEL_OPTIONS = gettext('Options')
|
||||
PREF_LABEL_EXPLAIN = gettext('Explain')
|
||||
PREF_LABEL_EDITOR = gettext('Editor')
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2023, 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 { withTheme } from '../fake_theme';
|
||||
import { createMount } from '@material-ui/core/test-utils';
|
||||
import ObjectBreadcrumbs from '../../../pgadmin/static/js/components/ObjectBreadcrumbs';
|
||||
import EventBus from '../../../pgadmin/static/js/helpers/EventBus';
|
||||
|
||||
const pgAdmin = {
|
||||
Browser: {
|
||||
Events: new EventBus(),
|
||||
get_preferences_for_module: function() {
|
||||
return {
|
||||
breadcrumbs_enable: true,
|
||||
breadcrumbs_show_comment: true,
|
||||
};
|
||||
},
|
||||
preference_version: ()=>123,
|
||||
onPreferencesChange: ()=>{/*This is intentional (SonarQube)*/},
|
||||
tree: {
|
||||
getNodeDisplayPath: jasmine.createSpy('getNodeDisplayPath').and.returnValue(['server', 'object']),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
describe('ObjectBreadcrumbs', ()=>{
|
||||
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();
|
||||
});
|
||||
|
||||
it('not hovered', (done)=>{
|
||||
let ThemedObjectBreadcrumbs = withTheme(ObjectBreadcrumbs);
|
||||
let ctrl = mount(<ThemedObjectBreadcrumbs pgAdmin={pgAdmin} />);
|
||||
setTimeout(()=>{
|
||||
ctrl.update();
|
||||
expect(ctrl.find('ForwardRef(AccountTreeIcon)').length).toBe(0);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('hovered object with comment', (done)=>{
|
||||
let ThemedObjectBreadcrumbs = withTheme(ObjectBreadcrumbs);
|
||||
let ctrl = mount(<ThemedObjectBreadcrumbs pgAdmin={pgAdmin} />);
|
||||
setTimeout(()=>{
|
||||
ctrl.update();
|
||||
pgAdmin.Browser.Events.trigger('pgadmin-browser:tree:hovered', {
|
||||
_metadata: {
|
||||
data: {
|
||||
description: 'some description'
|
||||
}
|
||||
},
|
||||
}, {
|
||||
_type: 'object',
|
||||
});
|
||||
setTimeout(()=>{
|
||||
ctrl.update();
|
||||
expect(ctrl.find('ForwardRef(AccountTreeIcon)').length).toBe(1);
|
||||
expect(ctrl.find('ForwardRef(CommentIcon)').length).toBe(1);
|
||||
done();
|
||||
}, 500);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
it('hovered object with no comment', (done)=>{
|
||||
let ThemedObjectBreadcrumbs = withTheme(ObjectBreadcrumbs);
|
||||
let ctrl = mount(<ThemedObjectBreadcrumbs pgAdmin={pgAdmin} />);
|
||||
setTimeout(()=>{
|
||||
ctrl.update();
|
||||
pgAdmin.Browser.Events.trigger('pgadmin-browser:tree:hovered', {
|
||||
_metadata: {
|
||||
data: {}
|
||||
},
|
||||
}, {
|
||||
_type: 'object',
|
||||
});
|
||||
setTimeout(()=>{
|
||||
ctrl.update();
|
||||
expect(ctrl.find('ForwardRef(AccountTreeIcon)').length).toBe(1);
|
||||
expect(ctrl.find('ForwardRef(CommentIcon)').length).toBe(0);
|
||||
done();
|
||||
}, 500);
|
||||
}, 500);
|
||||
});
|
||||
});
|
|
@ -8368,20 +8368,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jasmine-core@npm:3.10.1":
|
||||
"jasmine-core@npm:3.10.1, jasmine-core@npm:^3.6.0":
|
||||
version: 3.10.1
|
||||
resolution: "jasmine-core@npm:3.10.1"
|
||||
checksum: 77ee26aaf29576e982a2ebe6586218ff4d7cc4305ad18c400954bbdeb3c7987e9a4a8ac6d6548b65838852f325395fc901d69bf8c24bdccfbd67b263fbf5d4fd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jasmine-core@npm:^3.6.0":
|
||||
version: 3.99.1
|
||||
resolution: "jasmine-core@npm:3.99.1"
|
||||
checksum: 4e4a89739d99e471b86c7ccc4c5c244a77cc6d1e17b2b0d87d81266b8415697354d8873f7e764790a10661744f73a753a6e9bcd9b3e48c66a0c9b8a092b071b7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jasmine-enzyme@npm:^7.1.2":
|
||||
version: 7.1.2
|
||||
resolution: "jasmine-enzyme@npm:7.1.2"
|
||||
|
|