mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-28 19:43:51 -06:00
751f8383fa
The File menu now includes a "Create" submenu, and Delete/Rename options. Nodes can offer Delete/Rename functionality, and the options on the menu are automatically enabled/disabled based on the selected node. Each node can also offer Create functionality, and specify a list of node types (including itself) from which the option should be made available. The menu is dynamically generated based on the selected node. The Context menu on the treeview works in a similar way, except that nodes can offer any context menu items (we don't allow this on the top menu, as that should stay consistent to avoid user confusion).
164 lines
7.0 KiB
ReStructuredText
164 lines
7.0 KiB
ReStructuredText
Code Overview
|
|
=============
|
|
|
|
The bulk of pgAdmin is a Python web application written using the Flask framework
|
|
on the backend, and HTML5 with CSS3, Bootstrap and jQuery on the front end. A
|
|
desktop runtime is also included for users that prefer a desktop application to
|
|
a web application, which is written in C++ using the QT framework.
|
|
|
|
Runtime
|
|
-------
|
|
|
|
The runtime is essentially a Python webserver and browser in a box. Found in the
|
|
**/runtime** directory in the source tree, it is a relatively simple QT
|
|
application that is most easily modified using the **QT Creator** application.
|
|
|
|
Web Application
|
|
---------------
|
|
|
|
The web application forms the bulk of pgAdmin and can be found in the **/web**
|
|
directory in the source tree. The main file is **pgAdmin4.py** which can be used
|
|
to run the built-in standalone web server, or as a WSGI application for production
|
|
use.
|
|
|
|
Configuration
|
|
*************
|
|
|
|
The core application configuration is found in **config.py**. This file includes
|
|
all configurable settings for the application, along with descriptions of their
|
|
use. It is essential that various settings are configured prior to deployent on
|
|
a web server; these can be overriden in **config_local.py** to avoid modifying
|
|
the main configuration file.
|
|
|
|
User Settings
|
|
*************
|
|
|
|
When running in desktop mode, pgAdmin has a single, default user account that is
|
|
used for the desktop user. When running in server mode, there may be unlimited
|
|
users who are required to login prior to using the application. pgAdmin utilised
|
|
the **Flask-Security** module to manage application security and users, and
|
|
provides options for self-service password reset and password changes etc.
|
|
|
|
Whether in desktop or server mode, each user's settings are stored in a SQLite
|
|
database which is also used to store the user accounts. This is initially
|
|
created using the **setup.py** script which will create the database file and
|
|
schema within it, and add the first user account (with administrative
|
|
privileges) and a default server group for them. A **settings** table is also
|
|
used to store user configuration settings in a key-value fashion. Although not
|
|
required, setting keys (or names) are typically formatted using forward slashes
|
|
to artificially namespace values, much like the pgAdmin 3 settings files on Linux
|
|
or Mac.
|
|
|
|
Note that the local configuration must be setup prior to **setup.py** being run.
|
|
The local configuration will determine how the script sets up the database,
|
|
particularly with regard to desktop vs. server mode.
|
|
|
|
pgAdmin Core
|
|
************
|
|
|
|
The heart of pgAdmin is the **pgadmin** package. This contains the globally
|
|
available HTML templates used by the Jinja engine, as well as any global static
|
|
files such as images, Javascript and CSS files that are used in multiple modules.
|
|
|
|
The work of the package is handled in it's constructor, **__init__.py**. This
|
|
is responsible for setting up logging and authentication, dynamically loading
|
|
other modules, and a few other tasks.
|
|
|
|
Modules
|
|
*******
|
|
|
|
Units of functionality are added to pgAdmin through the addition of modules. Theses
|
|
are Python packages that implement Flask Blueprints, and provide various hook
|
|
points for other modules to utilise (primarily the default module - the browser).
|
|
|
|
To be recognised as a module, a Python package must be created. This must:
|
|
|
|
1) Be placed within the **web/pgadmin/** directory, and
|
|
2) Contain a Python module called **views**, and
|
|
3) Contain within the views module, a **blueprint** variable representing the
|
|
Flask Blueprint
|
|
|
|
Each module may define a **template** and **static** directory for the Blueprint
|
|
that it implements. To avoid name collisions, templates should be stored under
|
|
a directory within the specified template directory, named after the module itself.
|
|
For example, the **browser** module stores it's templates in
|
|
**web/pgadmin/browser/templates/browser/**. This does not apply to static files
|
|
which may omit the second module name.
|
|
|
|
In addition to defining the Blueprint, the **views** module is typically
|
|
responsible for defining all the views that will be rendered in response to
|
|
client requests. These must include appropriate route and security decorators.
|
|
|
|
Most pgAdmin modules will also implement a **hooks** Python module. This is
|
|
responsible for providing hook points to integrate the module into the rest of
|
|
the application - for example, a hook might tell the caller what CSS files need
|
|
to be included on the rendered page, or what menu options to include and what
|
|
they should do. Hook points need not exist if they are not required. It is the
|
|
responsiblity of the caller to ensure they are present before attempting to
|
|
utilise them.
|
|
|
|
Hooks currently implemented are:
|
|
|
|
.. code-block:: python
|
|
|
|
def register_submodules(app):
|
|
"""Register any child module or node blueprints"""
|
|
|
|
def get_file_menu_items():
|
|
def get_edit_menu_items():
|
|
def get_tools_menu_items():
|
|
def get_management_menu_items():
|
|
def get_help_menu_items():
|
|
"""Return a (set) of dicts of menu items, with name, priority, URL, target and onclick code."""
|
|
|
|
def get_scripts():
|
|
"""Return a list of script URLs to include in the rendered page header"""
|
|
|
|
def get_stylesheets():
|
|
"""Return a list of stylesheet URLs to include in the rendered page header"""
|
|
|
|
pgAdmin Modules may include any additional Python modules that are required to
|
|
fulfill their purpose, as required. They may also reference other dynamically
|
|
loaded modules, but must use the defined hook points and fail gracefully in the
|
|
event that a particular module is not present.
|
|
|
|
Nodes
|
|
*****
|
|
|
|
Nodes are very similar to modules, but implement individual nodes on the browser
|
|
treeview. To be recognised as a module, a Python package must be created. This
|
|
must:
|
|
|
|
1) Be placed within the **web/pgadmin/browser/** directory, and
|
|
2) Contain a Python module called **views**, and
|
|
3) Contain within the views module, a **blueprint** variable representing the
|
|
Flask Blueprint
|
|
|
|
The hook points currently defined for nodes are:
|
|
|
|
.. code-block:: python
|
|
|
|
def register_submodules(app):
|
|
"""Register any child node blueprints"""
|
|
|
|
def get_file_menu_items():
|
|
"""Return a (set) of dicts of menu items, with name, priority, URL, target and onclick code."""
|
|
|
|
def get_context_menu_items():
|
|
"""Return a (set) of dicts of content menu items with name, label, priority and JS"""
|
|
|
|
def get_create_menu_items():
|
|
"""Return a (set) of dicts of create menu items, with a Javascript array of
|
|
object types on which the option should appear, name, label. priority and
|
|
the function name (no parens) to call on click."""
|
|
|
|
def get_standard_menu_items():
|
|
"""Return a (set) of dicts of standard menu items (drop/rename), with
|
|
object type, action, priority and the function name (no parens) to call
|
|
on click."""
|
|
|
|
def get_script_snippets():
|
|
"""Return the script snippets needed to handle treeview node operations."""
|
|
|
|
def get_css_snippets():
|
|
"""Return the CSS needed to display the treeview node image.""" |