From 39089cca2143d5a72d95148c4a2d0f3a04c40b04 Mon Sep 17 00:00:00 2001 From: Dave Page Date: Mon, 23 Feb 2015 10:51:47 +0000 Subject: [PATCH] Add a Sphinx based help system, and include some initial docs on development. --- docs/en_US/Makefile.sphinx | 130 +++++++++++ docs/en_US/browser.rst | 5 + docs/en_US/code-overview.rst | 154 ++++++++++++ docs/en_US/coding-standards.rst | 187 +++++++++++++++ docs/en_US/conf.py | 219 ++++++++++++++++++ docs/en_US/debugger.rst | 4 + docs/en_US/images/logo-128.png | Bin 0 -> 22429 bytes docs/en_US/images/logo-right-128.png | Bin 0 -> 22418 bytes docs/en_US/index.rst | 96 ++++++++ docs/en_US/query-tool.rst | 5 + docs/en_US/submitting-patches.rst | 31 +++ web/config.py | 3 + web/pgadmin/about/hooks.py | 6 +- web/pgadmin/browser/nodes/CollectionNode.py | 14 ++ web/pgadmin/browser/nodes/ObjectNode.py | 15 ++ .../browser/nodes/server_groups/hooks.py | 3 +- .../browser/templates/browser/index.html | 10 +- web/pgadmin/help/__init__.py | 0 web/pgadmin/help/hooks.py | 23 ++ web/pgadmin/help/views.py | 22 ++ web/pgadmin/test/hooks.py | 3 +- 21 files changed, 920 insertions(+), 10 deletions(-) create mode 100644 docs/en_US/Makefile.sphinx create mode 100644 docs/en_US/browser.rst create mode 100644 docs/en_US/code-overview.rst create mode 100644 docs/en_US/coding-standards.rst create mode 100644 docs/en_US/conf.py create mode 100644 docs/en_US/debugger.rst create mode 100644 docs/en_US/images/logo-128.png create mode 100644 docs/en_US/images/logo-right-128.png create mode 100644 docs/en_US/index.rst create mode 100644 docs/en_US/query-tool.rst create mode 100644 docs/en_US/submitting-patches.rst create mode 100644 web/pgadmin/browser/nodes/CollectionNode.py create mode 100644 web/pgadmin/browser/nodes/ObjectNode.py create mode 100644 web/pgadmin/help/__init__.py create mode 100644 web/pgadmin/help/hooks.py create mode 100644 web/pgadmin/help/views.py diff --git a/docs/en_US/Makefile.sphinx b/docs/en_US/Makefile.sphinx new file mode 100644 index 000000000..5e3f3b137 --- /dev/null +++ b/docs/en_US/Makefile.sphinx @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pgAdminIII.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pgAdminIII.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/pgAdminIII" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pgAdminIII" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/en_US/browser.rst b/docs/en_US/browser.rst new file mode 100644 index 000000000..c047371e6 --- /dev/null +++ b/docs/en_US/browser.rst @@ -0,0 +1,5 @@ +Browser +======= + +The Browser is the main window used in pgAdmin. It allows you to connect to +database servers and browse the objects on them. \ No newline at end of file diff --git a/docs/en_US/code-overview.rst b/docs/en_US/code-overview.rst new file mode 100644 index 000000000..0e91eccac --- /dev/null +++ b/docs/en_US/code-overview.rst @@ -0,0 +1,154 @@ +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_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.""" \ No newline at end of file diff --git a/docs/en_US/coding-standards.rst b/docs/en_US/coding-standards.rst new file mode 100644 index 000000000..021184fec --- /dev/null +++ b/docs/en_US/coding-standards.rst @@ -0,0 +1,187 @@ +Coding Standards +================ + +pgAdmin uses multiple technologies and multiple languages, each of which have +their own coding standards. + +General +------- + +In all languages, indentations should be made with 4 spaces, and excessively long +lines wrapped where appropriate to ensure they can be read on smaller displays +(80 characters is used in many places, but this is not a required maximum size +as it's quite wasteful on modern displays). Typically lines should not be longer +than 120 characters. + +Comments should be included in all code where required to explain its +purpose or how it works if not obvious from a quick review of the code itself. + +CSS 3 +----- + +CSS3 is used for styling and layout throughout the application. Extensive use is +made of the Bootstrap Framework to aid in that process, however additional +styles must still be created from time to time. + +Most custom styling comes from individual modules which may advertise static +stylesheets to be included in the module that is loading them via hooks. + +Styling overrides (for example, to alter the Bootstrap look and feel) will +typically be found in the **overrides.css** file in the main static file +directory for the application. + +Styling should never be applied inline in HTML, always through an external +stylesheet, which should contain comments as appropriate to explain the usage +or purpose for the style. + +Styles should be specified clearly, one per line. For example: + +.. code-block:: css + + /* iFrames should have no border */ + iframe { + border-width: 0; + } + + /* Ensure the codemirror editor displays full height gutters when resized */ + .CodeMirror, .CodeMirror-gutters { + height: 100% !important; + } + +All stylesheets must be CSS3 compliant. + +HTML 5 +------ + +HTML 5 is used for page structure throughout the application, in most cases +being rendered from templates by the Jinja2 template engine in Flask. + +All HTML must be HTML 5 compliant. + +Javascript +---------- + +Client-side code is written in Javascript using jQuery and various plugins. +Whilst much of the code is rendered from static files, there is also code that +is rendered from templates using Jinja2 (often to inject the users settings) or +constructed on the fly from module hooks. + +A typical Javascript function might be formatted like this (this snipped is from +a template): + +.. code-block:: javascript + + // Delete a server group + function delete_server_group(item) { + alertify.confirm( + 'Delete server group?', + 'Are you sure you wish to delete the server group "{0}"?'.replace('{0}', tree.getLabel(item)), + function() { + var id = tree.getId(item) + $.post("{{ url_for('NODE-server-group.delete') }}", { id: id }) + .done(function(data) { + if (data.success == 0) { + report_error(data.errormsg, data.info); + } else { + var next = tree.next(item); + var prev = tree.prev(item); + tree.remove(item); + if (next.length) { + tree.select(next); + } else if (prev.length) { + tree.select(prev); + } + } + } + ) + }, + null + ) + } + +Note the use of a descriptive function name, using the underscore character to +separate words in all lower case, and short but descriptive lower case variable +names. + +C++ +--- + +C++ code is used in the desktop runtime for the application, primarily with the +QT framework and an embedded Python interpreter. Note the use of hanging braces, +which may be omitted if on a single statement is present: + +.. code-block:: c++ + + // Ping the application server to see if it's alive + bool PingServer(QUrl url) + { + QNetworkAccessManager manager; + QEventLoop loop; + QNetworkReply *reply; + QVariant redirectUrl; + + url.setPath("/utils/ping"); + + do + { + reply = manager.get(QNetworkRequest(url)); + + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + url = redirectUrl.toUrl(); + + if (!redirectUrl.isNull()) + delete reply; + + } while (!redirectUrl.isNull()); + + if (reply->error() != QNetworkReply::NoError) + return false; + + QString response = reply->readAll(); + + if (response != "PING") + { + qDebug() << "Failed to connect, server response: " << response; + return false; + } + + return true; + } + +Python +------ + +Python is used for the backend web server. All code must be compatible with +Python 2.7 and should include PyDoc comments whilst following the official +Python coding standards. An example function along with the file header is +shown below:: + + ########################################################################## + # + # pgAdmin 4 - PostgreSQL Tools + # + # Copyright (C) 2013 - 2015, The pgAdmin Development Team + # This software is released under the PostgreSQL Licence + # + ########################################################################## + + """Integration hooks for server groups.""" + + from flask import render_template, url_for + from flask.ext.security import current_user + + from pgadmin.settings.settings_model import db, ServerGroup + + def get_nodes(): + """Return a JSON document listing the server groups for the user""" + groups = ServerGroup.query.filter_by(user_id=current_user.id) + + value = '' + for group in groups: + value += '{"id":%d,"label":"%s","icon":"icon-server-group","inode":true},' % (group.id, group.name) + value = value[:-1] + + return value \ No newline at end of file diff --git a/docs/en_US/conf.py b/docs/en_US/conf.py new file mode 100644 index 000000000..0eb95e392 --- /dev/null +++ b/docs/en_US/conf.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- +# +# pgAdmin III documentation build configuration file, created by +# sphinx-quickstart on Sat Jul 9 15:58:11 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'pgAdmin 4' +copyright = u'2013 - 2015, The pgAdmin Development Team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0.0-dev' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['images'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} +html_sidebars = { + '**': ['localtoc.html', 'globaltoc.html', 'searchbox.html'] +} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pgadmin4' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'pgadmin4.tex', u'pgAdmin 4 Documentation', + u'The pgAdmin Development Team', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'pgadmin4', u'pgAdmin 4 Documentation', + [u'The pgAdmin Development Team'], 1) +] diff --git a/docs/en_US/debugger.rst b/docs/en_US/debugger.rst new file mode 100644 index 000000000..68e1917f0 --- /dev/null +++ b/docs/en_US/debugger.rst @@ -0,0 +1,4 @@ +Debugger +======== + +The Debugger allows you to debug PL/PGSQL functions interactively. \ No newline at end of file diff --git a/docs/en_US/images/logo-128.png b/docs/en_US/images/logo-128.png new file mode 100644 index 0000000000000000000000000000000000000000..af43ced3ac9be9220d1636a5d77b2f703d93dcf1 GIT binary patch literal 22429 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 literal 0 HcmV?d00001 diff --git a/docs/en_US/images/logo-right-128.png b/docs/en_US/images/logo-right-128.png new file mode 100644 index 0000000000000000000000000000000000000000..830523509cd8de11cbe6315c246fa15a6c8f96b2 GIT binary patch literal 22418 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, and +downloads are hosted on the +`PostgreSQL Website `_. + +******* +Licence +******* + +pgAdmin is released under the +`PostgreSQL Licence `_, which is a +liberal Open Source licence similar to BSD or MIT, and approved by the Open +Source Initiative. The copyright for the project source code, website and +documentation is attributed to the +`pgAdmin Development Team `_. \ No newline at end of file diff --git a/docs/en_US/query-tool.rst b/docs/en_US/query-tool.rst new file mode 100644 index 000000000..f2619c83a --- /dev/null +++ b/docs/en_US/query-tool.rst @@ -0,0 +1,5 @@ +Query Tool +========== + +The Query Tool allows you to compose and execute arbitrary SQL statements and +view the results. \ No newline at end of file diff --git a/docs/en_US/submitting-patches.rst b/docs/en_US/submitting-patches.rst new file mode 100644 index 000000000..7e6bbb610 --- /dev/null +++ b/docs/en_US/submitting-patches.rst @@ -0,0 +1,31 @@ +Submitting Patches +================== + +Before developing a patch for pgAdmin you should always contact the developers +on the `mailing list ` to discuss your +plans. This ensures that others know if you're fixing a bug and can then avoid +duplicating your work, and in the case of large patches, gives the community +the chance to discuss and refine your ideas before investing too much time +writing code that may later be rejected. + +You should always develop patches against a checkout of the source code from the +GIT source code repository, and not a release tarball. This ensures that you're +working with the latest code on the branch and makes it easier to generate +patches correctly. You can checkout the source code with a command like:: + + $ git clone git://git.postgresql.org/git/pgadmin4.git + +Once you've made the changes you wish to make, commit them to a private +development branch in your local repository. Then create a patch containing the +changes in your development branch against the upstream branch on which your +work is based. For example, if your current branch contains your changes, you +might run:: + + $ git diff origin/master > my_cool_feature.diff + +to create a patch between your development branch and the public master branch. + +Once you have your patch, mail it to the +`mailing list `. Please ensure you +include a full description of what the patch does, as well as the rationale for +any important design decisions. \ No newline at end of file diff --git a/web/config.py b/web/config.py index 5dcfc80c9..445f49c09 100644 --- a/web/config.py +++ b/web/config.py @@ -31,6 +31,9 @@ APP_SUFFIX = 'dev' # Copyright string for display in the app APP_COPYRIGHT = 'Copyright 2014 - 2015, The pgAdmin Development Team' +# Path to the online help. +HELP_PATH = '../../../docs/en_US/_build/html/' + # DO NOT CHANGE! # The application version string, constructed from the components APP_VERSION = '%s.%s.%s-%s' % (APP_MAJOR, APP_MINOR, APP_REVISION, APP_SUFFIX) diff --git a/web/pgadmin/about/hooks.py b/web/pgadmin/about/hooks.py index 7d7048aaf..8cf728c32 100644 --- a/web/pgadmin/about/hooks.py +++ b/web/pgadmin/about/hooks.py @@ -2,7 +2,7 @@ # # pgAdmin 4 - PostgreSQL Tools # -# Copyright (C) 2013 - 2014, The pgAdmin Development Team +# Copyright (C) 2013 - 2015, The pgAdmin Development Team # This software is released under the PostgreSQL Licence # ########################################################################## @@ -14,8 +14,8 @@ from flask import render_template, url_for import config def get_help_menu_items(): - """Return a (set) of dicts of help menu items, with name, priority, URL and - onclick code.""" + """Return a (set) of dicts of help menu items, with name, priority, URL, + target and onclick code.""" return [{'name': 'mnu_about', 'label': 'About %s' % (config.APP_NAME), 'priority': 999, diff --git a/web/pgadmin/browser/nodes/CollectionNode.py b/web/pgadmin/browser/nodes/CollectionNode.py new file mode 100644 index 000000000..ae0cc7c9c --- /dev/null +++ b/web/pgadmin/browser/nodes/CollectionNode.py @@ -0,0 +1,14 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Base class for Collection Nodes on the browser treeview""" + +def get_name(): + """Returns the display name of the collection""" + return "" \ No newline at end of file diff --git a/web/pgadmin/browser/nodes/ObjectNode.py b/web/pgadmin/browser/nodes/ObjectNode.py new file mode 100644 index 000000000..0212fee7b --- /dev/null +++ b/web/pgadmin/browser/nodes/ObjectNode.py @@ -0,0 +1,15 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Base class for Object Nodes on the browser treeview""" + +def get_name(): + """Returns the object's name""" + return "" + diff --git a/web/pgadmin/browser/nodes/server_groups/hooks.py b/web/pgadmin/browser/nodes/server_groups/hooks.py index e427a1b6d..a1095c46e 100644 --- a/web/pgadmin/browser/nodes/server_groups/hooks.py +++ b/web/pgadmin/browser/nodes/server_groups/hooks.py @@ -27,7 +27,8 @@ def get_nodes(): def get_file_menu_items(): - """Return a (set) of dicts of file menu items, with name, label, priority and URL.""" + """Return a (set) of dicts of file menu items, with name, priority, URL, + target and onclick code.""" return [ {'name': 'mnu_add_server_group', 'label': 'Add a server group...', 'priority': 10, 'url': '#', 'onclick': 'add_server_group()'}, {'name': 'mnu_delete_server_group', 'label': 'Delete server group', 'priority': 20, 'url': '#', 'onclick': 'delete_server_group()'}, diff --git a/web/pgadmin/browser/templates/browser/index.html b/web/pgadmin/browser/templates/browser/index.html index 3a638484f..b93a736f8 100644 --- a/web/pgadmin/browser/templates/browser/index.html +++ b/web/pgadmin/browser/templates/browser/index.html @@ -20,35 +20,35 @@ {% if file_items is defined and file_items|count > 0 %}{% endif %} {% if edit_items is defined and edit_items|count > 0 %}{% endif %} {% if tools_items is defined and tools_items|count > 0 %}{% endif %} {% if management_items is defined and management_items|count > 0 %}{% endif %} {% if help_items is defined and help_items|count > 0 %}{% endif %} diff --git a/web/pgadmin/help/__init__.py b/web/pgadmin/help/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/web/pgadmin/help/hooks.py b/web/pgadmin/help/hooks.py new file mode 100644 index 000000000..3d73561d3 --- /dev/null +++ b/web/pgadmin/help/hooks.py @@ -0,0 +1,23 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Browser integration functions for the Help module.""" + +from flask import url_for + +import config + +def get_help_menu_items(): + """Return a (set) of dicts of help menu items, with name, priority, URL, + target and onclick code.""" + return [{'name': 'mnu_contents', + 'label': 'Contents', + 'priority': 1, + 'target': '_new', + 'url': url_for('help.static', filename='index.html') }] \ No newline at end of file diff --git a/web/pgadmin/help/views.py b/web/pgadmin/help/views.py new file mode 100644 index 000000000..9d658bc1e --- /dev/null +++ b/web/pgadmin/help/views.py @@ -0,0 +1,22 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2015, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""A blueprint module implementing the pgAdmin help system.""" +MODULE_NAME = 'help' + +from flask import Blueprint +from flaskext.gravatar import Gravatar +from flask.ext.security import login_required +from flask.ext.login import current_user +from inspect import getmoduleinfo, getmembers + +import config + +# Initialise the module +blueprint = Blueprint(MODULE_NAME, __name__, static_url_path='/help', static_folder=config.HELP_PATH) diff --git a/web/pgadmin/test/hooks.py b/web/pgadmin/test/hooks.py index d7d8e0013..12a501858 100644 --- a/web/pgadmin/test/hooks.py +++ b/web/pgadmin/test/hooks.py @@ -12,7 +12,8 @@ from flask import render_template, url_for def get_file_menu_items(): - """Return a (set) of dicts of file menu items, with name, label, priority and URL.""" + """Return a (set) of dicts of file menu items, with name, priority, URL, + target and onclick code.""" return [ {'name': 'mnu_generate_test_html', 'label': 'Generated Test HTML', 'priority': 100, 'url': url_for('test.generated')}, {'name': 'mnu_test_alert', 'label': 'Test Alert', 'priority': 200, 'url': '#', 'onclick': 'test_alert()'},