Compare commits

..
427 Commits
Author SHA1 Message Date
Dave Page d57072b156 Bump version number for release. 2017-09-29 16:00:21 +01:00
Ashesh Vashi 5860de838a Changed the wording for 'Terminated session successfully' 2017-09-29 20:20:27 +05:30
Ashesh Vashi 4b2b08174c Do not show the terminate session icon in red as per Dave 2017-09-29 20:17:51 +05:30
Ashesh Vashi 2b64834179 Allow to terminate a session from the server, and database dashboard. 2017-09-29 20:10:33 +05:30
Ashesh Vashi 0d754fc39f Remove the reference of font-mfizz completely. 2017-09-29 11:26:45 +05:30
Ashesh Vashi 9c6c32e936 Resolved the logo issue.
For some unknown reason, font-mfizz was showing the slonik icon in
italic. Even after upgrading it to the latest version of font-mfizz, the
problem was not resolved.

So - instead of using the vector font, using the PostgreSQL SVG logo as
the application icon, and documentation link on dashboard now.
2017-09-29 11:07:26 +05:30
Surinder Kumar bcce574e83 Using the correct path for the font-mfizz stylesheet.
Reported by: Neel Patel
2017-09-29 09:17:39 +05:30
Akshay Joshi 5a132a547f Ensure using an alternate role to connect to a database doesn't cause an error when checking recovery state. Fixes #2742 2017-09-28 15:09:49 +01:00
Dave Page 9588d76b75 Add missing issue, per Harshal. 2017-09-28 10:45:23 +01:00
Dave Page 8ea85221f0 Update message catalogs. 2017-09-28 10:29:46 +01:00
Dave Page 50a78abf48 Update release notes. 2017-09-28 10:21:40 +01:00
Dave Page 739d8e2f1f Dead code cleanup. 2017-09-28 10:16:49 +01:00
Murtuza Zabuawala f855ed88ce Allow selection of SSL certificates and pgpass files in connection properties. Fixes #2649. Fixes #2650 2017-09-28 10:02:33 +01:00
Dave Page 510bc6c974 Update release notes. 2017-09-27 16:46:03 +01:00
Ashesh Vashi cc10a4ee54 Upgraded the font-mfizz to latest version (v:2.4.1) to resolve an issue,
about showing the PostgreSQL logo in italic in runtime on windows.
2017-09-27 07:41:15 +05:30
Chethana Kumar 62c9376546 Improve icon alignment. 2017-09-22 14:29:34 +01:00
Dave Page bcba596408 Add the ability to build a basic Docker container. 2017-09-21 16:49:37 +01:00
Dave Page 18dc938556 Use the correct lexer in the Apache/Windows docs. 2017-09-20 16:42:47 +01:00
Surinder Kumar 263e235862 Clarify how virtual envs can be used in WSGI mode, and ensure we ship the required bits on Windows. 2017-09-20 16:22:51 +01:00
Dave Page 354679e69b Fix an issue where we were executing SELECT statements in transactions in query tool which probably is not required because SELECT statements are already protected from dirty reads. Fixes #2683 2017-09-20 11:59:37 +01:00
Murtuza Zabuawala 64159d11ce Fix font on alertify dialogues 2017-09-20 11:42:16 +01:00
Akshay Joshi 13665f68d8 Fix validation message styling on thegrant wizard. Fixes #2673 2017-09-20 11:34:01 +01:00
Murtuza Zabuawala 2ddbddba33 Improve display of error messages in the query tool. Fixes #2700 2017-09-20 11:29:24 +01:00
Akshay Joshi fe757c384b Filtered Rows dialog not opened from the context menu. Fixes #2699 2017-09-19 11:46:51 +05:30
Dave Page 62d7a1044e Remove unused import that was causing a hard error on Windows 2017-09-18 16:54:43 +01:00
Dave Page 5ae681f2ba Bump version for RC2 release. 2017-09-18 16:15:13 +01:00
Harshal Dhumal f0ad26ba7a Fix for Exception when the server is restarted. Fixes #2713
This issue was caused because we recently added session_write_delay in session.
So session won't be written/updated to disk from memory until specified seconds are elapsed.

However we must forcefully write/update session to disk if user loges in or out irrespective of session_write_delay to keep sessions from memory and disk in sync as user logged in status is kept in session.
2017-09-18 14:39:43 +01:00
Akshay Joshi bdc08d94c4 Fix View Data option and column config for Foreign Tables. Fixes #2691 2017-09-18 14:32:17 +01:00
Murtuza Zabuawala 8bededa859 Fix disable trigger menu option. Fixes #2707 2017-09-18 12:37:59 +01:00
Murtuza Zabuawala e64c52a446 Fix tablespace move prompt message. Fixes #2708 2017-09-18 12:36:04 +01:00
Murtuza Zabuawala 5ebfd88f11 Correct alignment of the X button on dismissable alerts. 2017-09-18 11:57:44 +01:00
Murtuza Zabuawala bc5a5a5b45 Fix error message regexp in the query tool that could fail in some cases. Fixes #2700 2017-09-18 11:55:04 +01:00
Harshal Dhumal da40573f0b Fix user manager role handling. Fixes #2641 2017-09-18 11:45:57 +01:00
Harshal Dhumal 765e130336 Support Flask-Security 3.0 2017-09-18 11:40:09 +01:00
Dave Page a317df1351 Ensure builtins.SERVER_MODE is set in the WSGI wrapper. 2017-09-18 10:33:26 +01:00
Surinder Kumar 026ef7b8b7 Support React v15.5 and later where the code fails to run because React's PropTypes is no more part of React Module. 2017-09-18 10:08:12 +01:00
Harshal Dhumal 30e7016077 Changed array representation and formatting for the data types in Query Tool and View Data. Fixes #2671 2017-09-18 12:07:15 +05:30
Murtuza Zabuawala 8150f93c06 Fix menu left-hand margin. 2017-09-15 14:45:02 +01:00
Atul Sharma c3ea3b7bdf Replace the "Roboto" font family with "Open Sans" for alertify dialogs. 2017-09-15 14:08:29 +01:00
Murtuza Zabuawala 9cfb2f3cbe Fix filtering of system schemas so pg_* is hidden but pg* is not. Fixes #2709 2017-09-15 13:50:06 +01:00
Ashesh Vashi 55e14e4d78 Handle the executor nodes, which are unknown to the Explain module,
gracefully by showing the 'ex_unknown.png' for such nodes.

Reported by: Murtuza
Refs #2706
2017-09-15 10:51:37 +05:30
Atul Sharma 788f7f3a69 Bundle fonts with pgAdmin so we have a standard set for all platforms.
Research by Shirley at Pivotal.
2017-09-13 16:01:14 +01:00
Surinder Kumar e819465e38 Always pack React in prod mode to avoid a bug in debug mode that prevents the history tab working. 2017-09-13 15:50:09 +01:00
Chethana Kumar ff79dfc186 Update cast icons with improved design. 2017-09-13 10:43:39 +01:00
Chethana Kumar 3779c36d0f Update server and database icons with a clearer design. 2017-09-13 09:59:07 +01:00
Murtuza Zabuawala 80ce889c3d Fix an issue in User mapping module where users were not listed. Fixes #2693 2017-09-13 09:53:25 +01:00
Murtuza Zabuawala 5891bda06a Fix an issue where base types are not displaying in the create/edit domain dialog, also corrected the condition to show hidden system types. Fixes #2692 2017-09-13 09:52:16 +01:00
Surinder Kumar 120dbcc7d8 Run webpack in production mode when building for releases. Fixes #2660 2017-09-13 09:47:01 +01:00
Teng Zhang 512afd6618 Highlighting greenplum keywords in sql editor 2017-09-11 19:39:50 +05:30
Chethana Kumar f79b7f26b1 Using the svg icons for domain constraint, and server browser nodes. 2017-09-11 18:24:04 +05:30
Dave Page 51fd8f29fb Add new icons to release notes. 2017-09-11 11:22:43 +01:00
Dave Page 732c373dfb Use wheel==0.29.0 with Python 2.6 and 3.3. 2017-09-11 11:06:29 +01:00
Dave Page cca7526b9b Remove menu icon tests that are no longer required. 2017-09-11 10:13:54 +01:00
Dave Page 4b5b3195c4 Bump the build suffix in preparation for release. 2017-09-11 10:04:20 +01:00
Ashesh Vashi 3bbd1a8a48 Remove icons from the menus to de-clutter the UI and make it more consistent with most OSs. 2017-09-11 09:51:26 +01:00
Dave Page 8b1aeadaf0 Stick with the older Flask-Script module for Python 2.6 2017-09-11 09:09:49 +01:00
Ashesh Vashi ac2512799e Rename the SecurityGroupUnderSchema to SecurityGroupSchema, and
redefined in the database (instead of schema) javascript module, as it
is also used by the foreign-server node too.

Reported by: Neel Patel
2017-09-11 13:13:40 +05:30
Ashesh Vashi 8c8c0e78ca Miscellaneous fixes for icon sizing issue, missing tree nodes to be
webpacked, etc.

- Fixed the background-size for the svg icons to 20x20 px such that it
  does not adjust it's size when a context menu height is different due
  to length of the node label, also - it allows us to fix the issue of
  icons sizes in the Grant Wizard.

- Added two missing browser tree nodes in the webpack configuration
  i.e. Foreign Server, and User Mapping
- Removed a redundant javascript file foreign-server.js
- Fixed the missing context menu icons for Foreign Table, and Tablespace
  nodes.

Thanks EDB development team to find the regression added after the icon
changes in quick time.
2017-09-11 12:55:42 +05:30
Ashesh Vashi 4018562bc7 Changes in the stylesheets to support the svg icons for the browser
tree nodes.
2017-09-11 11:22:55 +05:30
Chethana Kumar 23a00f9614 Replacing existing browser tree node png icons with the svg icons. Made
it compatible with the pgAdmin 4 color combination.

TODO::
Icons for the following nodes are in PNG format.
- Domain Constraint (Only the invalid icon)
- pgAgent Job Steps
- Green Plum database server
- Server (Only server.png, which is used in the create/edit dialog)
2017-09-11 11:17:31 +05:30
Karen Blatchley 23dd68b212 Initial draft of the 2.0 release notes. 2017-09-08 15:50:13 +01:00
Murtuza Zabuawala 8d248dab4c Fix quoting of index column names on tables. Fixes #2619 2017-09-07 16:36:35 +01:00
Murtuza Zabuawala d5f60e1a47 Fix layout of password prompt dialogue. Fixes #2684 2017-09-07 16:27:02 +01:00
Harshal Dhumal 263aa42725 Reset query tool options before running tests. Fixes #2681 2017-09-05 16:25:15 +01:00
Surinder Kumar c4393a7795 Fix Copy so it still works after query results have been copied. Fixes #2637 2017-08-31 14:50:39 +01:00
Akshay Joshi 47cf874460 1) Fixed error in alertify.pgNotifier when server connection is lost.
2) Change styling of alertify.pgNotifier as we did for success, error and info.
2017-08-31 18:02:03 +05:30
Surinder Kumar 2945b3fe93 Define the proper NODE_ENV environment during running the webpack.
Using the webpack.DefinePlugin during the development build too, not
just in production build.

Fixes #2596.

Also - passing option 'warning: false' for UglifyJsPlugin, which will
not show warning messages on the console during the production build.
2017-08-31 14:28:52 +05:30
Dave Cramer eae6f0427c Fix display of types in GPDB. 2017-08-31 09:57:27 +01:00
Harshal Dhumal dbf760c6e7 Improve datamodel validations for default Validator if user (developer) do not implement validate function in datamodel. Fixes #2670 2017-08-31 09:54:31 +01:00
Murtuza Zabuawala 52840d68a8 Fix RE-SQL for triggers with a single arg. Fixes #2668 2017-08-31 09:39:09 +01:00
Teng Zhang 821442ed8f GPDB compatibility fixes:
When connected to a Greenplum database server
- Hide items that not work with GPDB, such as Triggers, FDW, FTS_*, etc
- Tables/Views/Catalogs/Language node can expand correctly
- Views/Languages/Catalogs can show properties dialog with correct information
- Show a greenplum icon at the server node

Teng Zhang & Hao Wang
2017-08-30 11:18:14 +01:00
Harshal Dhumal 048205ead5 Rename the debugger XSS test function to 'a_test_function' to ensure it appears near the top of the tree and not off-screen.
This should not be a permanent fix (the test should be able to scroll the treeview), but works for now to stop tests failing.
2017-08-30 11:12:27 +01:00
Surinder Kumar 7835da267b Allow pgAdmin to run with config database versions from the future. Fixes #2664 2017-08-29 15:03:02 +01:00
Harshal Dhumal ceb9438000 Cleanup feature tests. Fixes #2586 2017-08-29 14:57:56 +01:00
Murtuza Zabuawala 401e13ca65 Fixed issue where 'backend_type' column is exist for database server version greater than 10.
Issue is regression of RM #2597.
2017-08-28 16:18:05 +05:30
Harshal Dhumal b1ad89fb4a Using the proper python syntax to fetch the default binary path for
different servers types.
2017-08-26 09:59:57 +05:30
Ashesh Vashi 6b727c43b9 Define the utility path lable, and help message for the Greenplum
database server, shown in the preferences dialog.

Also, fixed the issue, when server type is not defined in the
DEFAULT_BINARY_PATHS, in the configuration.
2017-08-25 21:35:57 +05:30
Murtuza Zabuawala 74db837417 Allow queries to be cancelled from the dashboard, and display additional info in the subnode control. Fixes #2597 2017-08-25 16:57:33 +01:00
Teng Zhang 46c5df4e7b Greenplum specific DDL and Dashboard display changes.
Initial patch by Sarah McAlear<smcalear@pivotal.io>.
2017-08-25 17:53:03 +05:30
Murtuza Zabuawala d3babd78aa Fixes #2560 - View is not fully qualified in Trigger definition. 2017-08-25 17:45:20 +05:30
Surinder Kumar f711336a6b Add package run scripts to allow to run the webpack in watch mode, also
added '--progress' option to make it more interactive.
2017-08-25 17:26:56 +05:30
Wenlin Zhang 5dd375dd20 Fix the feature tests failuers. 2017-08-25 17:16:36 +05:30
Dave Page 8579909558 Ensure the SERVER_MODE changes don't break the PIP build. 2017-08-25 12:17:47 +01:00
Dave Page 5c016f0993 Update docs to more accurately reflect the SERVER_MODE config requirements. 2017-08-25 12:13:03 +01:00
Dave Page a65f7b330b Ensure builtins.SERVER_MODE is handled if running setup.py standalone. 2017-08-25 11:56:44 +01:00
Dave Page 507d8b3fe4 Regression tests aren't run under the runtime, so no need to check for builtins.SERVER_MODE's existence. 2017-08-25 11:56:10 +01:00
Dave Page 0e5ea58294 Ensure builtins.SERVER_MODE is present so the docs build cleanly. 2017-08-25 11:19:27 +01:00
Dave Page f195b18f2d Ship with pre-configured paths that can work in both Server and Desktop modes out of the box. Fixes #2662
Ship the web code using server mode with appropriate paths by default and enable the runtime to override the mode, and force into desktop changing the appropriate paths to user-specific ones.

Note that this change will likely cause more advanced users to have to tweak configs.

RPMs will also need changes to create /var/lib/pgadmin and /var/log/pgadmin, owned by the webserver account.
2017-08-25 10:54:28 +01:00
Dave Page fb9eee47bd Bump the version number for 2.0. Let's get testing started ASAP! 2017-08-25 10:18:42 +01:00
Navnath Gadakh bd04cfaaa8 Properly cleanup after running the FTS test cases. 2017-08-25 09:32:46 +01:00
Akshay Joshi fe6e4686a2 Unable to add/update variables for columns of a table. Fixes #2659 2017-08-23 17:11:30 +05:30
Surinder Kumar ee20a10e94 Syntax error while saving changes for start/end time, weekdays, monthdays, month, hours, minutes while updating the pgAgent Job. Fixes #2657. 2017-08-23 14:05:54 +05:30
Surinder Kumar cb9a05a7e7 Datetimepicker will expand from bottom instead of Top, because of that user won't be able to select start and end time properly. Fixes #2656 2017-08-23 11:26:24 +05:30
Sarah McAlear b585063a26 Refactor keyboard shortcut functions in the query tool. Fix some incorrect keycodes and update docs.
Initial work by Sarah & Violet @ Pivotal, with additional tweaks by Murtuza @ EDB.
2017-08-21 15:27:29 +01:00
Murtuza Zabuawala 2e2ca26020 Ensure role names are escaped in the membership control. Fixes #2606 2017-08-21 14:00:33 +01:00
Murtuza Zabuawala 654326a0d1 Update CodeMirror version. Fixes #1697. Fixes #2168. Fixes #2447. Fixes #2562. 2017-08-21 13:43:41 +01:00
Murtuza Zabuawala d757d8698d Fix connection string validation for pgAgent jobs. Fixes #2655 2017-08-21 13:20:07 +01:00
Surinder Kumar 6d7b54eb62 Update datetime picker. Fixes #2654 2017-08-21 13:17:35 +01:00
Atul Sharma e6223c9a49 Fixes #2567 - Use the proper database connection to fetch the default
prileges in the properties tab of the database.

Reviewed by: Murtuza Zabuawala
2017-08-18 09:15:57 +05:30
Violet Cheng d527769bf8 Extract the generate_url(..) function from node.js, and collection.js 2017-08-17 21:43:07 +05:30
Murtuza Zabuawala e9b80dae9c User can not add New Server through Quick links. Fixes #2634 2017-08-17 18:14:06 +05:30
Sarah McAlear dee5186f65 Fixed alertify notification messages where checkmark box disconnected from frame. Fixes #2644 2017-08-17 17:54:12 +05:30
Surinder Kumar c7686dee05 Unset compression ratio if it is an empty string in Backup module. Fixes #2582 2017-08-17 16:35:42 +05:30
Surinder Kumar bff48e0b2d Fixed the path reference of load-node.gif which was referencing to vendor directory. Fixes #2646 2017-08-17 15:27:09 +05:30
Murtuza Zabuawala 2df4625ce0 1) Connection Type cell was not honouring to 'Kind' option in Subnode control.
2) Kind option was not saved properly
3) User was not be able to update Kind option in edit mode.

Fixes #2633
2017-08-17 15:00:08 +05:30
Murtuza Zabuawala 2c6c4a16ce Use dict based data instead of 2d-array in Type module as we are adding keys on the fly.
Reviewed By: Harshal Dhumal
2017-08-17 13:07:39 +05:30
Neel Patel deb5475b98 On certain linux operating systems, Qt application exits with an error
message such as 'X Error: BadDrawable'.

In order to resolve the issue, we need to let the Qt know not to load
the MIT-SHM extension.

Reference:
https://iwf1.com/quick-fix-one-kdes-common-xorg-errors-x-error-baddrawable/
2017-08-09 16:52:43 +05:30
Khushboo Vashi c4ca781ce2 Fixed some UX issue with the Import/Export tool.
- Couldn't click on the filename control once gets an error.
- Encoding is not in alphabetical order.
2017-08-09 16:52:43 +05:30
Hao Wang 5141debae7 UX improvements of the history in the query tool.
- Added copy button for query text.
- Historical queries are binned/grouped by day.

Patch By: Hao Wang, Sarah McAlear
2017-08-09 16:52:43 +05:30
Surinder Kumar 33bd9d4782 Enable source maps for debugging purpose in all webpack modules
(except for vendor, and codemirror).
2017-08-09 16:52:43 +05:30
Ashesh Vashi 845025db8f Some cosmetic changes.
- Loading 'pgadmin' as 'sources/pgadmin', as found under the 'sources'
  reference directory to be consistent with other files.
- Removed the 'pgadmin' reference from the base.html template.
- Renamed 'pgadmin.slickgrid.editors.js', and
  'pgadmin.slickgrid.formatters.js' as 'editors.js', and 'formatters.js'
  respectively, as they're already in the 'pgadmin/static/js/slickgrid'
  directory.
- Removed the duplicate entry of 'translations' from the webpack.shim.js
2017-08-09 16:52:12 +05:30
Akshay Joshi e418cb8387 Changed the mapping of cell from 'numeric' to 'integer' for integer control as numeric cell has been removed from the code. Fixes #2631 2017-08-07 14:02:59 +05:30
Akshay Joshi 801a05891e Set the database name to blank('') when job type is set to batch, while creating pgAgent job. Fixes #2620 2017-08-04 19:31:17 +05:30
Surinder Kumar 06a65ecf71 Added missing pgagent file in webpack.config.js Fixes #2617 2017-08-04 17:39:05 +05:30
Murtuza Zabuawala ef48c2ed91 Fixed issue in query tool where messages were not displaying from functions/procedures properly. Fixes #2555 2017-08-04 15:50:39 +05:30
Murtuza Zabuawala bebfc62721 Fixed collation tests on Windows, replace use of default 'POSIX' collation with 'C' collation for testing. Fixes #2501 2017-08-03 16:46:20 +05:30
Murtuza Zabuawala 6717aff8f5 Domain create dialog do not open and Font size issue in Security label control. Fixes #2616 2017-08-01 16:37:17 +05:30
Akshay Joshi e506fa1dbe Improved alertify notification logic. Remove AlertifyWrapper class and extend notification methods in alertify itself. 2017-07-31 18:59:44 +05:30
Akshay Joshi a7f58e2b92 1) Added partition module in webpack config.
2) Fixed missing logic of partition from primary_key.js and unique_constraint.js as this two files are newly created for webpack.
3) Changed the node name from 'check_constraint' to 'check_constraints'. Also changed the same in test case url.
2017-07-31 18:25:04 +05:30
Ashesh Vashi bdefdf5d4e Requests for statistics were not stopped even when Dashboard panel is
closed. It is a regression of webpack.
2017-07-31 16:48:52 +05:30
Surinder Kumar 6d5417709c Moved the javascripts of different modules from 'templates' to 'static' directory.
Moving the javascripts for the following modules:
 - About
 - Browser nodes
 - Dashboard
 - FileManager
 - Vendor/snap.svg
 - Preferences
 - Settings
 - Backup
 - Datagrid
 - Debugger
 - Sqleditor
 - Grant Wizard
 - Import & Export
 - Maintenance
 - Restore and
 - User Management
2017-07-27 17:25:08 +05:30
Harshal Dhumal 831c614a60 Store the file dialog view on toggle. 2017-07-26 14:35:43 +01:00
Murtuza Zabuawala af26d983e5 Fixup tests following label changes. 2017-07-26 13:45:44 +01:00
Harshal Dhumal 97cd74a373 Default the file browser view to list, and make it configurable. Fixes #2579 2017-07-26 13:09:52 +01:00
Khushboo Vashi d1e7254fbd Handle control visibility properly in javascript strict mode. 2017-07-26 12:55:46 +01:00
Murtuza Zabuawala 1fa9648a21 Update keyboard shortcuts per discussion. Also, make the labels platform sensitive. 2017-07-26 12:50:42 +01:00
Harshal Dhumal d339d6b816 Do not dump the session data on the disk on every request.
Session object is updated, everytime a request is being served, and
that was forcing the session object dumped on the dist on every request.

On windows, it was causing issues on slower system on startup. Because -
windows file system locks the file, when it is opened by any
application. And, frequent requests on the pgAdmin main UI rendering
was causing issues, because of that.

In order to resolve the issue, we will not write the session data on
disk for every request, but - only after certain delay (in seconds),
from it was last written. It can be configured using the attribute
'PGADMIN_SESSION_DISK_WRITE_DELAY' in the configuration file,
default vaule for the delay is 10.
(i.e. 10 seconds)
2017-07-25 15:52:32 +05:30
Murtuza Zabuawala 178d583bcd Fix paths under non-standard virtual directories. Fixes #2563 2017-07-25 10:15:18 +01:00
Murtuza Zabuawala 617e9dbb3a Allow queries to be cancelled from the dashboards. Fixes #1812 2017-07-24 12:13:24 +01:00
Joao Pedro De Almeida Pereira fe95b7670b Ensure the appropriate entry is focussed when entering the history tab. 2017-07-24 11:46:06 +01:00
Dave Page eb5bb5fcc0 Update yarn.lock 2017-07-21 16:17:24 +01:00
Sarah McAlear 2ebb409999 Fix test assertion. 2017-07-21 16:16:41 +01:00
Surinder Kumar 03657df82a Ensure babel-polyfill is loaded in older qWebKits. Fixes #2593 2017-07-21 16:15:03 +01:00
Harshal Dhumal 7182b59976 Ensure arrow keys work correctly when the pane is focused instead of the tab in the query tool history. 2017-07-21 13:33:59 +01:00
Atul Sharma 70418144cf Add a field to the Server Dialogue allowing users to specify a subset of databases they'd like to see in the treeview. Fixes #1918 2017-07-21 12:44:57 +01:00
Murtuza Zabuawala acaa79cf6b Fix disconnection of new databases. Fixes #2594 2017-07-21 11:11:03 +01:00
Murtuza Zabuawala b313cbce0d Fix regression tests after Dave broke them. 2017-07-21 10:57:29 +01:00
Surinder Kumar a49a3103e2 Prevent the Werkzeug reloader from causing a "double start" at init time. 2017-07-21 09:46:30 +01:00
Surinder Kumar ede6765f6b Add an editorconfig file to help maintain coding standards. 2017-07-21 09:39:23 +01:00
Sarah McAlear 86dc1e81f1 Move Query Tool keyboard shortcut code into a new module and add tests. 2017-07-20 22:22:25 +01:00
Matthew Kleiman e29cd8d83d Improve the history UI. 2017-07-20 20:50:37 +01:00
Matthew Kleiman 21bfcd83f4 Allow navigation of query history using the arrow keys. Fixes #2590 2017-07-20 20:47:40 +01:00
Murtuza Zabuawala 64f3a559ab Add the Flask-Paranoid module for a little extra, well, paranoia in web mode. Fixes #2584 2017-07-20 18:04:33 +01:00
Dave Page 83ac1f3555 Remove debug logging of the URL map which is extremely long now, and not of a great deal of use. 2017-07-20 16:15:53 +01:00
Surinder Kumar ae3acbdbbc Fix webpacking of loading icon. 2017-07-20 13:38:16 +01:00
Harshal Dhumal 54882e061c Don't attempt to render binary data in the query tool result grid. Fixes #2080. Fixes #2074. 2017-07-20 13:09:47 +01:00
Surinder Kumar 2eb151c2d9 More webpack cleanup - add comments liberally and rename lib.css to style.css 2017-07-20 12:52:15 +01:00
Akshay Joshi 4d4da67247 Fix regressions introduced by PG10's partitioning code. Fixes #2043. Fixes #2324. 2017-07-20 12:49:40 +01:00
Surinder Kumar dfa877262d Webpacking cleanups 2017-07-19 15:03:21 +01:00
Surinder Kumar 6046be7fba Fix typo in filename. 2017-07-19 11:57:11 +01:00
Dave Page 1e1a9f2cf4 Add controls and shortcuts for commenting/uncommenting code in the SQL Editor. Fixes #2456.
Take the opportunity to tidy up the menus and add access keys to appropriate buttons.
2017-07-19 11:43:45 +01:00
Surinder Kumar b90d368ee7 Resolve an issue where collection nodes sometimes wouldn't sort properly. 2017-07-18 16:31:05 +01:00
Surinder Kumar 659aeeb58e Add a missing dependency. 2017-07-18 16:30:18 +01:00
Murtuza Zabuawala bab3da24e6 Support SSL in the regression tests. Fixes #2170 2017-07-18 15:23:11 +01:00
Surinder Kumar 6396b8ce18 Add missing new files from the previous commit. Ooops. 2017-07-18 15:14:59 +01:00
Surinder Kumar 4a91bcde30 Webpack all the things! Fixes #2135
This significantly speeds up loading of the application; in an average of 3 tests, v1.6
loaded in 11.5s in the runtime on a Mac, whilst the webpacked version of the code
loaded in 5.53s.
2017-07-18 15:13:17 +01:00
Dave Page d04ac7656a Remove change made for debugging and committed in error. 2017-07-17 15:19:30 +01:00
Khushboo Vashi c546182789 Modify the runtime to use time-based timeouts rather than retry based. Fixes #2556
This allows for slow vs. fast connection failures (e.g. an active rejection vs. no response).
2017-07-17 15:17:58 +01:00
Harshal Dhumal 3942461c50 Correct for malformed query generated when using custom type. Fixes #2544 2017-07-17 11:14:34 +01:00
Khushboo Vashi 059d671af5 Fix typo 2017-07-17 10:59:29 +01:00
Neel Patel dc6a1936f5 Tidy up tab styling. Fixes #2557 2017-07-17 10:58:17 +01:00
Harshal Dhumal 8bbcf0ab36 Fix handline of large file uploads and properly show any errors that may occur. Fixes #2153 2017-07-17 10:51:26 +01:00
Neel Patel dcc74af87b Stop tool buttons from changing their styling unexpectedly. Fixes #2559 2017-07-17 10:45:16 +01:00
Murtuza Zabuawala 3f83780049 Remove the comma from PIDs in the statistics panel. 2017-07-17 10:18:31 +01:00
Neel Patel 1fe0d51925 Prevent the tab bar being hidden when detached tabs are being closed. Fixes #2558 2017-07-17 10:14:40 +01:00
Harshal Dhumal 07aa74eaf5 Show tablespace on partitions. Fixes #2551 2017-07-17 09:50:18 +01:00
Ashesh Vashi 4eefc52748 [PostgreSQL 10] Fixed the Pause/Resume Replay of WAL files for PostgreSQL 10. Fixes #2566 2017-07-14 18:39:19 +05:30
Murtuza Zabuawala 822e62c238 Fix privileges control on IE 10/11. Fixes #1166 2017-07-14 12:45:09 +01:00
Khushboo Vashi da67963094 Don't continually poll for graph data on the dashboard if the server is disconnected. Fixes #1165 2017-07-14 12:42:29 +01:00
Mammoth Power de06e63334 Fix a compiler error with older compilers. 2017-07-11 17:22:20 +01:00
Dave Page 68a6c496d9 Straighten line 2017-07-11 13:20:16 +01:00
Dave Page 374bf79911 Fix proxy support with Qt 5.9+ 2017-07-11 11:48:13 +01:00
Dave Page dad6031bd6 Revert "Ensure dependencies are packaged in the tarball"
This reverts commit 6ad4a623c4.

ENOCOFFEE error
2017-07-11 09:23:57 +01:00
Neel Patel c93aa3810d Fix a compiler error with older compilers. 2017-07-11 09:14:53 +01:00
Dave Page 6ad4a623c4 Ensure dependencies are packaged in the tarball 2017-07-11 09:12:09 +01:00
Surinder Kumar 2bfe640a08 Fix alignment of Object > delete/drop & properties icons 2017-07-10 16:14:40 +01:00
Ashesh Vashi b095d1f33a Ensure the initial password is properly hashed during setup in web mode. Fixes #2492 2017-07-10 16:08:35 +01:00
Akshay Joshi f06c3578f6 Fix drop/drop cascade for partitioned tables. Fixes #2550 2017-07-10 16:02:32 +01:00
Harshal Dhumal 7aa7ea0fe2 Couple of typos in the release notes. 2017-07-10 15:18:48 +01:00
Dave Page ea5dfe23a0 Bump version numbers prior to release. 2017-07-10 14:56:20 +01:00
Karen Blatchley 4bfb31b03b Release notes for 1.6. 2017-07-10 14:52:45 +01:00
Akshay Joshi ed3cb7df41 Handle partitioned tables created "OF TYPE". Fixes #2545 2017-07-10 14:16:30 +01:00
Murtuza Zabuawala 6d3d2cd458 Handle un-mounted drives correctly on Windows. Fixes #1999 2017-07-10 14:04:57 +01:00
Surinder Kumar 33e56272ca Fix IE11 alert layout again. 2017-07-10 13:49:47 +01:00
Khushboo Vashi ecd95141f3 Refresh nodes correctly when there is a single child that is updated. Fixes #2532 2017-07-10 13:25:23 +01:00
Dave Page 55b1e7b186 Update Mingw build for changes in QtWebKit 2017-07-10 12:12:25 +01:00
Dave Page 2dfa622357 Fix history font on IE. 2017-07-10 10:25:27 +01:00
Murtuza Zabuawala 907c5fe198 Use the correct font for alerts on IE. 2017-07-10 10:07:23 +01:00
Sarah McAlear c02ac2ac66 Fix history view in IE11. 2017-07-10 10:03:04 +01:00
Joao Pedro De Almeida Pereira d56f1d847c Update dialogue error styling to match alerts 2017-07-10 09:36:10 +01:00
Dave Page ec739b3392 Revert "Open query tool and debugger windows in new tabs by default."
This reverts commit 1a6fe946ce.

This is going to break the regression tests, so reverting it for now.
2017-07-07 17:06:12 +01:00
Dave Page 1a6fe946ce Open query tool and debugger windows in new tabs by default. 2017-07-07 16:53:45 +01:00
Murtuza Zabuawala 08e874a026 Fix alert animation on IE11 2017-07-07 16:50:47 +01:00
Harshal Dhumal d151bdb4cd Fix handling of CREATE TABLE OF <type>. Fixes #2534 2017-07-07 16:34:33 +01:00
Joao Pedro De Almeida Pereira 815c4b4c45 Improve spacing around delete icons in backform tables. 2017-07-07 16:06:51 +01:00
Murtuza Zabuawala acd3568f06 Fix the formatting of the ROWS option for functions etc. Fixes #2537 2017-07-07 15:57:43 +01:00
Sarah McAlear 8646e9e404 Enable pretty html output of our karma test results. While running yarn test:karma, visit localhost:9876/debug.html to see test output. 2017-07-07 15:54:42 +01:00
Harshal Dhumal fc78202600 Fix clear history. 2017-07-07 15:51:06 +01:00
Akshay Joshi fae185ff66 Partitioned table does not present in grant wizard. Fixes #2543 2017-07-07 15:15:15 +05:30
Akshay Joshi e793413d76 Fixed issue by adding extra check for 'relkind' column 2017-07-07 12:33:58 +05:30
Akshay Joshi c2fb0394bf Added support of Declarative Partitioning (Range, List) for PostgreSQL 10.
This allows the user to create partitioned table and it's partitions.

  - Edit partitions, Create/Listing of constraints, rules, triggers under partitions. (Implemented by Harshal)
  - Updating browser tree node when create/attach/detach partitions from table dialog.(Implemented by Ashesh)
2017-07-07 11:55:55 +05:30
Murtuza Zabuawala ca7fe9a520 Ensure the save password option is enabled when creating a server. Fixes #2540 2017-07-06 13:33:46 +01:00
George Gelashvili e5bedf088e In subnodes without dropdowns, the rows had smaller height, making them appear unintentionally different than those with dropdowns. Make them the same. 2017-07-06 13:11:40 +01:00
Matthew Kleiman e2cbaaef71 UI tweaks for the query history. 2017-07-06 13:08:29 +01:00
Dave Page 1291841d98 Remove unused minimisation code 2017-07-06 13:04:13 +01:00
Dave Page 592c70e655 Add some useful make targets for bundling and linting. 2017-07-06 13:02:43 +01:00
Murtuza Zabuawala 9de6c08d28 Allow use of Shift+Tab to un-indent selected text. Fixes #1988 2017-07-05 14:20:19 +01:00
Murtuza Zabuawala 2bb01e2d1a Fix alert layout when more than one are shown at once. 2017-07-05 12:04:48 +01:00
Harshal Dhumal 76939e4f63 Prompt the user to save dirty queries rather than discard them for a more natural workflow. Fixes #1972 2017-07-04 23:39:10 +01:00
Murtuza Zabuawala b211eb199c Improve styling for alerts by highlighting the icon. 2017-07-04 12:03:32 +01:00
Khushboo Vashi 66b101fe4c Resolve a number of issues with domains and domain constraints. Fixes #2529 2017-07-04 11:52:58 +01:00
Murtuza Zabuawala 0aa763b706 Remove unnecessary whitespace from stored procedure SQL. Fixes #2146 2017-07-03 16:32:19 +01:00
Murtuza Zabuawala 5c7dcaba81 Allow debugging of functions in packages. Fixes #1948 2017-07-03 16:30:12 +01:00
Khushboo Vashi 070a9c077e Allow breakpoints to be set on triggers on views. Fixes #2528 2017-07-03 16:15:42 +01:00
Khushboo Vashi f6b879233c Fix deletion of table rows with the column definition having NOT NULL TRUE and HAS NO DEFAULT VALUE. Fixes #2527 2017-07-03 15:49:59 +01:00
Murtuza Zabuawala 2d5e55964a Improve the debugger's default page layout, and prevent attempts to continue debugging after the user has stopped. Fixes #2512, Fixes #2511 2017-07-03 15:14:45 +01:00
Harshal Dhumal 1977a5fcda Fix clipboard handling with large datasets. Fixes #2489 2017-07-03 11:19:02 +01:00
Harshal Dhumal 4e21cdb64b Fix a syntax error in the SQL Editor. 2017-07-03 11:02:20 +01:00
Murtuza Zabuawala 1e427890de Fix an issue where duplicate entry is made of successful executed query, one with status message and one without status message. 2017-07-03 11:00:42 +01:00
Khushboo Vashi 7c09a8f827 Fix typo that caused a layout issue with the Edit Grid. 2017-06-30 12:58:47 +01:00
Dave Page ffb00b502a Fix a couple of gripes from the JS linter on Windows. 2017-06-30 10:34:06 +01:00
Joao Pedro De Almeida Pereira f2d2075d81 Update alertify alerts to use the styling defined in the styleguide (missed some files in the original commit). 2017-06-30 10:23:12 +01:00
Joao Pedro De Almeida Pereira 2a30a86e7d Update alertify alerts to use the styling defined in the styleguide. 2017-06-30 10:21:05 +01:00
Joao Pedro De Almeida Pereira ba3ab7b322 Add support for SCSS building in webpack. 2017-06-30 10:15:44 +01:00
Khushboo Vashi 501120701e Allow the dashboard panel to be closed. Fixes #2506 2017-06-30 10:11:34 +01:00
Harshal Dhumal 2d65312910 Improve speed of Select All in the results grid. Fixes #2522 2017-06-30 09:54:31 +01:00
Akshay Joshi c98b64fd82 1) Edit cellEditing function, in some cases grid object is undefined.
2) Modify SubNodeCollectionControl, so that user can pass custom backgrid row.
3) Handling of visible parameter in SubNodeCollectionControl.
4) Customise title and delete message for Delete Cell.
5) Added Backgrid.Extension.Select2DepCell and moved Backgrid.Extension.StringDepCell from user management to backgrid.pgadmin.js.
2017-06-29 19:01:29 +05:30
Harshal Dhumal 7389744ecf A number of minor cleanups to the recent changes to the query tool. 2017-06-28 09:49:39 -04:00
Khushboo Vashi 301798d87a Fix encoding issue when saving servers. Fixes #2518
Patch by Khushboo, based on a suggested fix from Ladislav Jech
2017-06-28 09:44:32 -04:00
Dave Page ed5c74affe Fix image size. 2017-06-27 17:09:52 -04:00
Murtuza Zabuawala f0066d6006 Update preferences docs. 2017-06-27 17:04:56 -04:00
Murtuza Zabuawala a9fa093d4b Allow non-superusers to debug their own functions and prevent them from setting global breakpoints. Fixes #2162
Based on a patch from Kit Yam Tse
2017-06-27 16:58:07 -04:00
Joao Pedro De Almeida Pereira 7f55412059 Overhaul the query history tab to allow browsing of the history and full query text. Fixes #2282
Patch by Joao and the team at Pivotal.
2017-06-27 10:55:57 -04:00
Dave Page e413186d23 Add stylesheet to override brace matching styles, missed from the feature commit. 2017-06-27 10:41:26 -04:00
Dave Page 96412b3219 Revert "Allow the user to close the dashboard panel. Fixes #2506"
This reverts commit a87ee6d059.
2017-06-27 10:35:43 -04:00
Murtuza Zabuawala 1b49bb8b22 Add preferences to enable brace matching and brace closing in the SQL editors. Fixes #2513 2017-06-27 09:57:38 -04:00
Khushboo Vashi a87ee6d059 Allow the user to close the dashboard panel. Fixes #2506 2017-06-27 09:21:24 -04:00
Harshal Dhumal c65158312d Use on-demand loading for results in the query tool. Fixes #2137
With a 27420 row query, pgAdmin III runs the query in 5.873s on my laptop. pgAdmin 4 now takes ~1s.
2017-06-27 09:03:04 -04:00
Atul Sharma 15cb9fc35b Add support for the hostaddr connection parameter. This helps us play nicely with Kerberos/SSPI and friends. Fixes #2191 2017-06-26 15:48:59 -04:00
Surinder Kumar 3f4781cdcb Un-break query tool feature tests. 2017-06-26 15:25:05 -04:00
Khushboo Vashi 27bc5c803f Ensure saved passwords are effective immediately, not just following a restart when first saved. Fixes #1920 2017-06-26 07:55:34 -04:00
Khushboo Vashi d4e77deda4 Ensure revoked public privileges are displayed in the RE-SQL for functions. Fixes #2507 2017-06-26 07:50:39 -04:00
Surinder Kumar cfb4b11573 Use client-side url_for in the sql editor and data grid modules. 2017-06-26 07:43:03 -04:00
Khushboo Vashi 6b6d3369b3 Wait for the Tools menu to be populated when running the feature tests, instead of failing.
Fix by Khushboo, based on Harshal's previous work.
2017-06-23 14:07:31 +01:00
Dave Page 92b1b1365e Tidy up About box formatting, 'cos it's been annoying me for ages. 2017-06-23 10:21:40 +01:00
Dave Page 6fabf4764b Add access keys for top level menus. 2017-06-23 09:58:46 +01:00
Murtuza Zabuawala 7a4945ff9e Fix removal of sizes from column definitions. Fixes #2155 2017-06-23 09:42:46 +01:00
Matthew Kleiman 9af29364c7 Fix cell selection window alignment for the updated SlickGrid. 2017-06-23 09:37:58 +01:00
Matthew Kleiman 94aa5487fb Update Slickgrid to 2.3.7. As this version includes all the features we need, it can be moved out of the vendor directory and we'll use yarn to pull it in. 2017-06-23 09:35:56 +01:00
Matthew Kleiman b98fcaa829 Ensure the relevant Makefile targets install node modules before running. 2017-06-23 09:23:31 +01:00
Khushboo Vashi 25282f3094 Additional preference fix. 2017-06-22 14:55:45 +01:00
Murtuza Zabuawala 0ab637c7ab Fix import/export to work as expected with TSV data. Fixes #1934 2017-06-22 13:57:32 +01:00
Khushboo Vashi 33e75d24f8 Fix preferences handling for utilities. 2017-06-22 12:18:56 +01:00
Murtuza Zabuawala 137bae1b04 Ensure default values are honoured when adding/editing columns. Fixes #1860 2017-06-22 12:11:02 +01:00
Ashesh Vashi d26337a1ba Moved the javascripts of the following browser node modules to the
'static' directory from 'templates' in the respective module directory:
- Server Group
- Server
- Database
- Schema
- Cast
- Event trigger
- Extension
- Foreign data wrapper
- Language
- Catalog Object
- Collation
- Domain Constraint
- Domain
- Foreign server
- FTS Configuration
- FTS Dictionary
- FTS Parser
- FTS Template
- Function
- Procedure
- Trigger Function
- Package
- Sequence
- Catalog
- Schema
- Synonym
- Table
- Type
- Materialized View
- View
- pgAgent Modules
  + Job (pga_job)
  + Schedule (pga_schedule)
  + Steps (pga_jobstep)

Added new dynanic modules for listing the supported server types, and
current user information.

NOTE: We've not yet moved the javascripts for the children of the table
module.
2017-06-22 15:58:32 +05:30
Khushboo Vashi 67fd119de8 Maintain a client-side cache of preference values, populated using an async call. Fixes #2487 2017-06-21 17:09:59 +01:00
Murtuza Zabuawala b9f6fb9545 Update MatView and pgAgent modules to work with recent integer/numeric changes. Fixes #2504 2017-06-21 17:03:43 +01:00
Murtuza Zabuawala b9736cbd74 Handle missing/dropped synonyms gracefully. Fixes #2503 2017-06-21 16:59:43 +01:00
George Gelashvili 5cfa22cf23 Fix React to work with QtWebKit
We learned that the underlying issue was related to react-dom's SyntheticEvent.augmentClass function being undefined.

This seems to be caused by attempted property assignment after the SyntheticEvent had been replaced by a Proxy of itself. This works fine in Chromium et al, but QtWebKit doesn't deal with Proxy Event objects well.
Moving the augmentClass definition and assignment up above the Proxy stuff resolves the issue in a PR to React: https://github.com/facebook/react/pull/10011
2017-06-21 11:25:22 +01:00
George Gelashvili a45b87d9b7 Vendorize React. This is required at this time because we need to modify it to work with QtWebKit.
The patch to do that has been submitted upstream; if accepted, we can un-vendorize again.
2017-06-21 11:20:02 +01:00
Shruti B Iyer 281b67952a Consolidate selection colors in the drop down menu and browser tree to match the light blue agreed upon in the styleguide. 2017-06-21 11:11:49 +01:00
Murtuza Zabuawala f0202228d0 Increase the default size of the Grant Wizard to enable it to properly display privileges at the default size on smaller displays. Fixes #2013 2017-06-21 11:08:23 +01:00
Dave Page bf5a2252af Install the Yarn deps before trying to bundle. 2017-06-20 12:06:35 +01:00
Dave Page 9829d74a04 Correct the v10 template path. 2017-06-20 12:04:13 +01:00
Dave Page c5616c7869 Run yarn tasks where required to run the tests. 2017-06-20 11:58:54 +01:00
Dave Page bd917f2348 Create a runner for the feature tests. 2017-06-20 11:51:22 +01:00
Murtuza Zabuawala 34518d328e No need for the menu icon to link to the homepage, as pgAdmin is a SPA. Fixes #2479 2017-06-20 10:28:35 +01:00
Murtuza Zabuawala d2ba57c1ab Properly handle bytea[], and 'infinity'::real/real[]. Fixes #2498. Fixes #2502. 2017-06-20 10:19:11 +01:00
Neel Patel a21dad4c45 Fix runtime support under Qt4 2017-06-16 11:26:31 +01:00
Khushboo Vashi 1ee555e468 Ensure the feature tests use the correct test settings database. Fixes #2486 2017-06-16 10:17:38 +01:00
Neel Patel 0056a94115 Add support for detachable tabs to the runtime.
This allows the Query Tool, Debugger and web browser tabs to be moved to different monitors as desired.

Fixes #1344
2017-06-16 09:57:19 +01:00
Ashesh Vashi 900ccebb50 Using client-side implementation of 'url_for' in the settings module. 2017-06-16 08:57:23 +05:30
Ashesh Vashi 5c140b3f58 Using client-side 'url_for' implementation in the user management
module.
2017-06-16 00:16:30 +05:30
Ashesh Vashi e65b605912 Using client-side 'url_for' implementation in the import/export module. 2017-06-16 00:00:17 +05:30
Ashesh Vashi 07580b8444 Using client-side 'url_for' implementation in the maintenance module. 2017-06-15 23:50:53 +05:30
Dave Page 5d45dee686 Fix Yarn tasks for Windows 2017-06-15 15:32:07 +01:00
Johan Van de Wauw 827aa72e99 Fix a typo in the config file 2017-06-15 15:18:59 +01:00
Surinder Kumar 2a87585665 Fix script options which were inadvertently broken in the query tool tab naming patch. 2017-06-15 12:19:47 +01:00
Murtuza Zabuawala d70c3003d3 Add double precision[] tests to the query tool. 2017-06-15 11:54:17 +01:00
Murtuza Zabuawala 8376d33d77 Fix canceling of Grant Wizard on Windows. Fixes #2142 2017-06-15 11:42:13 +01:00
Dave Page 6938fbafb5 Add some more Makefile targets for running different test suites. 2017-06-14 14:11:51 +01:00
Surinder Kumar fdc9eed514 Ensure text editors render in an appropriate place on the results grid. Fixes #2477 2017-06-14 12:18:27 +01:00
Surinder Kumar 2b4a8ed89c Un-break the feature tests. Fixes from Surinder and myself. 2017-06-14 09:59:11 +01:00
Joao Pedro De Almeida Pereira 4b846ae4e0 Fix the JS Bundler test to work when there are multiple servers defined in a test run. 2017-06-14 09:37:20 +01:00
Dave Page cb97722fc3 Temporarily disable the Javascript bundler test until it handle more than one run. 2017-06-13 14:21:41 +01:00
Surinder Kumar 57d866f7b7 Use a more sensible name for Query Tool tabs. Fixes #2482 2017-06-13 11:34:24 +01:00
Ashesh Vashi 467825c2d1 Package 'mock' is required for testing, and for Python < 3.3 only. 2017-06-13 15:57:56 +05:30
Akshay Joshi 794b70daea Fixed issue of opening file manager dialog from Query Tool. 2017-06-13 15:48:12 +05:30
Ashesh Vashi 903389d7b7 Required mock package for python < 3.3.
It was required for the commit:
1208206bc0

Also, do not fetch the scenario-name, when it is not avaiable (but - use
default vaule as the stringified test-case itself).
2017-06-13 15:43:31 +05:30
Joao Pedro De Almeida Pereira a9ce9c9717 Skip a test that uses the COLLATE option on PG versions below 9.1 (e.g. Greenplum). 2017-06-13 10:27:09 +01:00
Khushboo Vashi 3a5fda44e4 Add a shortcut (Ctrl/Cmd + 0 (zero)) to the runtime to allow the zoom level to be reset. Fixes #2485 2017-06-13 10:21:51 +01:00
Shruti B Iyer 1208206bc0 Initial re-vamp of the History tab. 2017-06-13 09:50:41 +01:00
Khushboo Vashi 16a15bf934 Fix the fix for RM2324. 2017-06-13 09:18:44 +01:00
Ashesh Vashi 0243d886c3 Using client-side 'url_for' implementation in the Grant-Wizard module. 2017-06-13 11:47:55 +05:30
Ashesh Vashi f9a3878220 Using client-side 'url_for' implementation in the restore module. 2017-06-13 11:00:17 +05:30
Ashesh Vashi 4a46f7b1eb Using client-side 'url_for' implementation in the backup module. 2017-06-13 10:59:11 +05:30
Ashesh Vashi 1a7c9d5ca1 Using client-side 'url_for' implementation in the module - bgprocess
(background-processes).
2017-06-13 09:18:48 +05:30
Shruti B Iyer f1acad85db Add a missing translation call. 2017-06-12 17:20:40 +01:00
Shruti B Iyer 3f4f8b9e77 Add linting support, and, well, lint. 2017-06-12 16:55:14 +01:00
Shruti B Iyer 659eb1c1e8 Bring React into the tree, and add linting and bundling framework for the JS etc. 2017-06-12 16:51:54 +01:00
Surinder Kumar af43ccfc07 Teach dialogues about Escape to cancel, Enter to Save/OK, and F1 for help. Fixes #1535 2017-06-12 16:43:29 +01:00
Murtuza Zabuawala ec5bc23dfd Allow editing of the WITH ADMIN option of role membership. Fixes #2086 2017-06-12 13:58:51 +01:00
Murtuza Zabuawala 3743c6e86e Refresh the SQL editor view on resize to ensure the contents are re-rendered for the new viewport. Fixes #2078 2017-06-12 13:25:52 +01:00
Murtuza Zabuawala c435d48885 Properly handle trigger functions with parameters. Fixes #2043 2017-06-12 13:19:49 +01:00
Atul Sharma 49cd578816 Fix error on the stats tab with PG10. Also, rename the 10.0_plus template directory to 10_plus to match the new versioning. Fixes #2450 2017-06-12 12:53:09 +01:00
Khushboo Vashi 8bd8ae001b Fix the PostGIS Datatypes in SQL tab, Create / Update dialogues for Table, Column, Foreign Table and Type node. Fixes #2324
Note that this doesn't add full support for PostGIS types to the table/column dialogues, which still can't handle the typmod usage. It does bring support to parity with pgAdmin 3 though.
2017-06-12 12:49:17 +01:00
George Gelashvili 59da69087c Stop ignoring yarn.lock, per discussion with Pivotal team. 2017-06-12 09:16:32 +01:00
Ashesh Vashi fd3ddbeafb Implementation of the client side 'url_for(...)' function.
Created a url_for function module to be used by different javascript
modules to use the same functionality of flask at client side.

A python module can expose the list of endpoints, used by its
javascripts, by overriding the 'get_exposed_url_endpoints(self)'
function.

In this patch, we have modified all the browser modules to use this
function. It will allow us to move the majority of the javascript
modules of browser nodes from templates directory to the static
directory.

TODO::
- Move these javascripts modules to the static directory.
- Use this function in all the applicable javascript modules.
  e.g. tools, miscellaneous modules
2017-06-12 12:01:25 +05:30
Dave Page dea850b503 Tune startup retry loop - try 50 times, with a 100ms pause between each attempt. 2017-06-11 14:38:22 +01:00
Dave Page ef4b8e8c1c Another minor perf tweak for the runtime. 2017-06-11 14:34:49 +01:00
Dave Page f0d287588a Couple of minor performance tweaks. Tests on my Windows VM show a consistent 30% startup time reduction. 2017-06-11 13:56:49 +01:00
Surinder Kumar 49976b1934 Fine tune result grid column sizing now we don't have checkboxes. 2017-06-09 09:24:20 +01:00
Sarah McAlear ee4a847784 Use the correct font for the treeview. 2017-06-09 09:09:39 +01:00
Surinder Kumar 73c6f1ca3b A little leanup of the styling of the edit grid 2017-06-08 17:06:34 +01:00
Harshal Dhumal aa400cbc12 Fix integer/numeric validation on various dialogues. Fixes #2421 2017-06-08 14:59:26 +01:00
Murtuza Zabuawala 3bcbc50525 Fix the handling of double precision[] type. Fixes #1928 2017-06-08 14:50:51 +01:00
Surinder Kumar c9b717ed68 Set focus on the first enabled field when a dialogue is opened. Fixes #1533 2017-06-08 14:37:31 +01:00
Sarah McAlear 01bfa88309 Improvements to the Query Results grid:
- Improve the UI
- Allow copy/paste from sets of rows, columns or arbitrary blocks of cells

Patch by Matt, Shruti, Joao and Sarah @ Pivotal

Fixes #2476
2017-06-08 13:31:36 +01:00
Surinder Kumar 2fddf750e6 Retain column sizing in the query tool results grid when the same query is re-run multiple times in a row. Fixes #1971 2017-06-08 12:41:56 +01:00
Murtuza Zabuawala 678b891ff7 Fix an intermittent error seen during result polling. Fixes #2470 2017-06-08 12:34:14 +01:00
Murtuza Zabuawala b149fe371e Fix various issues with pgAgent job steps and schedules:
1) Error on clicking SQL panel when Schedule OR Step node is selected in browser. Fixes #1888

2) Error while dropping Schedule OR Step node. Fixes #1889

3) Newly created Schedule/Step node was not displaying in browser. Fixes #1890
2017-06-08 12:30:00 +01:00
Surinder Kumar 88737248ab Fix a couple of missing greys. 2017-06-07 16:31:47 +01:00
Surinder Kumar 63c093248d Allow users to remove default values from columns properly. Fixes #2461 2017-06-07 14:33:28 +01:00
George Gelashvili f89aec867a Resolve the PG datatype feature test flakiness and make for a nice buttery crust. 2017-06-07 14:26:42 +01:00
George Gelashvili 8d8e7dab3c Extract row staging into it's own module with tests. 2017-06-07 14:17:10 +01:00
Shruti B Iyer 0d05385585 Update the styling to use the set of grays defined in the WIP style guide. 2017-06-07 13:57:49 +01:00
Murtuza Zabuawala 495a3cedb0 List packages in PPAS 9.2-9.4 when creating synonyms. Fixes #1813 2017-06-07 13:44:36 +01:00
Khushboo Vashi b134ae2cb4 Fix the RE-SQL for for views to properly qualify trigger function names. Fixes #2381 2017-06-07 13:40:11 +01:00
Ashesh Vashi ae80976689 Using the client-side translation using the client-side 'gettext'
implementation.

This is the first step towards 'Avoid creating the javascript modules
using Jinja templates'.
2017-06-07 15:53:05 +05:30
Murtuza Zabuawala 7e9f82bc17 Prevent attempts to debug procedures with variadic arguments. Fixes #1466 2017-06-06 12:58:52 +01:00
Surinder Kumar beda7ebbf2 Add feature tests for the View Data tool. 2017-06-06 12:54:20 +01:00
Murtuza Zabuawala 9803468a77 Properly display security labels on EPAS 9.2+. Fixes #1575 2017-06-06 11:46:49 +01:00
Murtuza Zabuawala cd3484d936 Make $ quoting consistent. Fixes #1525 2017-06-06 11:40:25 +01:00
Surinder Kumar b82e001478 Ensure that boolean checkboxes cycle values in the correct order. Fixes #2448 2017-06-06 11:29:18 +01:00
Murtuza Zabuawala bf06d82870 Fix validation for external and range types. Fixes #1795 2017-06-06 11:24:10 +01:00
Murtuza Zabuawala e6aa3e1494 Fix default values and SQL formatting for event triggers. Fixes #1229 2017-06-06 11:19:40 +01:00
Dave Page 4c2004d479 Correct the validation logic when modifying indexes/exclusion constraints. Fixes #2113 2017-06-06 11:15:51 +01:00
Khushboo Vashi d21cbb8b1f Handle composite primary keys correctly when deleting rows in the Edit Grid. Fixes #2425 2017-06-06 09:58:47 +01:00
Murtuza Zabuawala 4b74a5ff35 Enable dialogue help buttons on Language and Foreign Table dialogues. Fixes #2116 2017-06-06 09:52:44 +01:00
Murtuza Zabuawala 0bc9997a95 Properly refresh the parent node when renaming children. Fixes #2355 2017-06-06 09:50:05 +01:00
Dave Page 9e98ded06c Display and allow toggling of trigger enable/disable status from the trigger dialogue. Fixes #2386 2017-06-05 17:11:21 +01:00
Murtuza Zabuawala 3f150f3f4e Handle procedure flags (IMMUTABLE STRICT SECURITY DEFINER PARALLEL RESTRICTED) properly in RE-SQL on EPAS. Fixes #2280 2017-06-05 17:04:55 +01:00
Murtuza Zabuawala a4d86d24e6 Cache statistics more reliably. Fixes #2357 2017-06-05 17:01:03 +01:00
Dave Page 12fa023c6d Fix a couple of issue descriptions. 2017-06-01 13:00:36 +01:00
Karen Blatchley 54760ef3bb Add documented release notes. 2017-06-01 12:29:37 +01:00
Dave Page 1b23a7912a Fix permissions on some files. 2017-05-31 16:48:09 +01:00
Surinder Kumar 456096092d Avoid re-rendering the edit grid for every row that is pasted. 2017-05-30 16:22:11 +01:00
Neel Patel 6e24cb038a Ensure the runtime works correctly if a Windows user has a proxy server enabled. 2017-05-30 13:17:07 +01:00
Surinder Kumar 1f26953504 Cleanup handling of default/null values when data editting. FIxes #2400 2017-05-27 14:51:02 -04:00
George Gelashvili 10caae4dc6 Increase feature test timeouts. 2017-05-27 14:17:06 -04:00
Dave Page 6abc4c239a Improve docs on patch creation 2017-05-26 16:55:20 -04:00
Murtuza Zabuawala 8aabee352c Import the ordereddict module for Python 2.6 2017-05-26 12:34:05 -04:00
Murtuza Zabuawala 2c9af4784e Allow creation of ENUM types with no members. Fixes #2426 2017-05-26 12:21:23 -04:00
Murtuza Zabuawala dba64e77f1 Order columns in multi-column pkeys correctly. Fixes #2417 2017-05-26 11:04:32 -04:00
Murtuza Zabuawala 45d423c0ce Ensure the last placeholder is included when generating UPDATE scripts for tables. Fixes #2436 2017-05-26 10:59:09 -04:00
Murtuza Zabuawala a45bb905f5 Pass the database ID to the query tool when using the Script options. Fixes #2435 2017-05-26 10:57:31 -04:00
Khushboo Vashi 3216eca4a8 Add feature tests to ensure that data types are properly rendered in the query tool. 2017-05-26 10:46:58 -04:00
Dave Page 2f097cd016 Fix typo in freshly added check. 2017-05-25 17:10:41 -04:00
Murtuza Zabuawala e9da157cc7 Add numerous missing checks to ensure objects really exist when we think they do. Fixes #2427 2017-05-25 16:28:04 -04:00
Dave Page 04ce72a6ae Fix RE-SQL for rules which got the table name wrong in the header and DROP statement. Fixes #2422 2017-05-19 12:21:29 +01:00
Murtuza Zabuawala eb18320950 Improve error handling in cases where the user tries to rename or create a server group that would duplicate an existing group. Fixes #2414 2017-05-17 15:57:38 +01:00
Dave Page 17de7db70b Fix server stats display for EPAS 9.2, where inet needs casting to text for concatenation. Fixes #1831 2017-05-17 15:53:13 +01:00
Murtuza Zabuawala a3226b1eb5 Reverse engineer SQL for table-returning functions correctly. Fixes #1851 2017-05-17 15:49:56 +01:00
Murtuza Zabuawala 655d5888a6 Various FTS dictionary cleanups. Fixes #1126 2017-05-17 14:13:05 +01:00
Surinder Kumar 1db81da020 Fix JS error when selecting a single grid cell. 2017-05-16 08:44:29 +01:00
Dave Page 4817b37742 Include backports.csv as a python dependency in the wheel. 2017-05-15 16:42:40 +01:00
Dave Page be42b67f79 Ensure all required directories are created before we start logging. 2017-05-15 15:59:47 +01:00
Surinder Kumar d7d4bf475b Various improvements to the NULL/DEFAULT handling in the data editor. Fixes #2399 2017-05-15 15:04:16 +01:00
Dave Page aa554eb767 Ensure that there's an __init__.py file present in the backports module directory on Windows 2017-05-15 15:03:15 +01:00
Dave Page 001e0ce1cf Mac build fixes:
- Rebuild Python packages from scratch so we know what libraries they use
- Ensure the backports Python module has an __init__.py file.
2017-05-15 14:38:52 +01:00
Murtuza Zabuawala 1cb2a62fa8 Ensure object names are properly escaped for external process management. Fixes #2405 2017-05-15 13:01:12 +01:00
Dave Page f0e78309cb Bump version in preparation for release. 2017-05-15 12:25:28 +01:00
Neel Patel 07b06348ab While building runtime with QtWebEngine, we found 2 compilation errors which were introduced in a previous commit in runtime:
We set "setNetworkAccessManager" in WebEnginePage which was only required for Webkit so removed that statement.
"triggerAction" on WebPage is only required for Qt > 5 with WebKit only. Not required for WebEngine so added that condition.
2017-05-15 11:29:14 +01:00
Murtuza Zabuawala 2ad14b379e Validate table presence in SQL and Properties route handles. Fixes #2395 2017-05-15 10:15:09 +01:00
Joao Pedro De Almeida Pereira 3bf17d9df4 1) Splits the SQL query used to retrieve the Dependents, Dependencies, and Roles SQL file into multiple versioned files.
2) Add Unit Tests for each file.
3) Add ORDER BY into Copy Selection Feature test to ensure the results are retrieved always in the same order
4) Renamed the Scenario of the xss_checks_pgadmin_debugger_test and skip it for versions less than 9.1
5) Deleted unused __init__.py files.
2017-05-15 10:40:46 +05:30
Surinder Kumar 0e7efc0cf8 Track disabled rows properly in the edit grid. 2017-05-12 16:42:06 +01:00
Murtuza Zabuawala aea0d93390 Hide menu options for creating objects, if the object type is set to hidden. Includes Jasmine tests. Fixes #2225 2017-05-12 12:10:46 +01:00
Dave Page dd318e679d Minor colour tweaks for highlighted rows in the data editor. These are likely to be changed again when we overhaul and standardise the colouring, but at least now they're using colours from the style guide. 2017-05-12 11:29:46 +01:00
Akshay Joshi 1f903ba231 Updated psycopg2 version for PostgreSQL 10 compatibility. Fixes #2377 2017-05-12 15:43:03 +05:30
Surinder Kumar 4f9628ed43 Improve handling of nulls and default values in the data editor. Fixes #2257 2017-05-12 10:53:57 +01:00
Murtuza Zabuawala 05787fdba9 Properly handle non-ASCII column names in CSV. Fixes #2314 2017-05-12 10:38:23 +01:00
Murtuza Zabuawala 94cbd70370 Don't change the trigger icon back to "enabled" when the trigger is updated when it's disabled. Fixes #2271 2017-05-10 09:48:21 +01:00
Murtuza Zabuawala 9452e0699e Allow creation of tables with pure numeric names. Fixes #2284 2017-05-10 09:40:32 +01:00
Neel Patel 3ed00d3be7 1) Fixed compilation issue with QT4.
2) Make trigger action 'RequestClose' backword compatible with annulen webkit.
2017-05-10 13:34:39 +05:30
Andrei Antonov cbf2de6c27 HTML escape the label, when setting the collection node count along
with the label of the tree-nodes.
2017-05-10 13:26:18 +05:30
Magnus Hagander 29217946c3 Relax version dependency on psycopg2
Right now psycopg2 is required to be exactly version 2.6.2, which makes it mostly impossible to install pgadmin4 without having the postgresql C development packages installed (since you need to rebuild psycopg2 from source to make that work, given that few platforms ship *exactly* that version).
2017-05-09 12:32:20 +01:00
Murtuza Zabuawala 13f4432bbd Support loading files with Unicode BOMs. Fixes #2369 2017-05-09 12:06:49 +01:00
Neel Patel d0e9c82fea Fixes #2328
1) Fixed issue of opening Query Tool and Debugger in new Tab with QT 5.8 and annulen webkit
 2) Moved unload event of window from javascript files to html.
 3) Change alertify messages for debugger.
 4) Closed all connections created by debugger. Previously only one connection has been closed.
2017-05-09 13:03:44 +05:30
Murtuza Zabuawala 63d42745ef Fix various issues in CSV file download feature:
1) To handle non-ascii filenames which we set from table name. Fixes #2314

2) To handle non-ascii query data. Fixes #2253

3) To dump JSON type columns properly in csv. Fixes #2360
2017-05-08 13:36:11 +01:00
Harshal Dhumal a80f760933 Only reconnect to databases that were previously connected. Fixes #2292 2017-05-08 12:36:51 +01:00
Khushboo Vashi 94b7fc483a Fix sorting of sizes on the statistics views by sorting raw values and prettifying on the client side. Includes Jasmine tests for the prettyfying function. Fixes #2315 2017-05-08 11:29:13 +01:00
Navnath Gadakh c32bf7780e Windows compatibility fixes for the test suite. 2017-05-08 09:25:05 +01:00
Murtuza Zabuawala 155348d712 Fix the Backup module where it was not working if user changes its preference language other than english. Fixes #2354 2017-05-04 16:06:10 +01:00
Murtuza Zabuawala 95f763463f Fix an issue in NodeAjaxControl caching with cache-node field and add cache-node field in Trigger & Event trigger node so that whenever the user creates new Trigger Function we get new data from server in NodeAjaxControl. . Fixes #2242 2017-05-04 16:02:28 +01:00
Surinder Kumar 93df5e3e54 Ensure errors thrown when deleting rows in the query tool in edit mode are shown properly. Fixes #2356 2017-05-02 12:20:30 +01:00
Sarah McAlear 4acecfa59a Use a different server name for unit vs. feature tests to avoid some observed conflicts. 2017-05-02 12:00:30 +01:00
Murtuza Zabuawala 6790bfd0c0 Fixed handling of default parameters ordering in functions. Fixes #2350 2017-04-25 18:40:44 +05:30
Murtuza Zabuawala 1ce1f216ca Fixed handling of nested privileges. Fixes #2335 2017-04-25 12:39:46 +05:30
Murtuza Zabuawala 38c8a4fb60 Fix handling of bigint[] type. Fixes #2272 2017-04-25 12:24:02 +05:30
Murtuza Zabuawala 928c0d3de8 startsWith() function of java script is not supported in IE, instead use startsWith() function of underscore string. Fixes #2347 2017-04-25 12:00:15 +05:30
Joao Pedro De Almeida Pereira f718e1f49c Only display the header row in SlickGrid where columns actually exist. 2017-04-24 20:26:59 +01:00
Akshay Joshi a449be784e Initial support for PG 10.0, per #2214 (missed some files) 2017-04-24 13:56:01 +01:00
Akshay Joshi 59834fba31 Initial support for PG 10.0, per #2214 2017-04-24 13:55:29 +01:00
Joao Pedro De Almeida Pereira 3eb92f7ea3 Update test requirements for the latest rev of Chrome. 2017-04-24 13:07:04 +01:00
Ashesh Vashi 139a10e8f9 Added dependency on Flask-Migrate added by previous commit:
6283ef7f5e
2017-04-24 16:26:50 +05:30
Sarah McAlear 6283ef7f5e [Configuration][Migration] Use 'alembic' for migration of the SQLite
based configuration file from one version to another, and also allows us
to have a single path of creating the table instead of creating tables
using SQLAlchemy or hand rolled SQL

This allows us to run the migrations directly in the code, and it will
avoid the error prone version numbering.

Patched by: Sarah McAlear
Revisions: Joao Pedro De Almeida Pereira, George Gelashvili.
Reviewed by: Ashesh Vashi, Murtuza Zabuawala
2017-04-24 08:37:27 +05:30
Dave Page 04ccc84bf6 Revert "Update Chromedriver version for Chrome 58."
This reverts commit 70832286bc.

The Jenkins CI doesn't like this at all.
2017-04-21 10:15:17 +01:00
Dave Page f6ffaaff98 Revert "Ensure PIP is the latest version when running the CI tests."
This reverts commit bf1f4aefa6.
2017-04-21 10:15:05 +01:00
Dave Page bf1f4aefa6 Ensure PIP is the latest version when running the CI tests. 2017-04-21 10:04:47 +01:00
Khushboo Vashi 618d9bc7a9 Enable horizontal scrolling in the treeview. Fixes #2339 2017-04-21 10:00:22 +01:00
Joao Pedro De Almeida Pereira 70832286bc Update Chromedriver version for Chrome 58.
Note:
If you had previously installed the old driver you need to uninstall and install again it.

$ pip uninstall chromedriver_installer
$ pip install -r regression/requirements.txt
2017-04-21 09:54:18 +01:00
Jonas Thelemann 929a43c9fa Prevent the top-left logo from changing colour when clicked. 2017-04-18 15:09:09 +01:00
Jonas Thelemann 649b064cf3 Re-order Makefile targets for readability. 2017-04-18 15:05:32 +01:00
Jonas Thelemann 8e127cf4fa German translation update. 2017-04-18 15:03:36 +01:00
Jonas Thelemann 7deb570b61 Translation doc update:
- ...anonymized the language codes (ISO 639-1, $LANG)
 - ...clarified the "Updating and Merging" description and removed the examples as they were pretty useless in my eyes. Correct me if they had a meaning.
 - ...anonymized the bash user
 - ...updated the "New Language" section
2017-04-18 15:02:35 +01:00
Dave Page 9f6041b2a7 Revert "Ensure the treeview can be scrolled horizontally. Fixes #2339"
This reverts commit 78c25cef21 which apparently prevents tree nodes being collapsed.
2017-04-18 14:51:26 +01:00
Khushboo Vashi 8d6add13c0 Order foreign table columns correctly. Fixes #2318 2017-04-18 14:37:30 +01:00
Khushboo Vashi 78c25cef21 Ensure the treeview can be scrolled horizontally. Fixes #2339 2017-04-18 14:01:13 +01:00
Khushboo Vashi a3007b7335 Ensure database driver names and description strings can be translated. Fixes #2190 2017-04-18 13:33:27 +01:00
Matthew Kleiman d663d553c5 Allow column or row selection in the query tool. Fixes #2216 2017-04-18 13:28:45 +01:00
Murtuza Zabuawala c35dbc7211 Proper alignment of dropdown menu labels 2017-04-14 15:53:25 +05:30
Akshay Joshi 0d566a6f3a Changed switch label from True/False to Show/Hide for 'Package Functions' and 'Package Procedures' node in Preferences dialog. 2017-04-14 14:57:38 +05:30
Surinder Kumar 9bbc05051c Remove some unused events. 2017-04-12 15:46:31 +01:00
Murtuza Zabuawala 019c1302cb Update inode info when refreshing treeview nodes. Fixes #2336 2017-04-12 13:29:56 +01:00
Akshay Joshi cbee76eac8 Align labels with switches properly. 2017-04-12 13:28:07 +01:00
Navnath Gadakh 62716c4193 Include passed test results in the JSON output from the regression tests. 2017-04-12 13:11:53 +01:00
Murtuza Zabuawala 7dd9efd811 Fix binary search algorithm so new treeview nodes are added in the correct position. Fixes #2331 2017-04-12 13:01:24 +01:00
1533 changed files with 137006 additions and 210403 deletions

No files matched your search

+2 -1
View File
@@ -12,6 +12,7 @@
.idea
.vscode
/dist
/docker-build
/mac-build
/pip-build
/src-build
@@ -37,4 +38,4 @@ runtime/ui_BrowserWindow.h
web/config_local.py
web/regression/test_config.json
node_modules/
yarn.lock
web/pgAdmin/static/js/generated
+26 -9
View File
@@ -164,6 +164,12 @@ REM Main function Ends
CD "%WD%\web"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
ECHO Install Javascript dependencies
call yarn install
ECHO Bundle all Javascript
call yarn run bundle
XCOPY /S /I /E /H /Y "%WD%\web" "%PGBUILDPATH%\web" > nul
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
@@ -201,6 +207,9 @@ REM Main function Ends
ECHO Removing Sphinx
pip uninstall -y sphinx Pygments alabaster colorama docutils imagesize requests snowballstemmer
ECHO Fixing backports.csv - adding missing __init__.py
type nul >> "%PGBUILDPATH%\%VIRTUALENV%\Lib\site-packages\backports\__init__.py"
ECHO Assembling runtime environment...
CD "%WD%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
@@ -247,10 +256,19 @@ REM Main function Ends
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\Qt5MultimediaWidgets.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libQt5WebKit.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libQt5WebKitWidgets.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
IF %QT_VERSION% GEQ 5.9 (
copy "%QTDIR%\bin\Qt5WebKit.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\Qt5WebKitWidgets.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
) ELSE (
copy "%QTDIR%\bin\libQt5WebKit.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libQt5WebKitWidgets.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
)
copy "%QTDIR%\bin\icudt57.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\icuin57.dll" "%PGBUILDPATH%\runtime"
@@ -259,13 +277,13 @@ REM Main function Ends
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libgcc_s_dw2-1.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libstdc++-6.dll" "%PGBUILDPATH%\runtime"
copy "%QTDIR%\bin\libstdc++-6.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libwinpthread-1.dll" "%PGBUILDPATH%\runtime"
copy "%QTDIR%\bin\libwinpthread-1.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libxml2-2.dll" "%PGBUILDPATH%\runtime"
copy "%QTDIR%\bin\libxml2-2.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
copy "%QTDIR%\bin\libxslt-1.dll" "%PGBUILDPATH%\runtime"
copy "%QTDIR%\bin\libxslt-1.dll" "%PGBUILDPATH%\runtime"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
MKDIR "%PGBUILDPATH%\runtime\platforms"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
@@ -384,7 +402,6 @@ REM Main function Ends
:CLEANUP_ENV
ECHO Cleaning up private environment...
rd "%PGBUILDPATH%\%VIRTUALENV%\Include" /S /Q
rd "%PGBUILDPATH%\%VIRTUALENV%\Scripts" /S /Q
DEL /s "%PGBUILDPATH%\%VIRTUALENV%\pip-selfcheck.json"
ECHO Cleaned up private environment successfully.
+6 -1
View File
@@ -238,6 +238,12 @@ REM Main function Ends
CD "%WD%\web"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
ECHO Install Javascript dependencies
call yarn install
ECHO Bundle all Javascript
call yarn run bundle
XCOPY /S /I /E /H /Y "%WD%\web" "%PGBUILDPATH%\web" > nul
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
@@ -500,7 +506,6 @@ REM Main function Ends
:CLEANUP_ENV
ECHO Cleaning up private environment...
rd "%PGBUILDPATH%\%VIRTUALENV%\Include" /S /Q
rd "%PGBUILDPATH%\%VIRTUALENV%\Scripts" /S /Q
DEL /s "%PGBUILDPATH%\%VIRTUALENV%\pip-selfcheck.json"
ECHO Cleaned up private environment successfully.
+58 -34
View File
@@ -16,23 +16,65 @@ SHELL = /bin/sh
# Include only platform-independent builds in all
all: docs pip src
# Include all clean sub-targets in clean
clean: clean-dist clean-docs clean-pip clean-appbundle clean-src
pip: docs
./pkg/pip/build.sh
appbundle: docs
./pkg/mac/build.sh
appbundle-webkit: docs
PGADMIN4_USE_WEBKIT=1 ./pkg/mac/build.sh
src:
./pkg/src/build.sh
install-node:
cd web && yarn install
minimise:
python web/tools/minimise.py ./web
bundle:
cd web && yarn run bundle
bundle-dev:
cd web && yarn run bundle:dev
linter:
cd web && yarn run linter
check: install-node bundle linter
cd web && yarn run karma start -- --single-run && python regression/runtests.py
check-python: install-node bundle
cd web && python regression/runtests.py --exclude feature_tests
check-feature: install-node bundle
cd web && python regression/runtests.py --pkg feature_tests
check-js: install-node linter
cd web && yarn run karma start -- --single-run
# Include all clean sub-targets in clean
clean: clean-appbundle clean-docker clean-dist clean-docs clean-pip clean-src
clean-appbundle:
rm -rf mac-build/
clean-docker:
rm -rf docker-build/
clean-dist:
rm -rf dist/
clean-docs:
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 $(MAKE) -C docs/en_US -f Makefile.sphinx clean
clean-pip:
rm -rf pip-build/
clean-src:
rm -rf src-build/
docker:
./pkg/docker/build.sh
docs:
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 $(MAKE) -C docs/en_US -f Makefile.sphinx html
msg-compile:
cd web && pybabel compile -d pgadmin/translations
msg-extract:
cd web && pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin
@@ -40,28 +82,10 @@ msg-extract:
msg-update:
cd web && pybabel update -i pgadmin/messages.pot -d pgadmin/translations
msg-compile:
cd web && pybabel compile -d pgadmin/translations
docs:
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 $(MAKE) -C docs/en_US -f Makefile.sphinx html
clean-pip:
rm -rf pip-build/
clean-appbundle:
rm -rf mac-build/
clean-src:
rm -rf src-build/
clean-docs:
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 $(MAKE) -C docs/en_US -f Makefile.sphinx clean
clean-dist:
rm -rf dist/
check:
python web/regression/runtests.py
.PHONY: docs
pip: docs
./pkg/pip/build.sh
src:
./pkg/src/build.sh
+17 -1
View File
@@ -18,7 +18,7 @@ utilised.
Although developed using web technologies, pgAdmin 4 can be deployed either on
a web server using a browser, or standalone on a workstation. The runtime/
subdirectory contains a QT based runtime application intended to allow this -
it is essentially a browser and Python interpretor in one package which is
it is essentially a browser and Python interpreter in one package which is
capable of hosting the Python application and presenting it to the user as a
desktop application.
@@ -69,6 +69,22 @@ You can also use Qt Creator to build, develop and debug the runtime. Simply
open the $PGADMIN4_SRC/runtime/pgAdmin4.pro project file in Qt Creator and
configure the project with a supported version of Qt when prompted.
Create Database Migrations
--------------------------
In order to make changes to the SQLite DB, navigate to the 'web' directory:
(pgadmin4) $ cd $PGADMIN4_SRC/web
Create a migration file with the following command:
(pgadmin4) $ FLASK_APP=pgAdmin4.py flask db revision
This will create a file in: $PGADMIN4_SRC/web/migrations/versions/ .
Add any changes to the 'upgrade' function.
There is no need to increment the SETTINGS_SCHEMA_VERSION.
Configuring the Python Environment
----------------------------------
+49
View File
@@ -0,0 +1,49 @@
#!/bin/sh
echo "EXECUTING: Feature tests"
echo
echo "Starting virtual frame buffer..."
echo
Xvfb -ac :99 -screen 0 1280x1024x16 &
FB_PID=$!
export DISPLAY=:99
echo "Creating Python ${PYTHON_VERSION} virtual environment..."
echo
cd $WORKSPACE/
PYTHON_SUFFIX=""
if [[ "$PYTHON_VERSION" == 3* ]]; then
PYTHON_SUFFIX="3"
fi
if [ "$PYTHON_VERSION" == 2.6 -o "$PYTHON_VERSION" == 3.3 ]; then
/usr/bin/virtualenv --no-wheel -p /usr/local/python-$PYTHON_VERSION/bin/python$PYTHON_SUFFIX $WORKSPACE/pgadmin-venv || { echo 'ERROR: Failed to create the Python virtual environment.' ; exit 1; }
. $WORKSPACE/pgadmin-venv/bin/activate || { echo 'ERROR: Failed to activate the Python virtual environment.' ; exit 1; }
$WORKSPACE/pgadmin-venv/bin/pip install wheel==0.29.0 || { echo 'ERROR: Failed to install wheel 0.29.0.' ; exit 1; }
else
/usr/bin/virtualenv -p /usr/local/python-$PYTHON_VERSION/bin/python$PYTHON_SUFFIX $WORKSPACE/pgadmin-venv || { echo 'ERROR: Failed to create the Python virtual environment.' ; exit 1; }
. $WORKSPACE/pgadmin-venv/bin/activate || { echo 'ERROR: Failed to activate the Python virtual environment.' ; exit 1; }
fi
$WORKSPACE/pgadmin-venv/bin/pip install -r requirements.txt || { echo 'ERROR: Failed to install the application requirements.' ; exit 1; }
$WORKSPACE/pgadmin-venv/bin/pip install -r web/regression/requirements.txt || { echo 'ERROR: Failed to install the regression test requirements.' ; exit 1; }
cd web
/usr/bin/yarn install || { echo 'ERROR: Failed to install the required Javascript modules.' ; exit 1; }
/usr/bin/yarn run bundle || { echo 'ERROR: Failed to bundle the Javascript code.' ; exit 1; }
cd ../
echo "Running regression tests..."
echo
$WORKSPACE/pgadmin-venv/bin/python $WORKSPACE/web/regression/runtests.py --pkg feature_tests || { echo 'ERROR: Error detected when running the Feature tests.' ; exit 1; }
echo "Cleaning up..."
echo
kill $FB_PID
+2 -1
View File
@@ -5,5 +5,6 @@ echo
cd $WORKSPACE/web/
/bin/npm install || { echo 'ERROR: Failed to install the required Javascript modules.' ; exit 1; }
/usr/bin/yarn install || { echo 'ERROR: Failed to install the required Javascript modules.' ; exit 1; }
/usr/bin/yarn run linter || { echo 'ERROR: Failed to lint the Javascript code.' ; exit 1; }
./node_modules/.bin/karma start --single-run || { echo 'ERROR: Error detected when running the Jasmine tests.' ; exit 1; }
+9 -13
View File
@@ -3,13 +3,6 @@
echo "EXECUTING: Python tests"
echo
echo "Starting virtual frame buffer..."
echo
Xvfb -ac :99 -screen 0 1280x1024x16 &
FB_PID=$!
export DISPLAY=:99
echo "Creating Python ${PYTHON_VERSION} virtual environment..."
echo
@@ -21,8 +14,15 @@ if [[ "$PYTHON_VERSION" == 3* ]]; then
PYTHON_SUFFIX="3"
fi
/usr/bin/virtualenv -p /usr/local/python-$PYTHON_VERSION/bin/python$PYTHON_SUFFIX $WORKSPACE/pgadmin-venv || { echo 'ERROR: Failed to create the Python virtual environment.' ; exit 1; }
. $WORKSPACE/pgadmin-venv/bin/activate || { echo 'ERROR: Failed to activate the Python virtual environment.' ; exit 1; }
if [ "$PYTHON_VERSION" == 2.6 -o "$PYTHON_VERSION" == 3.3 ]; then
/usr/bin/virtualenv --no-wheel -p /usr/local/python-$PYTHON_VERSION/bin/python$PYTHON_SUFFIX $WORKSPACE/pgadmin-venv || { echo 'ERROR: Failed to create the Python virtual environment.' ; exit 1; }
. $WORKSPACE/pgadmin-venv/bin/activate || { echo 'ERROR: Failed to activate the Python virtual environment.' ; exit 1; }
$WORKSPACE/pgadmin-venv/bin/pip install wheel==0.29.0 || { echo 'ERROR: Failed to install wheel 0.29.0.' ; exit 1; }
else
/usr/bin/virtualenv -p /usr/local/python-$PYTHON_VERSION/bin/python$PYTHON_SUFFIX $WORKSPACE/pgadmin-venv || { echo 'ERROR: Failed to create the Python virtual environment.' ; exit 1; }
. $WORKSPACE/pgadmin-venv/bin/activate || { echo 'ERROR: Failed to activate the Python virtual environment.' ; exit 1; }
fi
$WORKSPACE/pgadmin-venv/bin/pip install -r requirements.txt || { echo 'ERROR: Failed to install the application requirements.' ; exit 1; }
$WORKSPACE/pgadmin-venv/bin/pip install -r web/regression/requirements.txt || { echo 'ERROR: Failed to install the regression test requirements.' ; exit 1; }
@@ -31,7 +31,3 @@ echo
$WORKSPACE/pgadmin-venv/bin/python $WORKSPACE/web/regression/runtests.py --exclude feature_tests || { echo 'ERROR: Error detected when running the Python tests.' ; exit 1; }
echo "Cleaning up..."
echo
kill $FB_PID
+8
View File
@@ -2,6 +2,14 @@ import os
import sys
import inspect
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
root = os.path.realpath(
os.path.dirname(
os.path.realpath(__file__)
+8
View File
@@ -13,6 +13,14 @@
import sys, os
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
# Import the pgAdmin config
root = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, root + '/../../web/')
+32 -32
View File
@@ -16,12 +16,13 @@ packages and users interested in understanding how pgAdmin works.**
Configuration
*************
In order to configure pgAdmin to run in desktop mode, it is first necessary to
configure the Python code to run in single-user mode, and then to configure the
runtime to find and execute the code.
From pgAdmin 4 v2 onwards, the default configuration mode is server, however,
this is overridden by the desktop runtime at startup. In most environments, no
Python configuration is required unless you wish to override other default
settings.
Note that there are multiple configuration files that are read at startup by
pgAdmin. These are as follows:
There are multiple configuration files that are read at startup by pgAdmin. These
are as follows:
* ``config.py``: This is the main configuration file, and should not be modified.
It can be used as a reference for configuration settings, that may be overridden
@@ -35,31 +36,11 @@ pgAdmin. These are as follows:
for end users to change any default or packaging specific settings that they may
wish to adjust to meet local preferences or standards.
Python
------
NOTE: If the SERVER_MODE setting is changed in ``config_distro.py`` or ``config_local.py``,
you will most likely need to re-set the LOG_FILE, SQLITE_PATH, SESSION_DB_PATH
and STORAGE_DIR values as well as they will have been set based on the default
configuration or overridden by the runtime.
In order to configure the Python code, follow these steps:
1. Ensure that any existing configuration database (``pgadmin4.db``) is moved
out of the way in the ``web/`` directory containing the pgAdmin Python code.
2. Create a ``config_local.py`` file alongside the existing ``config.py`` file.
3. Edit ``config_local.py`` and add the following setting:
.. code-block:: python
SERVER_MODE = False
4. Run the following command to create the configuration database:
.. code-block:: bash
$ python setup.py
Alternatively, you can simply run ``pgAdmin4.py`` at this point or aat a later time,
and ``pgadmin4.db`` will be created automatically at first run.
Runtime
-------
@@ -73,6 +54,25 @@ semi-colon character, for example:
/Users/dpage/.virtualenvs/pgadmin4/lib/python2.7/site-packages/;/Users/dpage/python-libs/
The configuration settings are stored using the QSettings class in Qt, which
will use an INI file on Unix systems, a plist file on Mac OS X, and the registry
on Windows. The Python Path setting is stored in the ``PythonPath`` key.
The configuration settings are stored using the QSettings class in Qt, which
will use an INI file on Unix systems (~/.config/pgadmin/pgadmin4.conf),
a plist file on Mac OS X (~/Library/Preferences/org.pgadmin.pgadmin4.plist),
and the registry on Windows (HKEY_CURRENT_USER\\Software\\pgadmin\\pgadmin4).
The configuration settings:
+--------------------------+--------------------+---------------------------------------------------------------+
| Key | Type | Purpose |
+==========================+====================+===============================================================+
| ApplicationPath | String | The directory containing pgAdmin4.py |
+--------------------------+--------------------+---------------------------------------------------------------+
| ConnectionTimeout | Integer | The number of seconds to wait for application server startup. |
+--------------------------+--------------------+---------------------------------------------------------------+
| PythonPath | String | The Python module search path |
+--------------------------+--------------------+---------------------------------------------------------------+
| Browser/Geometry | Binary | The runtime window's size/shape |
+--------------------------+--------------------+---------------------------------------------------------------+
| Browser/WindowState | Binary | The runtime window's state |
+--------------------------+--------------------+---------------------------------------------------------------+
| Browser/Zoom | String | The runtime window's zoom level (zoom % / 100) |
+--------------------------+--------------------+---------------------------------------------------------------+
Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 227 KiB

View File
File mode changed.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File
File mode changed.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Executable → Regular
View File
File mode changed.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 42 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+1
View File
@@ -24,6 +24,7 @@ Contents:
contributions
pgagent
licence
release_notes
+14 -4
View File
@@ -23,6 +23,8 @@ When running in the Desktop Runtime, the following keyboard shortcuts are availa
+--------------------------+----------------+---------------------------------------+
| Ctrl+Minus | Cmd+Minus | Zoom out |
+--------------------------+----------------+---------------------------------------+
| Ctrl+0 | Cmd+0 | Reset the zoom level |
+--------------------------+----------------+---------------------------------------+
**SQL Editors**
@@ -39,6 +41,12 @@ When using the syntax-highlighting SQL editors, the following shortcuts are avai
+--------------------------+------------------+-------------------------------------+
| Ctrl+Alt+Right | Cmd+Option+Right | Move right one word |
+--------------------------+------------------+-------------------------------------+
| Ctrl+/ | Cmd+/ | Comment selected code (Inline) |
+--------------------------+------------------+-------------------------------------+
| Ctrl+. | Cmd+. | Uncomment selected code (Inline) |
+--------------------------+------------------+-------------------------------------+
| Ctrl+Shift+/ | Cmd+Shift+/ | Comment/Uncomment code (Block) |
+--------------------------+------------------+-------------------------------------+
| Ctrl+A | Cmd+A | Select all |
+--------------------------+------------------+-------------------------------------+
| Ctrl+C | Cmd+C | Copy selected text to the clipboard |
@@ -53,6 +61,10 @@ When using the syntax-highlighting SQL editors, the following shortcuts are avai
+--------------------------+------------------+-------------------------------------+
| Ctrl+Minus | Cmd+Minus | Zoom out |
+--------------------------+------------------+-------------------------------------+
| Tab | Tab | Indent selected text |
+--------------------------+------------------+-------------------------------------+
| Shift+Tab | Shift+Tab | Un-indent selected text |
+--------------------------+------------------+-------------------------------------+
**Query Tool**
@@ -77,9 +89,7 @@ When using the Query Tool, the following shortcuts are available:
+--------------------------+--------------------+-----------------------------------+
| Ctrl+G | Cmd+G | Find next |
+--------------------------+--------------------+-----------------------------------+
| Shift+Ctrl+G | Shift+Cmd+G | Find previous |
| Ctrl+Shift+G | Cmd+Shift+G | Find previous |
+--------------------------+--------------------+-----------------------------------+
| Shift+Ctrl+F | Shift+Cmd+F | Replace |
| Ctrl+Shift+F | Cmd+Shift+F | Replace |
+--------------------------+--------------------+-----------------------------------+
| Shift+Ctrl+R | Shift+Cmd+Option+F | Replace all |
+--------------------------+--------------------+-----------------------------------+
View File
File mode changed.
+15 -9
View File
@@ -4,23 +4,23 @@
pgAdmin Preferences
*******************
pgAdmin 4 has a selection of configuration options (*Preferences*) that you can use to customize your pgAdmin client. To open the *Preferences* dialog, select *Preferences* from the *File* menu.
pgAdmin 4 has a selection of configuration options (*Preferences*) that you can use to customize your pgAdmin client. To open the *Preferences* dialog, select *Preferences* from the *File* menu.
.. image:: images/preferences_tree.png
The left pane of the *Preferences* dialog displays a tree control; each node of the tree control provides access to options that are related to the selected node.
The left pane of the *Preferences* dialog displays a tree control; each node of the tree control provides access to options that are related to the selected node.
* Use the plus sign (+) to the left of a node to expand a segment of the tree control.
* Click the minus sign (-) to the left of a node to close that node.
* Use the plus sign (+) to the left of a node to expand a segment of the tree control.
* Click the minus sign (-) to the left of a node to close that node.
Expand the **Browser** node of the tree control to personalize your workspace.
Expand the **Browser** node of the tree control to personalize your workspace.
.. image:: images/preferences_browser_display.png
Use the options on the *Display* dialog to specify general display preferences:
Move the *Show system objects* switch to the *True* position to display system objects in the *pgAdmin* tree control. This option instructs pgAdmin to display objects such as system schemas (e.g. pg_temp*) and system columns (e.g. xmin, ctid) in the tree control.
Use the options on the *Nodes* dialog to select the object types that will be displayed in the *pgAdmin* tree control.
.. image:: images/preferences_browser_nodes.png
@@ -33,7 +33,7 @@ Expand the **Dashboards** node to specify your graphing preferences.
Use the options on the *Graphs* dialog specify a refresh rate for statistics, transaction throughput and tuples. The rate you specify will affect a corresponding graph on the *Dashboard* tab of the *pgAdmin* tabbed browser.
Expand the **Paths** node to specify the locations of supporting files.
Expand the **Paths** node to specify the locations of supporting files.
.. image:: images/preferences_paths_binary.png
@@ -43,7 +43,7 @@ Use the fields in the *Binary paths* node to specify paths to the PostgreSQL bin
Use the *Help* dialog to customize links to support documentation.
* Use the *EDB Advanced Server Help Path* to find a link path for EnterpriseDB Postgres Advanced Server documentation on the company website. This link is editable: substitute the applicable PostgreSQL version number for *$VERSION$*, or provide an alternate link path.
* Use the *EDB Advanced Server Help Path* to find a link path for EnterpriseDB Postgres Advanced Server documentation on the company website. This link is editable: substitute the applicable PostgreSQL version number for *$VERSION$*, or provide an alternate link path.
* Use the *PostgreSQL Help Path* to find a link path to the current set of PostgreSQL core documentation. This link is editable: substitute the applicable PostgreSQL version number for *$VERSION$*, or provide an alternate link path.
Expand the **SQL Editor** node to specify your preferences for the SQL Editor tool.
@@ -68,7 +68,13 @@ Use the options on the *Explain Options* dialog to specify the level of detail i
Use the options in the *Options* dialog to manage modifications to a SQL statement.
* Move the *Auto-Commit* switch to the *True* position to commit a SQL statement upon completion.
* Move the *Auto-Rollback* switch to the *True* to rollback a SQL statement to the beginning of the statement or to a prior rollback.
* Move the *Auto-Rollback* switch to the *True* to rollback a SQL statement to the beginning of the statement or to a prior rollback.
* Move the *Brace matching* switch to the *True* to highlight the matched braces in editor.
* Move the *Font size* field to specify the font size.
* Move the *Insert bracket pairs* switch to the *True* to insert pair brackets in the editor.
* Move the *Line wrapping* switch to the *True* to wrap the long lines in the editor.
* Move the *Tab size* field to specify the number of spaces per tab in the editor.
* Move the *Use spaces* switch to the *True* to insert spaces instead of tabs.
Expand the **Storage** node to specify a maximum file size for uploads.
+19
View File
@@ -0,0 +1,19 @@
*************
Release Notes
*************
pgAdmin release notes provide information on the features and improvements in each release. This page includes release
notes for major releases and minor (bugfix) releases. Select your version from the list below to see the release notes
for it.
.. toctree::
release_notes_2_0
release_notes_1_6
release_notes_1_5
release_notes_1_4
release_notes_1_3
release_notes_1_2
release_notes_1_1
release_notes_1_0
+20
View File
@@ -0,0 +1,20 @@
***********
Version 1.0
***********
Release date: 2016-09-29
The first major release of pgAdmin 4. With a more modern look and feel, this release includes the following features;
* Multiplatform
* Designed for multiple PostgreSQL versions and derivatives
* Extensive documentation
* Multiple deployment models
* Tools
* Routine maintenance
* Create, view and edit all common PostgreSQL objects
* Multibyte support
+55
View File
@@ -0,0 +1,55 @@
***********
Version 1.1
***********
Release date: 2016-10-27
This release contains a number of features and fixes reported since the release of pgAdmin4 1.0;
Features
********
| `Feature #1328 <https://redmine.postgresql.org/issues/1328>`_ - Add Python 3.5 Support
| `Feature #1859 <https://redmine.postgresql.org/issues/1859>`_ - Include wait information on the activity tab of the dashboards
Bug fixes
*********
| `Bug #1155 <https://redmine.postgresql.org/issues/1155>`_ - Display the start value when the user creates sequence
| `Bug #1531 <https://redmine.postgresql.org/issues/1531>`_ - Fix to update privileges for Views and Materials Views where "string indices must be integers error" displayed
| `Bug #1574 <https://redmine.postgresql.org/issues/1574>`_ - Display SQL in SQL pane for security label in PG and EPAS server
| `Bug #1576 <https://redmine.postgresql.org/issues/1576>`_ - Make security label option available in procedure properties
| `Bug #1577 <https://redmine.postgresql.org/issues/1577>`_ - Make debug option available for package function and procedure
| `Bug #1596 <https://redmine.postgresql.org/issues/1596>`_ - Correct spelling error from evnt_turncate to evnt_truncate
| `Bug #1599 <https://redmine.postgresql.org/issues/1599>`_ - Ensure the grant wizard works with objects with special characters in the name
| `Bug #1622 <https://redmine.postgresql.org/issues/1622>`_ - Fix issue using special characters when creating synonym
| `Bug #1728 <https://redmine.postgresql.org/issues/1728>`_ - Properties refreshing after objects are edited
| `Bug #1739 <https://redmine.postgresql.org/issues/1739>`_ - Prevent the user from trying to.....
| `Bug #1785 <https://redmine.postgresql.org/issues/1785>`_ - Correctly identify server type upon first connection
| `Bug #1786 <https://redmine.postgresql.org/issues/1786>`_ - Ensure errorModel unset property is set correctly when adding a new server
| `Bug #1808 <https://redmine.postgresql.org/issues/1808>`_ - Set seconds to valid value in pgAgent job schedule
| `Bug #1817 <https://redmine.postgresql.org/issues/1817>`_ - Display message "server does not support ssl" if server with ca-cert or ca-full added
| `Bug #1821 <https://redmine.postgresql.org/issues/1821>`_ - Optionally sign both the Mac app bundle and the disk image
| `Bug #1822 <https://redmine.postgresql.org/issues/1822>`_ - Handle non-ascii responses from the server when connecting
| `Bug #1823 <https://redmine.postgresql.org/issues/1823>`_ - Attempt to sign the Windows installer, failing with a warning if there's no cert available
| `Bug #1824 <https://redmine.postgresql.org/issues/1824>`_ - Add documenation for pgAgent
| `Bug #1835 <https://redmine.postgresql.org/issues/1835>`_ - Allow users to choose SELECT permissions for tables and sequences in the grant wizard
| `Bug #1837 <https://redmine.postgresql.org/issues/1837>`_ - Fix refreshing of FTS dictionaries which was causing error "Connection to the server has been lost"
| `Bug #1838 <https://redmine.postgresql.org/issues/1838>`_ - Don't append new objects with the wrong parent in tree browser if the correct one isn't loaded
| `Bug #1843 <https://redmine.postgresql.org/issues/1843>`_ - Function definition matches value returned from pg_get_functiondef()
| `Bug #1845 <https://redmine.postgresql.org/issues/1845>`_ - Allow refreshing synonym node. Does not display message "Unimplemented method (node) for this url (/browser/synonym/nodes/1/7/14301/2200/test)"
| `Bug #1847 <https://redmine.postgresql.org/issues/1847>`_ - Identify the collation correctly when reverse engineering table SQL. ERROR: schema "default" does not exist no longer displayed
| `Bug #1849 <https://redmine.postgresql.org/issues/1849>`_ - Remove security keys from config.py/config_local.py
| `Bug #1857 <https://redmine.postgresql.org/issues/1857>`_ - Fix error while renaming FTS dictionary and FTS template nodes
| `Bug #1858 <https://redmine.postgresql.org/issues/1858>`_ - Ensure the File Manager honours the file type while traversing the directories.
| `Bug #1861 <https://redmine.postgresql.org/issues/1861>`_ - Properly generate exclusion constraint SQL.
| `Bug #1863 <https://redmine.postgresql.org/issues/1863>`_ - Correctly quote type names in reverse engineered SQL for tables
| `Bug #1864 <https://redmine.postgresql.org/issues/1864>`_ - Fix layout of DateTimePicker control help message.
| `Bug #1867 <https://redmine.postgresql.org/issues/1867>`_ - Allow package bodies to be dropped.
| `Bug #1868 <https://redmine.postgresql.org/issues/1868>`_ - Resolved issue where Integer type of preferences are not updated
| `Bug #1872 <https://redmine.postgresql.org/issues/1872>`_ - Fix the file manager when used under Python 3.
| `Bug #1877 <https://redmine.postgresql.org/issues/1877>`_ - Ensure preferences values are stored properly.
| `Bug #1878 <https://redmine.postgresql.org/issues/1878>`_ - Ensure steps and schedules can be created in empty jobs. ProgrammingError: can't adapt type 'Undefined' was displayed
| `Bug #1880 <https://redmine.postgresql.org/issues/1880>`_ - Add new indexes to the correct parent on the treeview.
+103
View File
@@ -0,0 +1,103 @@
***********
Version 1.2
***********
Release date: 2017-02-10
This release contains a number of features and fixes reported since the release of pgAdmin4 1.1.
Features
********
| `Feature #1375 <https://redmine.postgresql.org/issues/1375>`_ - Migrate the runtime to QtWebEngine from QtWebKit
| `Feature #1765 <https://redmine.postgresql.org/issues/1765>`_ - Find and replace functionality with regexp and group replacement
| `Feature #1789 <https://redmine.postgresql.org/issues/1789>`_ - Column width of data output panel should fit to data (as pgAdmin III)
| `Feature #1790 <https://redmine.postgresql.org/issues/1790>`_ - [Web] Support setting a field's value to "null"
| `Feature #1848 <https://redmine.postgresql.org/issues/1848>`_ - macOS appbundle is missing postgresql binaries for import etc.
| `Feature #1910 <https://redmine.postgresql.org/issues/1910>`_ - Remember last used directory in the file manager
| `Feature #1911 <https://redmine.postgresql.org/issues/1911>`_ - Direct path navigation in the file manager
| `Feature #1922 <https://redmine.postgresql.org/issues/1922>`_ - Improve handling of corrupt configuration databases
| `Feature #1963 <https://redmine.postgresql.org/issues/1963>`_ - Add a Chinese (Simplified) translation
| `Feature #1964 <https://redmine.postgresql.org/issues/1964>`_ - Create a docs tarball along with the source tarball
| `Feature #2025 <https://redmine.postgresql.org/issues/2025>`_ - Allow the SQL Editors to word-wrap
| `Feature #2124 <https://redmine.postgresql.org/issues/2124>`_ - Create a template loader to simplify SQL template location, and remove duplicate templates
Bug fixes
*********
| `Bug #1227 <https://redmine.postgresql.org/issues/1227>`_ - Display improved error message for Debugger listener starting error and reset between executions
| `Bug #1267 <https://redmine.postgresql.org/issues/1267>`_ - Fix issue where MINIFY_HTML doesn't work with the docs
| `Bug #1364 <https://redmine.postgresql.org/issues/1364>`_ - Ensure dialogue control buttons are consistent
| `Bug #1394 <https://redmine.postgresql.org/issues/1394>`_ - Fix Table dialogue column specification issues
| `Bug #1432 <https://redmine.postgresql.org/issues/1432>`_ - Enhanced OSX File Browser
| `Bug #1585 <https://redmine.postgresql.org/issues/1585>`_ - Cannot save scripts to the network
| `Bug #1599 <https://redmine.postgresql.org/issues/1599>`_ - Ensure the grant wizard works with objects with special characters in the name
| `Bug #1603 <https://redmine.postgresql.org/issues/1603>`_ - Fix quoting of objects names for external utilities.
| `Bug #1679 <https://redmine.postgresql.org/issues/1679>`_ - Re-engineer the background process executor to avoid using sqlite as some builds of components it relies on do not support working in forked children
| `Bug #1680 <https://redmine.postgresql.org/issues/1680>`_ - Render column headers at the correct width in the query tool under Firefox
| `Bug #1729 <https://redmine.postgresql.org/issues/1729>`_ - Improve display of role options
| `Bug #1730 <https://redmine.postgresql.org/issues/1730>`_ - Improve the display of role membership on both the properties panel and role dialogue
| `Bug #1745 <https://redmine.postgresql.org/issues/1745>`_ - Ensure breakpoints are cleared properly when working with Debugger
| `Bug #1747 <https://redmine.postgresql.org/issues/1747>`_ - Add newly created triggers to the treeview
| `Bug #1780 <https://redmine.postgresql.org/issues/1780>`_ - Properly size the SQL Editor gutter as the width of the line numbers increases
| `Bug #1792 <https://redmine.postgresql.org/issues/1792>`_ - List files and folders alphabetically
| `Bug #1800 <https://redmine.postgresql.org/issues/1800>`_ - Handle the template property on databases appropriately
| `Bug #1801 <https://redmine.postgresql.org/issues/1801>`_ - Handle databases with datallowconn == false
| `Bug #1807 <https://redmine.postgresql.org/issues/1807>`_ - Properly detect when files have changed in the query tool and set flag accordingly
| `Bug #1830 <https://redmine.postgresql.org/issues/1830>`_ - Fix a SQL error when reverse-engineering ROLE SQL on EPAS servers
| `Bug #1832 <https://redmine.postgresql.org/issues/1832>`_ - Prevent attempts to access what may be an empty list in Dependancies tab
| `Bug #1840 <https://redmine.postgresql.org/issues/1840>`_ - Enable/disable NULLs and ASC/DESC options for index columns and exclusion constraints appropriately
| `Bug #1842 <https://redmine.postgresql.org/issues/1842>`_ - Show index columns in the correct order in RE-SQL
| `Bug #1855 <https://redmine.postgresql.org/issues/1855>`_ - Ensure dialogue panels show their errors themselves, and not in the properties panel when creating Trigger Function
| `Bug #1865 <https://redmine.postgresql.org/issues/1865>`_ - Properly schema qualify domains when reverse engineering SQL
| `Bug #1874 <https://redmine.postgresql.org/issues/1874>`_ - Add file resources to the windows runtime
| `Bug #1893 <https://redmine.postgresql.org/issues/1893>`_ - Fix refreshing of Unique constraints
| `Bug #1896 <https://redmine.postgresql.org/issues/1896>`_ - Use the correct OID for retrieving properties of freshly created exclusion constraints
| `Bug #1899 <https://redmine.postgresql.org/issues/1899>`_ - Properly quote role names when specifying function ownership
| `Bug #1909 <https://redmine.postgresql.org/issues/1909>`_ - Handle startup errors more gracefully in the runtime
| `Bug #1912 <https://redmine.postgresql.org/issues/1912>`_ - Properly format arguments passed by triggers to functions
| `Bug #1919 <https://redmine.postgresql.org/issues/1919>`_ - Ensure all changes to rows are stored in the data editor
| `Bug #1924 <https://redmine.postgresql.org/issues/1924>`_ - Ensure the check_option is only set when editing views when appropriate
| `Bug #1936 <https://redmine.postgresql.org/issues/1936>`_ - Don't strip \r\n from "Download as CSV" batches of rows, as it leads to malformed data
| `Bug #1937 <https://redmine.postgresql.org/issues/1937>`_ - Generate mSQL for new schemas correctly
| `Bug #1938 <https://redmine.postgresql.org/issues/1938>`_ - Fix sorting of numerics in the statistics grids
| `Bug #1939 <https://redmine.postgresql.org/issues/1939>`_ - Updated dynamic default for the window size (90% x 90%)
| `Bug #1949 <https://redmine.postgresql.org/issues/1949>`_ - Ensure trigger function names are schema qualified in trigger RE-SQL
| `Bug #1951 <https://redmine.postgresql.org/issues/1951>`_ - Fix issue where nnable to browse table columns when oid values exceeed max int
| `Bug #1953 <https://redmine.postgresql.org/issues/1953>`_ - Add display messages and notices received in the query tool
| `Bug #1961 <https://redmine.postgresql.org/issues/1961>`_ - Fix upgrade check on Python 3
| `Bug #1962 <https://redmine.postgresql.org/issues/1962>`_ - Ensure treeview collection nodes are translated in the UI
| `Bug #1967 <https://redmine.postgresql.org/issues/1967>`_ - Store layout changes on each adjustment
| `Bug #1976 <https://redmine.postgresql.org/issues/1976>`_ - Prevent users selecting elements of the UI that shouldn't be selectable
| `Bug #1979 <https://redmine.postgresql.org/issues/1979>`_ - Deal with Function arguments correctly in the properties dialogue
| `Bug #1986 <https://redmine.postgresql.org/issues/1986>`_ - Fix various encoding issues with multibyte paths and filenames resulting in empty file save
| `Bug #1992 <https://redmine.postgresql.org/issues/1992>`_ - Quote identifiers correctly in auto-complete
| `Bug #1994 <https://redmine.postgresql.org/issues/1994>`_ - Update to show modifications in edit grid
| `Bug #2000 <https://redmine.postgresql.org/issues/2000>`_ - Allow setting of effective_io_concurrency on tablespaces in 9.6+
| `Bug #2005 <https://redmine.postgresql.org/issues/2005>`_ - Fix various mis-spellings of VACUUM
| `Bug #2006 <https://redmine.postgresql.org/issues/2006>`_ - Fix error when modifying table name or set schema on tables with postgis geometry column
| `Bug #2007 <https://redmine.postgresql.org/issues/2007>`_ - Correctly sort rows by the pkey when viewing first/last 100
| `Bug #2009 <https://redmine.postgresql.org/issues/2009>`_ - Reset the column list properly if the access method is changed on an index to ensure error handling works correctly
| `Bug #2012 <https://redmine.postgresql.org/issues/2012>`_ - Prevent attempts to create server groups with no name
| `Bug #2015 <https://redmine.postgresql.org/issues/2015>`_ - Enable trigger option when user tries to change Row trigger value through properties section
| `Bug #2024 <https://redmine.postgresql.org/issues/2024>`_ - Properly handle setting comments and other options on databases with allowconn = False
| `Bug #2026 <https://redmine.postgresql.org/issues/2026>`_ - Improve detection of the pldbgapi extension and functions before allowing debugging
| `Bug #2027 <https://redmine.postgresql.org/issues/2027>`_ - Fix inconsistent table styling
| `Bug #2028 <https://redmine.postgresql.org/issues/2028>`_ - Fix display of double scrollbars on the grant wizard
| `Bug #2032 <https://redmine.postgresql.org/issues/2032>`_ - Fix time formatting on dashboards
| `Bug #2033 <https://redmine.postgresql.org/issues/2033>`_ - Show icons for unique and exclusion constraints in the dependency/dependents panels
| `Bug #2045 <https://redmine.postgresql.org/issues/2045>`_ - Update copyright year on doc page
| `Bug #2046 <https://redmine.postgresql.org/issues/2046>`_ - Fix error when setting up regression on Windows for pgadmin4
| `Bug #2047 <https://redmine.postgresql.org/issues/2047>`_ - Ensure dialogues cannot be moved under the navbar
| `Bug #2061 <https://redmine.postgresql.org/issues/2061>`_ - Enable/disable NULLs and ASC/DESC options for index columns and exclusion constraints appropriately
| `Bug #2065 <https://redmine.postgresql.org/issues/2065>`_ - Improve display of columns of exclusion contraints and foreign keys in the properties lists
| `Bug #2069 <https://redmine.postgresql.org/issues/2069>`_ - Correct tablespace displayed in table properties
| `Bug #2076 <https://redmine.postgresql.org/issues/2076>`_ - Handle sized time/timestamp columns correctly
| `Bug #2109 <https://redmine.postgresql.org/issues/2109>`_ - Update copyright year
| `Bug #2110 <https://redmine.postgresql.org/issues/2110>`_ - Handle saved directories that no longer exist gracefully
| `Bug #2112 <https://redmine.postgresql.org/issues/2026>`_ - Enable comments on Initial database through right Click
| `Bug #2133 <https://redmine.postgresql.org/issues/2133>`_ - Fix display of graphical query plans for UPDATE/DELETE queries
| `Bug #2138 <https://redmine.postgresql.org/issues/2138>`_ - Fix display of zeros in read-only grid editors
| `Bug #2139 <https://redmine.postgresql.org/issues/2139>`_ - Fixed issue causing Message (Connection to the server has been lost.) displayed with Materialized view and view under sql tab
| `Bug #2152 <https://redmine.postgresql.org/issues/2152>`_ - Fix handling of "char" columns
| `Bug #2156 <https://redmine.postgresql.org/issues/2156>`_ - Added compatibility fixes for newer versions of Jinja2 (e.g. 2.9.5+)
+49
View File
@@ -0,0 +1,49 @@
***********
Version 1.3
***********
Release date: 2017-03-10
This release contains a number of features and fixes reported since the release of pgAdmin4 1.2.
Features
********
| `Feature #2036 <https://redmine.postgresql.org/issues/2036>`_ - Query tool efficiency - SlickGrid result set format efficiency
| `Feature #2038 <https://redmine.postgresql.org/issues/2038>`_ - Query tool efficiency - Incremental back off when polling
| `Feature #2163 <https://redmine.postgresql.org/issues/2163>`_ - Make syntax highlighting more visible
| `Feature #2210 <https://redmine.postgresql.org/issues/2210>`_ - Build a universal Python wheel instead of per-python-version ones
| `Feature #2215 <https://redmine.postgresql.org/issues/2215>`_ - Improve visibility of syntax highlighting colours
Bug fixes
*********
| `Bug #1796 <https://redmine.postgresql.org/issues/1796>`_ - Add missing "Run Now" option for pgAdmin jobs
| `Bug #1797 <https://redmine.postgresql.org/issues/1797>`_ - Resolve encoding issues with DATA_DIR
| `Bug #1914 <https://redmine.postgresql.org/issues/1914>`_ - Resolved error utf8' codec can't decode byte
| `Bug #1983 <https://redmine.postgresql.org/issues/1983>`_ - Fix bug in Sql query contains Arabic Charaters
| `Bug #2089 <https://redmine.postgresql.org/issues/2089>`_ - Add PARALLEL SAFE|UNSAFE|RESTRICTED support
| `Bug #2115 <https://redmine.postgresql.org/issues/2115>`_ - Fix exclusion constraint reverse engineered SQL
| `Bug #2119 <https://redmine.postgresql.org/issues/2119>`_ - Fix display of long integers and decimals
| `Bug #2126 <https://redmine.postgresql.org/issues/2126>`_ - Correct node labels in Preferences for EDB functions and procedures
| `Bug #2151 <https://redmine.postgresql.org/issues/2151>`_ - Display un-sized varlen column types correctly in the query tool
| `Bug #2154 <https://redmine.postgresql.org/issues/2154>`_ - Fix display of long integers and decimals
| `Bug #2159 <https://redmine.postgresql.org/issues/2159>`_ - Resolve issue where Query editor is not working with Python2.6
| `Bug #2160 <https://redmine.postgresql.org/issues/2160>`_ - Various encoding fixes to allow 'ascii' codec to decode byte 0xc3 in position 66: ordinal not in range(128)
| `Bug #2166 <https://redmine.postgresql.org/issues/2166>`_ - Resolved import/Export issue for a table
| `Bug #2173 <https://redmine.postgresql.org/issues/2173>`_ - Resolved issues where Sequences API test cases are not working in PG9.2 and PPAS9.2
| `Bug #2174 <https://redmine.postgresql.org/issues/2174>`_ - Resolved various file-system encoding/decoding related cases
| `Bug #2185 <https://redmine.postgresql.org/issues/2185>`_ - Removed sorting columns on the treeview
| `Bug #2192 <https://redmine.postgresql.org/issues/2192>`_ - Fix startup complete tests to ensure we properly poll the server for completed startup
| `Bug #2198 <https://redmine.postgresql.org/issues/2198>`_ - Fix function arguments when generating create SQL
| `Bug #2200 <https://redmine.postgresql.org/issues/2200>`_ - Properly handle event trigger functions in different schemas
| `Bug #2201 <https://redmine.postgresql.org/issues/2201>`_ - Fix renaming of check constraints when the table name is changed at the same time
| `Bug #2202 <https://redmine.postgresql.org/issues/2202>`_ - Fix issue where Dependents query fails due to non ascii characters
| `Bug #2204 <https://redmine.postgresql.org/issues/2204>`_ - Fixed issue where pgadmin 4 jobs not showing any activity
| `Bug #2205 <https://redmine.postgresql.org/issues/2205>`_ - Fix display of boolean nulls in the query tool
| `Bug #2208 <https://redmine.postgresql.org/issues/2208>`_ - Ensure primary key column names are quoted in View Data mode of the Query Tool
| `Bug #2212 <https://redmine.postgresql.org/issues/2212>`_ - Ensure servers are deleted when their parent group is deleted
| `Bug #2213 <https://redmine.postgresql.org/issues/2213>`_ - Enable right click on browser tree
| `Bug #2218 <https://redmine.postgresql.org/issues/2218>`_ - Show the correct indeterminate state when editing new boolean values
| `Bug #2228 <https://redmine.postgresql.org/issues/2228>`_ - Authenticate the runtime to the server
| `Bug #2230 <https://redmine.postgresql.org/issues/2230>`_ - Prevent the Slonik logo obscuring the login dialogue on small displays in server mode
+45
View File
@@ -0,0 +1,45 @@
***********
Version 1.4
***********
Release date: 2017-04-13
This release contains a number of features and fixes reported since the release of pgAdmin4 1.3.
Features
********
| `Feature #2232 <https://redmine.postgresql.org/issues/2232>`_ - Add the ability to gray-out/disable the "Save Password" option when creating a connection to a server
| `Feature #2261 <https://redmine.postgresql.org/issues/2261>`_ - Display table DDL for Greenplum in SQL tab
| `Feature #2320 <https://redmine.postgresql.org/issues/2163>`_ - Added German translation
Bug fixes
*********
| `Bug #2077 <https://redmine.postgresql.org/issues/2077>`_ - Add missing "Run Now" option for pgAdmin jobs
| `Bug #2105 <https://redmine.postgresql.org/issues/2105>`_ - Fix validation on the table dialogue so the Save button isn't enabled if the name is removed and autovac custom settings are enabled
| `Bug #2145 <https://redmine.postgresql.org/issues/2145>`_ - Resolve the issue for restoring the table from the backup
| `Bug #2187 <https://redmine.postgresql.org/issues/2187>`_ - Ensure the web/ directory is cleared before upgrading Windows installations
| `Bug #2190 <https://redmine.postgresql.org/issues/2190>`_ - Allow users to select UI language at login or from Preferences rather than unpredictable behaviour from browsers
| `Bug #2226 <https://redmine.postgresql.org/issues/2226>`_ - Show tooltips for disabled buttons to help user learning
| `Bug #2241 <https://redmine.postgresql.org/issues/2241>`_ - Fix numeric control validation in nested schemas
| `Bug #2243 <https://redmine.postgresql.org/issues/2243>`_ - Fix dropping of databases with Unicode names
| `Bug #2244 <https://redmine.postgresql.org/issues/2244>`_ - Prevent an error being displayed if the user views data on a table with no columns
| `Bug #2246 <https://redmine.postgresql.org/issues/2246>`_ - Add missing braces to reverse engineered SQL header block for Functions
| `Bug #2258 <https://redmine.postgresql.org/issues/2258>`_ - Fix handling of DATERANGE[] type
| `Bug #2264 <https://redmine.postgresql.org/issues/2264>`_ - Resolve error message *ExtDeprecationWarning* displayed on new pgAdmin4 setup for Python 3.4 on ubuntu 14.04 Linux 64
| `Bug #2265 <https://redmine.postgresql.org/issues/2265>`_ - Resolved import/Export issue for a table
| `Bug #2274 <https://redmine.postgresql.org/issues/2274>`_ - Properly handle truncated table names
| `Bug #2277 <https://redmine.postgresql.org/issues/2277>`_ - Resolved various file-system encoding/decoding related cases
| `Bug #2281 <https://redmine.postgresql.org/issues/2281>`_ - Ensure menus are updated after disconnecting a server
| `Bug #2283 <https://redmine.postgresql.org/issues/2283>`_ - Check if cell is in multiselect mode before setting default selection of multiple values
| `Bug #2287 <https://redmine.postgresql.org/issues/2287>`_ - Properly handle EXPLAIN queries entered directly by the user in the query tool
| `Bug #2291 <https://redmine.postgresql.org/issues/2291>`_ - Fix error highlighting in the query tool
| `Bug #2299 <https://redmine.postgresql.org/issues/2299>`_ - Fix usage of QString
| `Bug #2303 <https://redmine.postgresql.org/issues/2303>`_ - Fix ascending/descending sort order in backgrid while clicking on the headers
| `Bug #2304 <https://redmine.postgresql.org/issues/2304>`_ - Resolve the issue for restoring the table from the backup
| `Bug #2305 <https://redmine.postgresql.org/issues/2305>`_ - Resolve the issue where Generic function qtLiteral was not adapting values properly when they contain non ascii characters
| `Bug #2310 <https://redmine.postgresql.org/issues/2310>`_ - Fix Dialog Help where query tool/Debugger opens in new browser tab
| `Bug #2319 <https://redmine.postgresql.org/issues/2319>`_ - Resolve issue where Click on pgAdmin4 logo leads to unauthorized error
| `Bug #2321 <https://redmine.postgresql.org/issues/2321>`_ - Improved functionality of browser tree when adding new nodes if parent collection node has not loaded
| `Bug #2330 <https://redmine.postgresql.org/issues/2330>`_ - Ensure the query tool displays but does not render HTML returned by the server in the results grid
+37
View File
@@ -0,0 +1,37 @@
***********
Version 1.5
***********
Release date: 2017-05-19
This release contains a number of features and fixes reported since the release of pgAdmin4 1.4.
Features
********
| `Feature #2216 <https://redmine.postgresql.org/issues/2216>`_ - Allow column or row selection in the query tool
Bug fixes
*********
| `Bug #2225 <https://redmine.postgresql.org/issues/2225>`_ - Hide menu options for creating objects, if the object type is set to hidden. Includes Jasmine tests
| `Bug #2253 <https://redmine.postgresql.org/issues/2253>`_ - Fix various issues in CSV file download feature
| `Bug #2257 <https://redmine.postgresql.org/issues/2257>`_ - Improve handling of nulls and default values in the data editor
| `Bug #2271 <https://redmine.postgresql.org/issues/2271>`_ - Don't change the trigger icon back to "enabled" when the trigger is updated when it's disabled
| `Bug #2284 <https://redmine.postgresql.org/issues/2284>`_ - Allow creation of tables with pure numeric names
| `Bug #2292 <https://redmine.postgresql.org/issues/2292>`_ - Only reconnect to databases that were previously connected
| `Bug #2314 <https://redmine.postgresql.org/issues/2314>`_ - Fix various issues in CSV file download feature
| `Bug #2315 <https://redmine.postgresql.org/issues/2315>`_ - Fix sorting of sizes on the statistics views by sorting raw values and prettifying on the client side. Includes Jasmine tests for the prettyfying function
| `Bug #2318 <https://redmine.postgresql.org/issues/2318>`_ - Order foreign table columns correctly
| `Bug #2331 <https://redmine.postgresql.org/issues/2331>`_ - Fix binary search algorithm so new treeview nodes are added in the correct position
| `Bug #2336 <https://redmine.postgresql.org/issues/2336>`_ - Update inode info when refreshing treeview nodes.
| `Bug #2339 <https://redmine.postgresql.org/issues/2339>`_ - Ensure the treeview can be scrolled horizontally
| `Bug #2350 <https://redmine.postgresql.org/issues/2350>`_ - Fix handling of default parameters ordering in functions
| `Bug #2354 <https://redmine.postgresql.org/issues/2354>`_ - Fix the Backup module where it was not working if user changes its preference language other than English
| `Bug #2356 <https://redmine.postgresql.org/issues/2356>`_ - Ensure errors thrown when deleting rows in the query tool in edit mode are shown properly
| `Bug #2360 <https://redmine.postgresql.org/issues/2360>`_ - Fix various issues in CSV file download feature
| `Bug #2369 <https://redmine.postgresql.org/issues/2369>`_ - Support loading files with Unicode BOMs
| `Bug #2377 <https://redmine.postgresql.org/issues/2377>`_ - Update psycopg2 version for PostgreSQL 10 compatibility
| `Bug #2379 <https://redmine.postgresql.org/issues/2379>`_ - Make various improvements to the NULL/DEFAULT handling in the data editor
| `Bug #2405 <https://redmine.postgresql.org/issues/2405>`_ - Ensure object names are properly escaped for external process management
| `Bug #2410 <https://redmine.postgresql.org/issues/2410>`_ - Fix PostgreSQL 10.0 compatibility issues
+103
View File
@@ -0,0 +1,103 @@
***********
Version 1.6
***********
Release date: 2017-07-13
This release contains a number of features and fixes reported since the release of pgAdmin4 1.5
Features
********
| `Feature #1344 <https://redmine.postgresql.org/issues/1344>`_ - Allow the Query Tool, Debugger and web browser tabs to be moved to different monitors as desired
| `Feature #1533 <https://redmine.postgresql.org/issues/1533>`_ - Set focus on the first enabled field when a dialogue is opened
| `Feature #1535 <https://redmine.postgresql.org/issues/1535>`_ - Teach dialogues about Escape to cancel, Enter to Save/OK, and F1 for help
| `Feature #1971 <https://redmine.postgresql.org/issues/1971>`_ - Retain column sizing in the query tool results grid when the same query is re-run multiple times in a row
| `Feature #1972 <https://redmine.postgresql.org/issues/1972>`_ - Prompt the user to save dirty queries rather than discard them for a more natural workflow
| `Feature #2137 <https://redmine.postgresql.org/issues/2137>`_ - On-demand loading for the query tool results
| `Feature #2191 <https://redmine.postgresql.org/issues/2191>`_ - Add support for the hostaddr connection parameter. This helps us play nicely with Kerberos/SSPI and friends
| `Feature #2282 <https://redmine.postgresql.org/issues/2282>`_ - Overhaul the query history tab to allow browsing of the history and full query text
| `Feature #2379 <https://redmine.postgresql.org/issues/2379>`_ - Support inserting multiple new rows into a table without clicking Save for each row
| `Feature #2485 <https://redmine.postgresql.org/issues/2485>`_ - Add a shortcut to reset the zoom level in the runtime
| `Feature #2506 <https://redmine.postgresql.org/issues/2506>`_ - Allow the user to close the dashboard panel
| `Feature #2513 <https://redmine.postgresql.org/issues/2513>`_ - Add preferences to enable brace matching and brace closing in the SQL editors
Bug fixes
*********
| `Bug #1126 <https://redmine.postgresql.org/issues/1126>`_ - Various FTS dictionary cleanups
| `Bug #1229 <https://redmine.postgresql.org/issues/1229>`_ - Fix default values and SQL formatting for event triggers
| `Bug #1466 <https://redmine.postgresql.org/issues/1466>`_ - Prevent attempts to debug procedures with variadic arguments
| `Bug #1525 <https://redmine.postgresql.org/issues/1525>`_ - Make $ quoting consistent
| `Bug #1575 <https://redmine.postgresql.org/issues/1575>`_ - Properly display security labels on EPAS 9.2+
| `Bug #1795 <https://redmine.postgresql.org/issues/1795>`_ - Fix validation for external and range types
| `Bug #1813 <https://redmine.postgresql.org/issues/1813>`_ - List packages in PPAS 9.2-9.4 when creating synonyms
| `Bug #1831 <https://redmine.postgresql.org/issues/1831>`_ - Fix server stats display for EPAS 9.2, where inet needs casting to text for concatenation
| `Bug #1851 <https://redmine.postgresql.org/issues/1851>`_ - Reverse engineer SQL for table-returning functions correctly
| `Bug #1860 <https://redmine.postgresql.org/issues/1860>`_ - Ensure default values are honoured when adding/editing columns
| `Bug #1888 <https://redmine.postgresql.org/issues/1888>`_ - Fix various issues with pgAgent job steps and schedules
| `Bug #1889 <https://redmine.postgresql.org/issues/1889>`_ - Fix various issues with pgAgent job steps and schedules
| `Bug #1890 <https://redmine.postgresql.org/issues/1890>`_ - Fix various issues with pgAgent job steps and schedules
| `Bug #1920 <https://redmine.postgresql.org/issues/1920>`_ - Ensure saved passwords are effective immediately, not just following a restart when first saved
| `Bug #1928 <https://redmine.postgresql.org/issues/1928>`_ - Fix the handling of double precision[] type
| `Bug #1934 <https://redmine.postgresql.org/issues/1934>`_ - Fix import/export to work as expected with TSV data
| `Bug #1999 <https://redmine.postgresql.org/issues/1999>`_ - Handle warning correctly when saving query results to an unmounted USB drive
| `Bug #2013 <https://redmine.postgresql.org/issues/2013>`_ - Increase the default size of the Grant Wizard to enable it to properly display privileges at the default size on smaller displays
| `Bug #2014 <https://redmine.postgresql.org/issues/2014>`_ - To fix unexpected behaviour displayed if user stops debugging on package/procedure fire_emp
| `Bug #2043 <https://redmine.postgresql.org/issues/2043>`_ - Properly handle trigger functions with parameters
| `Bug #2078 <https://redmine.postgresql.org/issues/2078>`_ - Refresh the SQL editor view on resize to ensure the contents are re-rendered for the new viewport
| `Bug #2086 <https://redmine.postgresql.org/issues/2086>`_ - Allow editing of the WITH ADMIN option of role membership
| `Bug #2113 <https://redmine.postgresql.org/issues/2113>`_ - Correct the validation logic when modifying indexes/exclusion constraints
| `Bug #2116 <https://redmine.postgresql.org/issues/2116>`_ - Enable dialogue help buttons on Language and Foreign Table dialogues
| `Bug #2142 <https://redmine.postgresql.org/issues/2142>`_ - Fix canceling of Grant Wizard on Windows
| `Bug #2155 <https://redmine.postgresql.org/issues/2155>`_ - Fix removal of sizes from column definitions
| `Bug #2162 <https://redmine.postgresql.org/issues/2162>`_ - Allow non-superusers to debug their own functions and prevent them from setting global breakpoints
| `Bug #2242 <https://redmine.postgresql.org/issues/2242>`_ - Fix an issue in NodeAjaxControl caching with cache-node field and add cache-node field in Trigger & Event trigger node so that whenever the user creates new Trigger Function we get new data from server in NodeAjaxControl
| `Bug #2280 <https://redmine.postgresql.org/issues/2280>`_ - Handle procedure flags (IMMUTABLE STRICT SECURITY DEFINER PARALLEL RESTRICTED) properly in RE-SQL on EPAS
| `Bug #2324 <https://redmine.postgresql.org/issues/2324>`_ - Fix the PostGIS Datatypes in SQL tab, Create / Update dialogues for Table, Column, Foreign Table and Type node
| `Bug #2344 <https://redmine.postgresql.org/issues/2344>`_ - Fix issue with ctrl-c / ctrl-v not working in query tool
| `Bug #2348 <https://redmine.postgresql.org/issues/2348>`_ - Fix issue when resizing columns in Query Too/View Data where all row/colums will select/deselect
| `Bug #2355 <https://redmine.postgresql.org/issues/2355>`_ - Properly refresh the parent node when renaming children
| `Bug #2357 <https://redmine.postgresql.org/issues/2355>`_ - Cache statistics more reliably
| `Bug #2381 <https://redmine.postgresql.org/issues/2381>`_ - Fix the RE-SQL for for views to properly qualify trigger function names
| `Bug #2386 <https://redmine.postgresql.org/issues/2386>`_ - Display and allow toggling of trigger enable/disable status from the trigger dialogue
| `Bug #2398 <https://redmine.postgresql.org/issues/2398>`_ - Bypass the proxy server for local addresses on Windows
| `Bug #2400 <https://redmine.postgresql.org/issues/2400>`_ - Cleanup handling of default/null values when data editing
| `Bug #2414 <https://redmine.postgresql.org/issues/2414>`_ - Improve error handling in cases where the user tries to rename or create a server group that would duplicate an existing group
| `Bug #2417 <https://redmine.postgresql.org/issues/2417>`_ - Order columns in multi-column pkeys correctly
| `Bug #2422 <https://redmine.postgresql.org/issues/2422>`_ - Fix RE-SQL for rules which got the table name wrong in the header and DROP statement
| `Bug #2425 <https://redmine.postgresql.org/issues/2425>`_ - Handle composite primary keys correctly when deleting rows in the Edit Grid
| `Bug #2426 <https://redmine.postgresql.org/issues/2426>`_ - Allow creation of ENUM types with no members
| `Bug #2427 <https://redmine.postgresql.org/issues/2427>`_ - Add numerous missing checks to ensure objects really exist when we think they do
| `Bug #2435 <https://redmine.postgresql.org/issues/2435>`_ - Pass the database ID to the query tool when using the Script options
| `Bug #2436 <https://redmine.postgresql.org/issues/2436>`_ - Ensure the last placeholder is included when generating UPDATE scripts for tables
| `Bug #2448 <https://redmine.postgresql.org/issues/2448>`_ - Ensure that boolean checkboxes cycle values in the correct order
| `Bug #2450 <https://redmine.postgresql.org/issues/2450>`_ - Fix error on the stats tab with PG10. Also, rename the 10.0_plus template directory to 10_plus to match the new versioning
| `Bug #2461 <https://redmine.postgresql.org/issues/2461>`_ - Allow users to remove default values from columns properly
| `Bug #2468 <https://redmine.postgresql.org/issues/2468>`_ - Fix issue where function create script won't compile
| `Bug #2470 <https://redmine.postgresql.org/issues/2470>`_ - Fix an intermittent error seen during result polling
| `Bug #2476 <https://redmine.postgresql.org/issues/2476>`_ - Improvements to the Query Results grid including improvements to the UI and allow copy/paste from sets of rows, columns or arbitrary blocks of cells
| `Bug #2477 <https://redmine.postgresql.org/issues/2477>`_ - Ensure text editors render in an appropriate place on the results grid
| `Bug #2479 <https://redmine.postgresql.org/issues/2479>`_ - No need for the menu icon to link to the homepage, as pgAdmin is a SPA
| `Bug #2482 <https://redmine.postgresql.org/issues/2482>`_ - Use a more sensible name for Query Tool tabs
| `Bug #2486 <https://redmine.postgresql.org/issues/2486>`_ - Ensure the feature tests use the correct test settings database
| `Bug #2487 <https://redmine.postgresql.org/issues/2487>`_ - Maintain a client-side cache of preference values, populated using an async call
| `Bug #2489 <https://redmine.postgresql.org/issues/2489>`_ - Fix clipboard handling with large datasets
| `Bug #2492 <https://redmine.postgresql.org/issues/2492>`_ - Ensure the initial password is properly hashed during setup in web mode
| `Bug #2498 <https://redmine.postgresql.org/issues/2498>`_ - Properly handle bytea[], and 'infinity'::real/real[]
| `Bug #2502 <https://redmine.postgresql.org/issues/2502>`_ - Properly handle bytea[], and 'infinity'::real/real[]
| `Bug #2503 <https://redmine.postgresql.org/issues/2503>`_ - Handle missing/dropped synonyms gracefully
| `Bug #2504 <https://redmine.postgresql.org/issues/2504>`_ - Update MatView and pgAgent modules to work with recent integer/numeric changes
| `Bug #2507 <https://redmine.postgresql.org/issues/2507>`_ - Ensure revoked public privileges are displayed in the RE-SQL for functions
| `Bug #2518 <https://redmine.postgresql.org/issues/2518>`_ - Fix encoding issue when saving servers
| `Bug #2522 <https://redmine.postgresql.org/issues/2522>`_ - Improve speed of Select All in the results grid
| `Bug #2527 <https://redmine.postgresql.org/issues/2527>`_ - Fix deletion of table rows with the column definition having NOT NULL TRUE and HAS NO DEFAULT VALUE
| `Bug #2528 <https://redmine.postgresql.org/issues/2528>`_ - Allow breakpoints to be set on triggers on views
| `Bug #2529 <https://redmine.postgresql.org/issues/2529>`_ - Resolve a number of issues with domains and domain constraints
| `Bug #2532 <https://redmine.postgresql.org/issues/2532>`_ - Refresh nodes correctly when there is a single child that is updated
| `Bug #2534 <https://redmine.postgresql.org/issues/2534>`_ - Fix handling of CREATE TABLE OF <type>
| `Bug #2535 <https://redmine.postgresql.org/issues/2535>`_ - Fix clear history functionality
| `Bug #2540 <https://redmine.postgresql.org/issues/2540>`_ - Ensure the save password option is enabled when creating a server
+90
View File
@@ -0,0 +1,90 @@
***********
Version 2.0
***********
Release date: 2017-09-xx
This release contains a number of features and fixes reported since the release of pgAdmin4 1.6
Features
********
| `Feature #1918 <https://redmine.postgresql.org/issues/1918>`_ - Add a field to the Server Dialogue allowing users to specify a subset of databases they'd like to see in the treeview
| `Feature #2135 <https://redmine.postgresql.org/issues/2135>`_ - Significantly speed up loading of the application
| `Feature #2556 <https://redmine.postgresql.org/issues/2556>`_ - Allow for slow vs. fast connection failures
| `Feature #2579 <https://redmine.postgresql.org/issues/2579>`_ - Default the file browser view to list, and make it configurable
| `Feature #2597 <https://redmine.postgresql.org/issues/2597>`_ - Allow queries to be cancelled from the dashboard and display additional info in the subnode control
| `Feature #2649 <https://redmine.postgresql.org/issues/2649>`_ - Support use of SSL certificates for authentication
| `Feature #2650 <https://redmine.postgresql.org/issues/2650>`_ - Support use of pgpass files
| `Feature #2662 <https://redmine.postgresql.org/issues/2662>`_ - Ship with pre-configured paths that can work in both Server and Desktop modes out of the box
| `Feature #2689 <https://redmine.postgresql.org/issues/2689>`_ - Update icons with new designs and remove from menus to de-clutter the UI
Bug fixes
*********
| `Bug #1165 <https://redmine.postgresql.org/issues/1165>`_ - Prevent continual polling for graph data on the dashboard if the server is disconnected
| `Bug #1697 <https://redmine.postgresql.org/issues/1697>`_ - Update CodeMirror version
| `Bug #2043 <https://redmine.postgresql.org/issues/2043>`_ - Properly handle trigger functions with parameters
| `Bug #2074 <https://redmine.postgresql.org/issues/2074>`_ - Make $ quoting consistent
| `Bug #2080 <https://redmine.postgresql.org/issues/2080>`_ - Fix issue where Browser hangs/crashes when loading data (using sql editor) from table which contains large blob data
| `Bug #2153 <https://redmine.postgresql.org/issues/2153>`_ - Fix handline of large file uploads and properly show any errors that may occur
| `Bug #2168 <https://redmine.postgresql.org/issues/2168>`_ - Update CodeMirror version
| `Bug #2170 <https://redmine.postgresql.org/issues/2170>`_ - Support SSL in the regression tests
| `Bug #2324 <https://redmine.postgresql.org/issues/2324>`_ - Fix PostGIS Datatypes in SQL tab, Create / Update dialogues for Table, Column, Foreign Table and Type node
| `Bug #2447 <https://redmine.postgresql.org/issues/2447>`_ - Update CodeMirror version
| `Bug #2452 <https://redmine.postgresql.org/issues/2452>`_ - Install pgadmin4-v1 1.5 on Centos7
| `Bug #2501 <https://redmine.postgresql.org/issues/2501>`_ - Fix collation tests on Windows, replace use of default 'POSIX' collation with 'C' collation for testing
| `Bug #2541 <https://redmine.postgresql.org/issues/2541>`_ - Fix issues using special keys on MacOS
| `Bug #2544 <https://redmine.postgresql.org/issues/2544>`_ - Correct malformed query generated when using custom type
| `Bug #2551 <https://redmine.postgresql.org/issues/2551>`_ - Show tablespace on partitions
| `Bug #2555 <https://redmine.postgresql.org/issues/2555>`_ - Fix issue in query tool where messages were not displaying from functions/procedures properly
| `Bug #2557 <https://redmine.postgresql.org/issues/2557>`_ - Tidy up tab styling
| `Bug #2558 <https://redmine.postgresql.org/issues/2558>`_ - Prevent the tab bar being hidden when detached tabs are being closed
| `Bug #2559 <https://redmine.postgresql.org/issues/2559>`_ - Stop tool buttons from changing their styling unexpectedly
| `Bug #2560 <https://redmine.postgresql.org/issues/2560>`_ - Fix View 'CREATE Script' Problem
| `Bug #2562 <https://redmine.postgresql.org/issues/2562>`_ - Update CodeMirror version
| `Bug #2563 <https://redmine.postgresql.org/issues/2563>`_ - Fix paths under non-standard virtual directories
| `Bug #2566 <https://redmine.postgresql.org/issues/2566>`_ - Fix Pause/Resume Replay of WAL files for PostgreSQL 10
| `Bug #2567 <https://redmine.postgresql.org/issues/2567>`_ - Use the proper database connection to fetch the default priviledges in the properties tab of the database
| `Bug #2582 <https://redmine.postgresql.org/issues/2582>`_ - Unset compression ratio if it is an empty string in Backup module
| `Bug #2586 <https://redmine.postgresql.org/issues/2586>`_ - Cleanup feature tests
| `Bug #2590 <https://redmine.postgresql.org/issues/2590>`_ - Allow navigation of query history using the arrow keys
| `Bug #2592 <https://redmine.postgresql.org/issues/2592>`_ - Stop Flask from initialising service twice in Debug mode
| `Bug #2593 <https://redmine.postgresql.org/issues/2593>`_ - Ensure babel-polyfill is loaded in older qWebKits
| `Bug #2594 <https://redmine.postgresql.org/issues/2594>`_ - Fix disconnection of new databases
| `Bug #2596 <https://redmine.postgresql.org/issues/2596>`_ - Define the proper NODE_ENV environment during running the webpack
| `Bug #2606 <https://redmine.postgresql.org/issues/2606>`_ - Ensure role names are escaped in the membership control
| `Bug #2616 <https://redmine.postgresql.org/issues/2616>`_ - Domain create dialog do not open and Font size issue in Security label control
| `Bug #2617 <https://redmine.postgresql.org/issues/2617>`_ - Add missing pgagent file in webpack.config.js
| `Bug #2619 <https://redmine.postgresql.org/issues/2619>`_ - Fix quoting of index column names on tables
| `Bug #2620 <https://redmine.postgresql.org/issues/2620>`_ - Set database name to blank('') when job type is set to batch, while creating pgAgent job
| `Bug #2631 <https://redmine.postgresql.org/issues/2631>`_ - Change mapping of cell from 'numeric' to 'integer' for integer control as numeric cell has been removed from the code
| `Bug #2633 <https://redmine.postgresql.org/issues/2633>`_ - Fix pgAgent job step issues
| `Bug #2634 <https://redmine.postgresql.org/issues/2634>`_ - Add New Server through Quick links
| `Bug #2637 <https://redmine.postgresql.org/issues/2637>`_ - Fix Copy so it still works after query results have been copied
| `Bug #2641 <https://redmine.postgresql.org/issues/2641>`_ - User management issues - styling and inability to edit users properly
| `Bug #2644 <https://redmine.postgresql.org/issues/2644>`_ - Fix alertify notification messages where checkmark box disconnected from frame
| `Bug #2646 <https://redmine.postgresql.org/issues/2646>`_ - Fix the path reference of load-node.gif which was referencing to vendor directory
| `Bug #2654 <https://redmine.postgresql.org/issues/2654>`_ - Update datetime picker
| `Bug #2655 <https://redmine.postgresql.org/issues/2655>`_ - Fix connection string validation for pgAgent jobs
| `Bug #2656 <https://redmine.postgresql.org/issues/2656>`_ - Change Datetimepicker to expand from bottom in pgAgent so calendar does not get hidden
| `Bug #2657 <https://redmine.postgresql.org/issues/2657>`_ - Fix syntax error while saving changes for start/end time, weekdays, monthdays, month, hours, minutes while updating the pgAgent Job
| `Bug #2659 <https://redmine.postgresql.org/issues/2659>`_ - Fix issue where unable to add/update variables for columns of a table
| `Bug #2660 <https://redmine.postgresql.org/issues/2660>`_ - Not able to select rows in History Tab
| `Bug #2668 <https://redmine.postgresql.org/issues/2668>`_ - Fix RE-SQL for triggers with a single arg
| `Bug #2670 <https://redmine.postgresql.org/issues/2670>`_ - Improve datamodel validations for default Validator if user (developer) does not implement validate function in datamodel
| `Bug #2671 <https://redmine.postgresql.org/issues/2671>`_ - Fix array data type formating for bigint, real, float, double precision
| `Bug #2681 <https://redmine.postgresql.org/issues/2681>`_ - Reset query tool options before running tests
| `Bug #2684 <https://redmine.postgresql.org/issues/2684>`_ - Fix layout of password prompt dialogue
| `Bug #2691 <https://redmine.postgresql.org/issues/2691>`_ - View data option is missing from pgAdmin4 2.0 version
| `Bug #2692 <https://redmine.postgresql.org/issues/2692>`_ - Base type is missing for Domain on pgAdmin4
| `Bug #2693 <https://redmine.postgresql.org/issues/2693>`_ - User list is not available on User mapping pgAdmin4
| `Bug #2698 <https://redmine.postgresql.org/issues/2698>`_ - User can not create function due to missing return type
| `Bug #2699 <https://redmine.postgresql.org/issues/2699>`_ - Filtered Rows issue on pgAdmin4
| `Bug #2700 <https://redmine.postgresql.org/issues/2700>`_ - Cancel button is visible after query executed succesfully
| `Bug #2707 <https://redmine.postgresql.org/issues/2707>`_ - Disable trigger button does not work on pgAdmin4
| `Bug #2708 <https://redmine.postgresql.org/issues/2708>`_ - Tablespace name should displayed instead of %s(new_tablespace)s with Move Objects to another tablespace
| `Bug #2709 <https://redmine.postgresql.org/issues/2709>`_ - Display user relations in schema prefixed by 'pg'
| `Bug #2713 <https://redmine.postgresql.org/issues/2713>`_ - Fix an exception seen sometimes when the server is restarted
| `Bug #2742 <https://redmine.postgresql.org/issues/2742>`_ - Ensure using an alternate role to connect to a database doesn't cause an error when checking recovery state.
Executable → Regular
View File
File mode changed.
+19 -11
View File
@@ -46,7 +46,7 @@ little practical gain.
Configuration
*************
In order to configure pgAdmin to run in server mode, it is first necessary to
In order to configure pgAdmin to run in server mode, it may be necessary to
configure the Python code to run in multi-user mode, and then to configure the
web server to find and execute the code.
@@ -68,19 +68,17 @@ pgAdmin. These are as follows:
Python
------
From pgAdmin 4 v2 onwards, server mode is the default configuration. If running under
the desktop runtime, this is overridden automatically. There should typically be no
need to modify the configuration simply to enable server mode to work, however it may
be desirable to adjust some of the paths used.
In order to configure the Python code, follow these steps:
1. Create a ``config_local.py`` file alongside the existing ``config.py`` file.
2. Edit ``config_local.py`` and add the following setting:
.. code-block:: python
SERVER_MODE = True
3. In most cases, the default file locations are setup for running in desktop mode.
Add settings similar to the following to ``config_local.py`` to use paths suitable
for server mode.
2. Edit ``config_local.py`` and add the following settings. In most cases, the default
file locations should be appropriate:
*NOTE: You must ensure the directories specified are writeable by
the user that the web server processes will be running as, e.g. apache or www-data.*
@@ -122,6 +120,16 @@ application may be configured similarly to the example below:
Allow from all
</Directory>
</VirtualHost>
Now open the file ``C:\Program Files\pgAdmin4\web\pgAdmin4.wsgi`` with your favorite editor and add the code
below which will activate Python virtual environment when Apache server runs.
.. code-block:: python
activate_this = 'C:\Program Files\pgAdmin4\venv\Scripts\activate_this.py'
execfile(activate_this, dict(__file__=activate_this))
**Note:** The changes made in ``pgAdmin4.wsgi`` file will revert when pgAdmin4 is either upgraded or downgraded.
Apache HTTPD Configuration (Linux/Unix)
---------------------------------------
@@ -134,7 +142,7 @@ application may be configured similarly to the example below:
<VirtualHost *>
ServerName pgadmin.example.com
WSGIDaemonProcess pgadmin processes=1 threads=25
WSGIDaemonProcess pgadmin processes=1 threads=25 python-home=/path/to/python/virtualenv
WSGIScriptAlias / /opt/pgAdmin4/web/pgAdmin4.wsgi
<Directory /opt/pgAdmin4/web>
+72 -15
View File
@@ -1,20 +1,23 @@
.. _server_dialog:
*****************
The Server Dialog
The Server Dialog
*****************
Use the *Server* dialog to describe a connection to a server. Note: you must ensure the pg_hba.conf file of the server from which you are connecting allows connections from the host of the client.
Use the *Server* dialog to describe a connection to a server. Note: you must ensure the pg_hba.conf file of the server
from which you are connecting allows connections from the host of the client.
The *Server* dialog organizes the connection of a server through the following dialog tabs: *General*, and *Connection*.
The *Server* dialog organizes the connection of a server through the following dialog tabs: *General*, and *Connection*.
.. image:: images/server_general.png
Use the fields in the *General* tab to identify the server:
* Use the *Name* field to add a descriptive name for the server; the name specified will be displayed in the *pgAdmin* tree control of the client.
* Use the *Name* field to add a descriptive name for the server; the name specified will be displayed in the *pgAdmin*
tree control of the client.
* Use the drop-down list box in the *Server group* field to specify the *pgAdmin* tree control parent node for the server.
* Uncheck the checkbox next to *Connect now?* to instruct pgAdmin not to attempt a connection upon completion of the dialog. The default enables connection.
* Uncheck the checkbox next to *Connect now?* to instruct pgAdmin not to attempt a connection upon completion of the
dialog. The default enables connection.
* Provide a comment about the server in the *Comments* field.
Click the *Connection* tab to continue.
@@ -23,18 +26,72 @@ Click the *Connection* tab to continue.
Use the fields in the *Connection* tab to configure a connection:
* Specify the IP address of the server host, or the fully qualified domain name in the *Host name/address* field. On Unix based systems, the address field may be left blank to use the default PostgreSQL Unix Domain Socket on the local machine, or may be set to an alternate path containing a PostgreSQL socket. If you enter a path, the path must begin with a "/".
* Specify the IP address of the server host, or the fully qualified domain name in the *Host name/address* field. On
Unix based systems, the address field may be left blank to use the default PostgreSQL Unix Domain Socket on the local
machine, or may be set to an alternate path containing a PostgreSQL socket. If you enter a path, the path must begin
with a "/".
* Enter the listener port number of the server host in the *Port* field. The default is *5432*.
* Use the *Maintenance database* field to specify the name of the initial database to which the client will connect. If you will be using pgAgent or adminpack objects, the pgAgent schema and adminpack objects should be installed on that database.
* Use the *User name* field to specify the name of a role that will be used when authenticating with the server.
* Use the *Password* field to provide a password that will be supplied when authenticating with the server.
* Check the box next to *Save password* to instruct pgAdmin to save the password for future use.
* Use the *Role* field to specify the name of a role that has privileges that will be conveyed to the client after authentication with the server. This selection allows you to connect as one role, and then assume the permissions of this specified role after the connection is established. Note that the connecting role must be a member of the role specified.
* Use the drop-down list box in the SSL field to select the type of SSL connection the server should use. For more information about using SSL encryption, see Section 31.18 of the Postgres documentation:
http://www.postgresql.org/docs/9.5/static/libpq-ssl.html
* Use the *Maintenance database* field to specify the name of the initial database to which the client will connect.
If you will be using pgAgent or adminpack objects, the pgAgent schema and adminpack objects should be installed on that
database.
* Use the *User name* field to specify the name of a role that will be used when authenticating with the server.
* Use the *Password* field to provide a password that will be supplied when authenticating with the server.
* Check the box next to *Save password* to instruct pgAdmin to save the password for future use.
* Use the *Role* field to specify the name of a role that has privileges that will be conveyed to the client after
authentication with the server. This selection allows you to connect as one role, and then assume the permissions of
this specified role after the connection is established. Note that the connecting role must be a member of the role
specified.
Click the *SSL* tab to continue.
.. image:: images/server_ssl.png
Use the fields in the *SSL* tab to configure a SSL:
* Use the drop-down list box in the SSL field to select the type of SSL connection the server should use. For more
information about using SSL encryption, see Section 31.18 of the Postgres documentation:
http://www.postgresql.org/docs/9.5/static/libpq-ssl.html
* Specify the file containing the name of the client SSL certificate, replacing the default *~/.postgresql/postgresql.crt*
in case of Desktop mode and *<STORAGE_DIR>/<USERNAME>/.postgresql/postgresql.crt* in case of Web mode. This parameter
is ignored if an SSL connection is not made.
* Specify the file containing the secret key used for the client certificate, replacing the default *~/.postgresql/postgresql.key*
in case of Desktop mode and *<STORAGE_DIR>/<USERNAME>/.postgresql/postgresql.key* in case of Web mode. This parameter
is ignored if an SSL connection is not made.
* Specify the file containing the SSL certificate authority, replacing the default *~/.postgresql/root.crt*. This
parameter is ignored if an SSL connection is not made.
* Specify the file containing the SSL certificate revocation list, replacing the default *~/.postgresql/root.crl*. This
parameter is ignored if an SSL connection is not made.
* If set to True, data sent over SSL connections will be compressed else compression will be disabled, The default
is *False*. This parameter is ignored if an SSL connection is not made, see Section 32.1.2 of the Postgres documentation
for more details:
In Server mode, files can be uploaded to the server using the File chooser dialog.
https://www.postgresql.org/docs/9.6/static/libpq-connect.html
*WARNING:* In Server mode, certificates, private keys and the revocation list are stored in the per-user file storage
area on the server, which is owned by the user account under which the pgAdmin server process is run. This means that
administrators of the server may be able to access those files, so appropriate caution should be taken before choosing
to use this feature.
Click the *Advanced* tab to continue.
.. image:: images/server_advanced.png
Use the fields in the *Advanced* tab to configure a connection:
* Specify the IP address of the server host. Using this field to specify the host IP address will avoid a DNS lookup on
connection, however it may be useful to specify both a host name and address when using Kerberos, GSSAPI, or SSPI
authentication methods, as well as for verify-full SSL certificate verification
* The DB restriction field allows you to enter an SQL restriction that will be used against the pg_database table to
limit the databases that you see. For example, you might enter: *live_db test_db* so that only live_db and test_db are
shown in the pgAdmin browser. Separate entries with a comma or tab as you type.
* Specify the password file which allow user to login without providing password, see Section 31 of the Postgres documentation:
https://www.postgresql.org/docs/9.6/static/libpq-pgpass.html
* Click the *Save* button to save work.
* Click the *Cancel* button to exit without saving work.
* Click the *Reset* button to restore configuration parameters.
+11
View File
@@ -28,6 +28,17 @@ might run::
to create a patch between your development branch and the public master branch.
You can also create patches directly from the development tree, for example::
$ git diff > my_cool_feature.diff
If you are adding new files, you may need to stage them for commit, and then
create your patch against the staging area. If any of the files are binary,
for example, images, you will need to use the *--binary* option::
$ git add file1.py file2.py images/image1.png [...]
$ git diff --cached --binary > my_cool_feature.diff
Once you have your patch, check it thoroughly to ensure it meets the pgAdmin
:doc:`coding_standards`, and review it against the :doc:`code_review` to minimise
the chances of it being rejected. Once you're happy with your work, mail it
+29 -78
View File
@@ -2,37 +2,38 @@
Translations
************
pgAdmin supports multiple languages using the `Flask-Babel
<https://pythonhosted.org/Flask-Babel/>`_ Python module. A list of supported
languages is included in the **web/config.py** configuration file and must be
updated whenever langauges are added or removed.
pgAdmin supports multiple languages using the `Flask-Babel
<https://pythonhosted.org/Flask-Babel/>`_ Python module. A list of supported
languages is included in the **web/config.py** configuration file and must be
updated whenever languages are added or removed with
`ISO 639-1 <https://en.wikipedia.org/wiki/ISO_639-1>`_ (two letter) language
codes. The codes are named **$LANG** in this document.
Translation Marking
===================
Strings can be marked for translation in either Python code (using **gettext()**)
or Jinja templates (using **_()**). Here are some examples that show how this
or Jinja templates (using **_()**). Here are some examples that show how this
is achieved.
Python::
errormsg = gettext('No server group name was specified')
Jinja:
.. code-block:: html
<input type="submit" value="{{ _('Change Password') }}">
.. code-block:: html
<title>{{ _('%(appname)s Password Change', appname=config.APP_NAME) }}</title>
.. code-block:: javascript
define(['sources/gettext', ...], function(gettext, ...){
...
var alert = alertify.prompt(
gettext('Password Change'),
gettext('New password for %(userName)s', {userName: 'jsmith' }),
@@ -40,83 +41,34 @@ Jinja:
)
})
Updating and Merging
====================
Whenever new strings are added to the application, the template catalogues
(**web/pgadmin/messages.pot**) must be updated and the existing catalogues
merged with the updated template and compiled. This can be achieved using the
following command from the **web** directory, in the Python virtual environment
used for pgAdmin:
Whenever new strings are added to the application, the template catalogue
(**web/pgadmin/messages.pot**) and the existing translation
catalogues (**web/pgadmin/translations/$LANG/LC_MESSAGES/messages.po**) must be updated
and compiled. This can be achieved using the following commands from the
**web** directory in the Python virtual environment for pgAdmin:
.. code-block:: bash
(pgadmin4)piranha:web dpage$ pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin
For example:
(pgadmin4) user$ pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin
Once the template has been updated it needs to be merged into the existing
message catalogues:
.. code-block:: bash
(pgadmin4)piranha:web dpage$ pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin
extracting messages from pgadmin/__init__.py
extracting messages from pgadmin/about/__init__.py
extracting messages from pgadmin/about/hooks.py
extracting messages from pgadmin/about/views.py
extracting messages from pgadmin/about/templates/about/index.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/browser/__init__.py
extracting messages from pgadmin/browser/hooks.py
extracting messages from pgadmin/browser/views.py
extracting messages from pgadmin/browser/nodes/CollectionNode.py
extracting messages from pgadmin/browser/nodes/ObjectNode.py
extracting messages from pgadmin/browser/nodes/__init__.py
extracting messages from pgadmin/browser/nodes/server_groups/__init__.py
extracting messages from pgadmin/browser/nodes/server_groups/hooks.py
extracting messages from pgadmin/browser/nodes/server_groups/views.py
extracting messages from pgadmin/browser/templates/browser/body.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/browser/templates/browser/index.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/browser/templates/browser/messages.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/help/__init__.py
extracting messages from pgadmin/help/hooks.py
extracting messages from pgadmin/help/views.py
extracting messages from pgadmin/redirects/__init__.py
extracting messages from pgadmin/redirects/views.py
extracting messages from pgadmin/settings/__init__.py
extracting messages from pgadmin/settings/hooks.py
extracting messages from pgadmin/settings/settings_model.py
extracting messages from pgadmin/settings/views.py
extracting messages from pgadmin/templates/base.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/change_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/fields.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/forgot_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/login_user.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/messages.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/panel.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/reset_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/templates/security/watermark.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_")
extracting messages from pgadmin/test/__init__.py
extracting messages from pgadmin/test/hooks.py
extracting messages from pgadmin/test/views.py
extracting messages from pgadmin/utils/__init__.py
extracting messages from pgadmin/utils/views.py
writing PO template file to pgadmin/messages.pot
Once the template has been updated, it needs to be merged into the existing
message catalogues, for example:
.. code-block:: bash
(pgadmin4)piranha:web dpage$ pybabel update -i pgadmin/messages.pot -d pgadmin/translations
updating catalog 'pgadmin/translations/fr/LC_MESSAGES/messages.po' based on 'pgadmin/messages.pot'
(pgadmin4) user$ pybabel update -i pgadmin/messages.pot -d pgadmin/translations
Finally, the message catalogues can be compiled for use:
.. code-block:: bash
(pgadmin4)piranha:web dpage$ pybabel compile -d pgadmin/translations
compiling catalog 'pgadmin/translations/fr/LC_MESSAGES/messages.po' to 'pgadmin/translations/fr/LC_MESSAGES/messages.mo'
(pgadmin4) user$ pybabel compile -d pgadmin/translations
Adding a new Language
Adding a New Language
=====================
Adding a new language is simple. First, add the language name and identifier to
@@ -125,15 +77,14 @@ Adding a new language is simple. First, add the language name and identifier to
# Languages we support in the UI
LANGUAGES = {
'en': 'English',
'fr': 'Français'
'zh': 'Chinese (Simplified)',
'de': 'German',
'pl': 'Polish'
}
Then, create the new message catalogue from the **web** directory in the source
tree, in the Python virtual environment used for pgAdmin:
Then, create the new message catalogue from the **web** directory in the source
tree in the Python virtual environment for pgAdmin:
.. code-block:: bash
(pgadmin4)piranha:web dpage$ pybabel init -i pgadmin/messages.pot -d pgadmin/translations -l fr
This will initialise a new catalogue for a French translation.
(pgadmin4) user$ pybabel init -i pgadmin/messages.pot -d pgadmin/translations -l $LANG
+35 -33
View File
@@ -1,36 +1,38 @@
This is a list of the third party libraries/code used in the application, not
including Python modules installed via Pip which are listed in requirements.txt.
Library Version Licence URL
======= ======= ======= ===
QT 4.6.2+ LGPL v2.1/3 http://www.qt.io/
Bootstrap 3.3.4 MIT http://getbootstrap.com/
jQuery 1.11.1 MIT http://jquery.com/
Modernizr 2.6.2 MIT/BSD http://modernizr.com/
AlertifyJS 1.7.1 MIT http://alertifyjs.com/ *** Do not update - changed to GPL3 in 1.8.0 ***
CodeMirror 5.14.2 MIT http://codemirror.net/
aciTree 4.5.0-rc.7 MIT/GPL http://acoderinsights.ro/en/aciTree-tree-view-with-jQuery
contextMenu 2.1.0 MIT https://github.com/swisnl/jQuery-contextMenu
wcDocker 0f5690318c MIT/GPL https://github.com/WebCabin/wcDocker
Require.js 2.1.18 BSD/MIT http://requirejs.org/
Underscore.js 1.8.3 MIT http://underscorejs.org/
Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/
Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform
Backbone 1.1.2 MIT http://backbonejs.org
font-Awesome 4.5 SIL OFL http://fortawesome.github.io/Font-Awesome/
font-mfizz 2.3 MIT http://fizzed.com/oss/font-mfizz
backgrid.js 0.3.5 MIT http://backgridjs.com/
backbone.undo 0.2 MIT http://backbone.undojs.com/
bootstrap-switch 3.3.2 MIT http://www.bootstrap-switch.org/
select2 4.0.1 MIT https://select2.github.io/
backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid-filter
backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator
backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator
backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all
dropzone 4e20bd4 MIT https://github.com/enyo/dropzone
Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
SlickGrid 2.2.4 MIT https://github.com/6pac/SlickGrid
jQuery-UI 1.11.3 MIT https://jqueryui.com/
BigNumber 3.0.1 MIT http://mikemcl.github.io/bignumber.js
Library Version Licence URL
======= ======= ======= ===
QT 4.6.2+ LGPL v2.1/3 http://www.qt.io/
Bootstrap 3.3.4 MIT http://getbootstrap.com/
jQuery 1.11.1 MIT http://jquery.com/
Modernizr 2.6.2 MIT/BSD http://modernizr.com/
AlertifyJS 1.7.1 MIT http://alertifyjs.com/ *** Do not update - changed to GPL3 in 1.8.0 ***
CodeMirror 5.14.2 MIT http://codemirror.net/
aciTree 4.5.0-rc.7 MIT/GPL http://acoderinsights.ro/en/aciTree-tree-view-with-jQuery
contextMenu 2.1.0 MIT https://github.com/swisnl/jQuery-contextMenu
wcDocker 0f5690318c MIT/GPL https://github.com/WebCabin/wcDocker
Require.js 2.1.18 BSD/MIT http://requirejs.org/
Underscore.js 1.8.3 MIT http://underscorejs.org/
Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/
Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform
Backbone 1.1.2 MIT http://backbonejs.org
font-Awesome 4.5 SIL OFL http://fortawesome.github.io/Font-Awesome/
font-mfizz 2.4.1 MIT http://fizzed.com/oss/font-mfizz
backgrid.js 0.3.5 MIT http://backgridjs.com/
backbone.undo 0.2 MIT http://backbone.undojs.com/
bootstrap-switch 3.3.2 MIT http://www.bootstrap-switch.org/
select2 4.0.1 MIT https://select2.github.io/
backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid-filter
backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator
backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator
backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all
dropzone 4e20bd4 MIT https://github.com/enyo/dropzone
Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
SlickGrid 2.3.7-8ff6814 MIT https://github.com/6pac/SlickGrid
jQuery-UI 1.11.3 MIT https://jqueryui.com/
BigNumber 3.0.1 MIT http://mikemcl.github.io/bignumber.js
Source Code Pro 1.1 SIL OFL https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700
Open Sans 2.0 AL https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600,700
+48
View File
@@ -0,0 +1,48 @@
########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
#########################################################################
# Get the basics out of the way
FROM centos:latest
LABEL name="pgAdmin 4" \
vendor="The pgAdmin Development Team" \
license="PostgreSQL"
# We only need the web/ directory, and a few other things
COPY web /var/www/pgadmin
COPY requirements.txt /var/www/pgadmin
# Install everything we need. Use easy_install to get pip, to avoid setting up EPEL
RUN yum install -y python-setuptools python-devel httpd mod_wsgi gcc
RUN easy_install pip
# Now install the Python runtime dependencies
RUN pip install -r /var/www/pgadmin/requirements.txt
# Create required directories for running
RUN mkdir -p /var/log/pgadmin
RUN chown -R apache /var/log/pgadmin
RUN mkdir -p /var/lib/pgadmin
RUN chown -R apache /var/lib/pgadmin
# Apache config time
COPY pgadmin4.conf /etc/httpd/conf.d/
COPY entry.sh /
# Finally, remove packages we only needed for building
RUN yum -y remove gcc cpp glibc-devel glibc-headers kernel-headers libgomp libmpc mpfr
# Default config options
ENV PGADMIN_DEFAULT_EMAIL container@pgadmin.org
ENV PGADMIN_DEFAULT_PASSWORD Conta1ner
EXPOSE 80 443
# Start the service
ENTRYPOINT ["/bin/bash", "/entry.sh"]
+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
#########################################################################
# Runtime checks
if [ ! -d runtime -a ! -d web ]; then
echo This script must be run from the top-level directory of the source tree.
exit 1
fi
if [ ! -d .git -a ! -f .git/config ]; then
echo This script must be run from a git checkout of the source tree.
exit 1
fi
# Get the required package info
APP_RELEASE=`grep "^APP_RELEASE" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
APP_REVISION=`grep "^APP_REVISION" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
APP_NAME=`grep "^APP_NAME" web/config.py | cut -d"=" -f2 | sed "s/'//g" | sed 's/^ //'`
APP_LONG_VERSION=$APP_RELEASE.$APP_REVISION
APP_SHORT_VERSION=`echo $APP_LONG_VERSION | cut -d . -f1,2`
APP_SUFFIX=`grep "^APP_SUFFIX" web/config.py | cut -d"=" -f2 | sed 's/ //g' | sed "s/'//g"`
if [ ! -z $APP_SUFFIX ]; then
export APP_LONG_VERSION=$APP_LONG_VERSION-$APP_SUFFIX
fi
CONTAINER_NAME=`echo $APP_NAME | sed 's/ //g' | awk '{print tolower($0)}'`
# Output basic details to show we're working
echo Building Docker Container for $APP_NAME version $APP_LONG_VERSION...
# Create/clearout the build directory
echo Creating/cleaning required directories...
if [ -d docker-build ]; then
rm -rf docker-build
fi
mkdir docker-build
# Create the output directory if not present
if [ ! -d dist ]; then
mkdir dist
fi
# Build the clean tree
for FILE in `git ls-files web`
do
echo Adding $FILE
# We use tar here to preserve the path, as Mac (for example) doesn't support cp --parents
tar cf - $FILE | (cd docker-build; tar xf -)
done
pushd web
yarn install
yarn run bundle
for FILE in `ls -d pgAdmin/static/js/generated/*`
do
echo Adding $FILE
tar cf - $FILE | (cd ../docker-build/web; tar xf -)
done
popd
# Build the docs
if [ -d docs/en_US/_build/html ]; then
rm -rf docs/en_US/_build/html
fi
LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 make -C docs/en_US -f Makefile.sphinx html
mkdir docker-build/web/docs
cp -R docs/en_US/_build/html/* docker-build/web/docs/
# Configure pgAdmin
echo "HELP_PATH = '../../docs/'" >> docker-build/web/config_distro.py
echo "DEFAULT_BINARY_PATHS = {" >> docker-build/web/config_distro.py
echo " 'pg': ''," >> docker-build/web/config_distro.py
echo " 'ppas': ''," >> docker-build/web/config_distro.py
echo " 'gpdb': ''" >> docker-build/web/config_distro.py
echo "}" >> docker-build/web/config_distro.py
# Copy the Docker specific assets into place
cp pkg/docker/Dockerfile docker-build/
cp pkg/docker/entry.sh docker-build/
cp pkg/docker/pgadmin4.conf docker-build/
cp requirements.txt docker-build/
# Build the container
docker build docker-build -t $CONTAINER_NAME \
-t $CONTAINER_NAME:latest \
-t $CONTAINER_NAME:$APP_RELEASE \
-t $CONTAINER_NAME:$APP_LONG_VERSION
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
#########################################################################
export PGADMIN_SETUP_EMAIL=${PGADMIN_DEFAULT_EMAIL}
export PGADMIN_SETUP_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
/usr/sbin/httpd -D FOREGROUND
+22
View File
@@ -0,0 +1,22 @@
########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
#########################################################################
ServerName pgadmin4
<VirtualHost *>
WSGIDaemonProcess pgadmin processes=1 threads=25
WSGIScriptAlias / /var/www/pgadmin/pgAdmin4.wsgi
<Directory /var/www/pgadmin>
WSGIProcessGroup pgadmin
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
+9 -1
View File
@@ -87,7 +87,7 @@ _create_python_virtualenv() {
cd $BUILDROOT
test -d $VIRTUALENV || virtualenv -p $PYTHON $VIRTUALENV || exit 1
source $VIRTUALENV/bin/activate
$PIP install -r $SOURCEDIR/requirements.txt || { echo PIP install failed. Please resolve the issue and rerun the script; exit 1; }
$PIP install --no-cache-dir --no-binary :all: -r $SOURCEDIR/requirements.txt || { echo PIP install failed. Please resolve the issue and rerun the script; exit 1; }
# Figure out some paths for use when completing the venv
# Use "python" here as we want the venv path
@@ -128,6 +128,9 @@ _create_python_virtualenv() {
if test -d $DIR_PYMODULES_PATH; then
mv $DIR_PYMODULES_PATH $DIR_PYMODULES_PATH/../python
fi
# Fix the backports module which will have no __init__.py file
touch $BUILDROOT/$VIRTUALENV/lib/python/site-packages/backports/__init__.py
}
_build_runtime() {
@@ -175,6 +178,11 @@ _complete_bundle() {
# run complete-bundle to copy the dependent libraries and frameworks and fix the rpaths
./complete-bundle.sh "$BUILDROOT/$APP_BUNDLE_NAME" || { echo complete-bundle.sh failed; exit 1; }
pushd $SOURCEDIR/web
yarn install
yarn run bundle
popd
# copy the web directory to the bundle as it is required by runtime
cp -r $SOURCEDIR/web "$BUILDROOT/$APP_BUNDLE_NAME/Contents/Resources/" || exit 1
cd "$BUILDROOT/$APP_BUNDLE_NAME/Contents/Resources/web"
+9
View File
@@ -57,6 +57,15 @@ do
tar cf - $FILE | (cd ../pip-build/pgadmin4; tar xf -)
done
yarn install
yarn run bundle
for FILE in `ls -d pgAdmin/static/js/generated/*`
do
echo Adding $FILE
tar cf - $FILE | (cd ../pip-build/pgadmin4; tar xf -)
done
cd ../docs
for FILE in `git ls-files`
do
+9 -1
View File
@@ -13,6 +13,14 @@ import imp
from setuptools import setup
from codecs import open
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
"""This script helps to generate PIP packages"""
# Get the requirements list for the current version of Python
@@ -79,7 +87,7 @@ setup(
extras_require={
# ...
":python_version<'2.7'": ["ordereddict"],
":python_version<='2.7'": ["importlib"],
":python_version<='2.7'": ["backports.csv", "importlib"],
},
# Specify data files to be included. For Python 2.6 include them in MANIFEST.in
+11
View File
@@ -69,6 +69,17 @@ do
tar cf - $FILE | (cd src-build/$TARBALL_NAME; tar xf -)
done
pushd web
yarn install
yarn run bundle
for FILE in `ls -d pgAdmin/static/js/generated/*`
do
echo Adding $FILE
tar cf - $FILE | (cd ../src-build/$TARBALL_NAME/web; tar xf -)
done
popd
# Create the tarball
echo Creating tarball...
cd src-build
+5 -1
View File
@@ -13,6 +13,7 @@ Flask-Gravatar==0.4.2
Flask-HTMLmin==1.2
Flask-Login==0.3.2
Flask-Mail==0.9.1
Flask-Migrate==2.0.3
Flask-Principal==0.4.0
Flask-Security==1.7.5
Flask-SQLAlchemy==2.1
@@ -26,7 +27,7 @@ MarkupSafe==0.23
ordereddict; python_version < '2.7'
passlib==1.6.2
pbr==1.9.1
psycopg2==2.6.2
psycopg2>=2.7.1
pycrypto==2.6.1
pyrsistent==0.11.13
python-dateutil==2.5.0
@@ -39,3 +40,6 @@ SQLAlchemy==1.0.14
sqlparse==0.1.19
Werkzeug==0.9.6
WTForms==2.0.2
backports.csv==1.0.4; python_version <= '2.7'
Flask-Paranoid==0.1.0
Flask-Script==2.0.5; python_version < '2.7'
+261 -191
View File
@@ -66,15 +66,26 @@ BrowserWindow::BrowserWindow(QString url)
// Setup the shortcuts
createActions();
m_tabWidget = new TabWindow(this);
m_tabWidget = new DockTabWidget(this);
m_tabWidget->tabBar()->setVisible(false);
m_mainGridLayout = new QGridLayout(m_tabWidget);
m_mainGridLayout->setContentsMargins(0, 0, 0, 0);
m_pgAdminMainTab = new QWidget(m_tabWidget);
m_tabGridLayout = new QGridLayout(m_pgAdminMainTab);
m_tabGridLayout->setContentsMargins(0, 0, 0, 0);
m_mainWebView = new WebViewWindow(m_pgAdminMainTab);
#ifdef PGADMIN4_USE_WEBENGINE
m_mainWebView->setPage(new WebEnginePage());
#else
m_cookieJar = new QNetworkCookieJar();
m_netAccessMan = new QNetworkAccessManager();
m_netAccessMan->setCookieJar(m_cookieJar);
m_mainWebView->setPage(new WebViewPage());
m_mainWebView->page()->setNetworkAccessManager(m_netAccessMan);
m_mainWebView->settings()->setAttribute(QWebSettings::JavascriptEnabled, true);
m_mainWebView->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
#endif
#ifdef PGADMIN4_DEBUG
@@ -107,10 +118,12 @@ BrowserWindow::BrowserWindow(QString url)
#else
// Register the slot when click on the URL link form main menu bar
connect(m_mainWebView, SIGNAL(linkClicked(const QUrl &)),SLOT(urlLinkClicked(const QUrl &)));
// Register the slot when click on the URL link for QWebPage
connect(m_mainWebView->page(), SIGNAL(createTabWindowKit(QWebPage * &)),SLOT(createNewTabWindowKit(QWebPage * &)));
#endif
// Register the slot on tab index change
connect(m_tabWidget,SIGNAL(currentChanged(int )),this,SLOT(tabIndexChanged(int )));
connect(m_tabWidget,SIGNAL(currentChanged(int )), m_tabWidget,SLOT(tabIndexChanged(int )));
// Listen for download file request from the web page
#ifdef PGADMIN4_USE_WEBENGINE
@@ -120,6 +133,7 @@ BrowserWindow::BrowserWindow(QString url)
m_mainWebView->page()->setForwardUnsupportedContent(true);
connect(m_mainWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &)));
connect(m_mainWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
m_mainWebView->page()->setForwardUnsupportedContent(true);
m_mainWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
#endif
@@ -150,6 +164,13 @@ BrowserWindow::BrowserWindow(QString url)
m_mainWebView->setUrl(m_appServerUrl);
}
// Destructor
BrowserWindow::~BrowserWindow()
{
if (m_tabWidget)
delete m_tabWidget;
}
// Save the window geometry on close
void BrowserWindow::closeEvent(QCloseEvent *event)
{
@@ -178,6 +199,8 @@ void BrowserWindow::createActions()
exitShortcut->setContext(Qt::ApplicationShortcut);
connect(exitShortcut, SIGNAL(activated()), this, SLOT(close()));
signalMapper = new QSignalMapper(this);
// About box
aboutShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_A), this);
aboutShortcut->setContext(Qt::ApplicationShortcut);
@@ -186,12 +209,23 @@ void BrowserWindow::createActions()
// Zoom in
zoomInShortcut = new QShortcut(QKeySequence(QKeySequence::ZoomIn), this);
zoomInShortcut->setContext(Qt::ApplicationShortcut);
connect(zoomInShortcut, SIGNAL(activated()), this, SLOT(zoomIn()));
signalMapper->setMapping(zoomInShortcut, 1);
connect(zoomInShortcut, SIGNAL(activated()), signalMapper, SLOT(map()));
// Zoom out
zoomOutShortcut = new QShortcut(QKeySequence(QKeySequence::ZoomOut), this);
zoomOutShortcut->setContext(Qt::ApplicationShortcut);
connect(zoomOutShortcut, SIGNAL(activated()), this, SLOT(zoomOut()));
signalMapper->setMapping(zoomOutShortcut, -1);
connect(zoomOutShortcut, SIGNAL(activated()), signalMapper, SLOT(map()));
// Reset Zoom
zoomResetShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_0), this);
zoomResetShortcut->setContext(Qt::ApplicationShortcut);
signalMapper->setMapping(zoomResetShortcut, 0);
connect(zoomResetShortcut, SIGNAL(activated()), signalMapper, SLOT(map()));
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setZoomLevel(int)));
#ifdef __APPLE__
#ifdef PGADMIN4_USE_WEBENGINE
@@ -764,125 +798,14 @@ void BrowserWindow::unsupportedContent(QNetworkReply * reply)
}
}
// Slot: When the tab index change, hide/show the toolbutton displayed on tab
void BrowserWindow::tabIndexChanged(int index)
{
int tabCount = 1;
for (tabCount = 1; tabCount < m_tabWidget->count(); tabCount++)
{
if (tabCount != index)
m_tabWidget->showHideToolButton(tabCount, 0);
else
m_tabWidget->showHideToolButton(tabCount, 1);
}
}
// Close the tab and remove the memory of the given index tab
void BrowserWindow::closetabs()
{
int loopCount = 0;
int index = 0;
QPushButton *btn = NULL;
int totalTabs = m_tabWidget->count();
// If QTabWidget contains only one tab then hide the TabBar window
if ((totalTabs - 1) < 2)
m_tabWidget->tabBar()->setVisible(false);
else
m_tabWidget->tabBar()->setVisible(true);
QObject *senderPtr = QObject::sender();
if (senderPtr != NULL)
{
btn = dynamic_cast<QPushButton*>(senderPtr);
index = m_tabWidget->getButtonIndex(btn);
}
if (index != 0)
{
QWidget *tab = m_tabWidget->widget(index);
WebViewWindow *webviewPtr = NULL;
loopCount = 0;
// free the allocated memory when the tab is closed
if (tab != NULL)
delete tab;
// Adjust the tab index value if the tab is closed in between
for (loopCount = 1; loopCount < totalTabs; loopCount++)
{
if (index > loopCount)
continue;
QWidget *tab = m_tabWidget->widget(loopCount);
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
webviewPtr->setTabIndex((webviewPtr->getTabIndex() - 1));
}
}
}
}
}
}
// Slot: go back to page and enable/disable toolbutton
void BrowserWindow::goBackPage()
{
WebViewWindow *webviewPtr = NULL;
QWidget *tab = m_tabWidget->widget(m_tabWidget->currentIndex());
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
{
webviewPtr->back();
m_tabWidget->enableDisableToolButton(m_tabWidget->currentIndex());
}
}
}
}
}
// Slot: go forward to page and enable/disable toolbutton
void BrowserWindow::goForwardPage()
{
WebViewWindow *webviewPtr = NULL;
QWidget *tab = m_tabWidget->widget(m_tabWidget->currentIndex());
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
{
webviewPtr->forward();
m_tabWidget->enableDisableToolButton(m_tabWidget->currentIndex());
}
}
}
}
}
// Slot: set the title of tab when the new tab created or existing tab contents changed
void BrowserWindow::tabTitleChanged(const QString &str)
{
WebViewWindow *nextWebViewPtr = NULL;
bool flagTabText = false;
QToolButton *backToolButton = NULL;
QToolButton *forwardToolButton = NULL;
if (!str.isEmpty())
{
QObject *senderPtr = QObject::sender();
@@ -892,19 +815,96 @@ void BrowserWindow::tabTitleChanged(const QString &str)
webViewPtr = dynamic_cast<WebViewWindow*>(senderPtr);
if (webViewPtr != NULL)
{
m_tabWidget->setTabText(webViewPtr->getTabIndex(), str);
m_tabWidget->setTabToolTipText(webViewPtr->getTabIndex(), str);
m_tabWidget->enableDisableToolButton(webViewPtr->getTabIndex());
DockTabWidget *dock_tab_widget = dynamic_cast<DockTabWidget*>(webViewPtr->parent()->parent()->parent());
if (dock_tab_widget != NULL)
{
for (int loopCount = dock_tab_widget->count();loopCount >= 0;loopCount--)
{
QWidget *tab = dock_tab_widget->widget(loopCount);
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
nextWebViewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (nextWebViewPtr != NULL && nextWebViewPtr == webViewPtr)
{
// If tab title is for Query tool then we should hide tool buttons.
QWidget *tab = dock_tab_widget->tabBar()->tabButton(loopCount, QTabBar::LeftSide);
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
QToolButton *toolBtnPtr = dynamic_cast<QToolButton*>(widgetPtr);
if (toolBtnPtr != NULL)
{
if (!QString::compare(toolBtnPtr->toolTip(), tr("Go back"), Qt::CaseInsensitive))
backToolButton = toolBtnPtr;
if (!QString::compare(toolBtnPtr->toolTip(), tr("Go forward"), Qt::CaseInsensitive))
forwardToolButton = toolBtnPtr;
}
}
}
}
if (backToolButton != NULL && forwardToolButton != NULL)
{
if (!str.startsWith("Query -"))
{
if (str.startsWith("Debugger"))
{
backToolButton->hide();
forwardToolButton->hide();
webViewPtr->setBackForwardButtonHidden(true);
}
// If user open any file in query tool then "Query -" name will not appear
// but it is still query tool so hide the tool button.
else if (!webViewPtr->getBackForwardButtonHidden())
{
backToolButton->show();
forwardToolButton->show();
webViewPtr->setBackForwardButtonHidden(false);
}
}
else
{
backToolButton->hide();
forwardToolButton->hide();
webViewPtr->setBackForwardButtonHidden(true);
}
}
dock_tab_widget->setTabText(loopCount, str);
dock_tab_widget->setTabToolTipText(loopCount, str);
dock_tab_widget->enableDisableToolButton(loopCount);
flagTabText = true;
break;
}
}
}
if (flagTabText)
break;
}
if (!flagTabText)
{
dock_tab_widget->setTabText(dock_tab_widget->currentIndex(), str);
dock_tab_widget->setTabToolTipText(dock_tab_widget->currentIndex(), str);
dock_tab_widget->enableDisableToolButton(dock_tab_widget->currentIndex());
}
}
}
}
else
{
m_tabWidget->setTabText(m_tabWidget->currentIndex(), str);
m_tabWidget->setTabToolTipText(m_tabWidget->currentIndex(), str);
}
}
}
void BrowserWindow::current_dir_path(const QString &dir)
{
m_dir = dir;
@@ -914,39 +914,55 @@ void BrowserWindow::current_dir_path(const QString &dir)
settings.setValue("Browser/LastSaveLocation", m_last_open_folder_path);
}
#ifdef PGADMIN4_USE_WEBENGINE
// Below slot will be called when link is required to open in new tab.
void BrowserWindow::createNewTabWindow(QWebEnginePage * &p)
#ifndef PGADMIN4_USE_WEBENGINE
void BrowserWindow::createNewTabWindowKit(QWebPage * &p)
{
m_addNewTab = new QWidget(m_tabWidget);
m_addNewGridLayout = new QGridLayout(m_addNewTab);
m_addNewGridLayout->setContentsMargins(0, 0, 0, 0);
m_addNewWebView = new WebViewWindow(m_addNewTab);
m_addNewWebView->setPage(new WebEnginePage());
m_addNewWebView->setPage(new WebViewPage());
m_addNewWebView->setZoomFactor(m_mainWebView->zoomFactor());
// Register the slot when click on the URL link form main menu bar
connect(m_addNewWebView, SIGNAL(linkClicked(const QUrl &)),SLOT(urlLinkClicked(const QUrl &)));
// Register the slot when click on the URL link for QWebPage
connect(m_addNewWebView->page(), SIGNAL(createTabWindowKit(QWebPage * &)),SLOT(createNewTabWindowKit(QWebPage * &)));
m_addNewWebView->page()->setForwardUnsupportedContent(true);
connect(m_addNewWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &)));
connect(m_addNewWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
m_addNewWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
m_addNewWebView->settings()->setAttribute(QWebSettings::JavascriptEnabled, true);
m_addNewWebView->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
m_widget = new QWidget(m_addNewTab);
m_toolBtnBack = new QToolButton(m_widget);
m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnBack->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnBack->setIcon(QIcon(":/back.png"));
m_toolBtnBack->setToolTip(tr("Go back"));
m_toolBtnBack->setDisabled(true);
m_toolBtnBack->hide();
m_toolBtnForward = new QToolButton(m_widget);
m_toolBtnForward->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnForward->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnForward->setIcon(QIcon(":/forward.png"));
m_toolBtnForward->setToolTip(tr("Go forward"));
m_toolBtnForward->setDisabled(true);
m_toolBtnForward->hide();
QPushButton *m_btnClose = new QPushButton(m_widget);
QToolButton *m_btnClose = new QToolButton(m_widget);
m_btnClose->setFixedHeight(PGA_BTN_SIZE);
m_btnClose->setFixedWidth(PGA_BTN_SIZE);
m_btnClose->setIcon(QIcon(":/close.png"));
m_btnClose->setToolTip(tr("Close tab"));
m_horizontalLayout = new QHBoxLayout(m_widget);
m_horizontalLayout->setContentsMargins(0,1,0,0);
m_horizontalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_horizontalLayout->setSpacing(1);
m_horizontalLayout->addWidget(m_toolBtnBack);
@@ -956,13 +972,13 @@ void BrowserWindow::createNewTabWindow(QWebEnginePage * &p)
connect(m_addNewWebView, SIGNAL(titleChanged(const QString &)), SLOT(tabTitleChanged(const QString &)));
// Register the slot on toolbutton to show the previous history of web
connect(m_toolBtnBack, SIGNAL(clicked()), this, SLOT(goBackPage()));
connect(m_toolBtnBack, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoBackPage()));
// Register the slot on toolbutton to show the next history of web
connect(m_toolBtnForward, SIGNAL(clicked()), this, SLOT(goForwardPage()));
connect(m_toolBtnForward, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoForwardPage()));
// Register the slot on close button , added manually
connect(m_btnClose, SIGNAL(clicked()), SLOT(closetabs()));
connect(m_btnClose, SIGNAL(clicked()), m_tabWidget, SLOT(dockClosetabs()));
m_addNewGridLayout->addWidget(m_addNewWebView, 0, 0, 1, 1);
m_tabWidget->addTab(m_addNewTab, QString());
@@ -973,6 +989,75 @@ void BrowserWindow::createNewTabWindow(QWebEnginePage * &p)
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::LeftSide, m_widget);
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::RightSide, m_btnClose);
m_addNewWebView->setTabIndex((m_tabWidget->count() - 1));
m_addNewWebView->page()->setNetworkAccessManager(m_netAccessMan);
p = m_addNewWebView->page();
}
#endif
#ifdef PGADMIN4_USE_WEBENGINE
// Below slot will be called when link is required to open in new tab.
void BrowserWindow::createNewTabWindow(QWebEnginePage * &p)
{
m_addNewTab = new QWidget(m_tabWidget);
m_addNewGridLayout = new QGridLayout(m_addNewTab);
m_addNewGridLayout->setContentsMargins(0, 0, 0, 0);
m_addNewWebView = new WebViewWindow();
m_addNewWebView->setPage(new WebEnginePage());
m_addNewWebView->setZoomFactor(m_mainWebView->zoomFactor());
m_widget = new QWidget(m_addNewTab);
m_toolBtnBack = new QToolButton(m_widget);
m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnBack->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnBack->setIcon(QIcon(":/back.png"));
m_toolBtnBack->setToolTip(tr("Go back"));
m_toolBtnBack->hide();
m_toolBtnForward = new QToolButton(m_widget);
m_toolBtnForward->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnForward->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnForward->setIcon(QIcon(":/forward.png"));
m_toolBtnForward->setToolTip(tr("Go forward"));
m_toolBtnForward->hide();
m_toolBtnClose = new QToolButton(m_widget);
m_toolBtnClose->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnClose->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnClose->setIcon(QIcon(":/close.png"));
m_toolBtnClose->setToolTip(tr("Close tab"));
m_horizontalLayout = new QHBoxLayout(m_widget);
m_horizontalLayout->setContentsMargins(0,1,0,0);
m_horizontalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_horizontalLayout->setSpacing(1);
m_horizontalLayout->addWidget(m_toolBtnBack);
m_horizontalLayout->addWidget(m_toolBtnForward);
// Register the slot on titleChange so set the tab text accordingly
connect(m_addNewWebView, SIGNAL(titleChanged(const QString &)), SLOT(tabTitleChanged(const QString &)));
// Register the slot on toolbutton to show the previous history of web
connect(m_toolBtnBack, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoBackPage()));
// Register the slot on toolbutton to show the next history of web
connect(m_toolBtnForward, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoForwardPage()));
// Register the slot on close button , added manually
connect(m_toolBtnClose, SIGNAL(clicked()), m_tabWidget, SLOT(dockClosetabs()));
m_addNewGridLayout->addWidget(m_addNewWebView, 0, 0, 1, 1);
m_tabWidget->addTab(m_addNewTab, QString());
m_tabWidget->tabBar()->setVisible(true);
m_tabWidget->setCurrentIndex((m_tabWidget->count() - 1));
// Set the back and forward button on tab
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::LeftSide, m_widget);
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::RightSide, m_toolBtnClose);
m_addNewWebView->setTabIndex((m_tabWidget->count() - 1));
p = m_addNewWebView->page();
}
@@ -990,42 +1075,55 @@ void BrowserWindow::urlLinkClicked(const QUrl &name)
if (!tabFound)
{
m_addNewTab = new QWidget(m_tabWidget);
m_addNewGridLayout = new QGridLayout(m_addNewTab);
m_addNewGridLayout->setContentsMargins(0, 0, 0, 0);
m_addNewWebView = new WebViewWindow(m_addNewTab);
m_addNewWebView = new WebViewWindow();
m_addNewWebView->setZoomFactor(m_mainWebView->zoomFactor());
// Listen for the download request from the web page
#ifdef PGADMIN4_USE_WEBENGINE
m_addNewWebView->setPage(new WebEnginePage());
connect(m_addNewWebView->page()->profile(),SIGNAL(downloadRequested(QWebEngineDownloadItem*)),this,SLOT(downloadRequested(QWebEngineDownloadItem*)));
#else
m_addNewWebView->setPage(new WebViewPage());
m_addNewWebView->page()->setForwardUnsupportedContent(true);
connect(m_addNewWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &)));
connect(m_addNewWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
// Register the slot when click on the URL link form main menu bar
connect(m_addNewWebView, SIGNAL(linkClicked(const QUrl &)),SLOT(urlLinkClicked(const QUrl &)));
// Register the slot when click on the URL link for QWebPage
connect(m_addNewWebView->page(), SIGNAL(createTabWindowKit(QWebPage * &)),SLOT(createNewTabWindowKit(QWebPage * &)));
m_addNewWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
#endif
m_widget = new QWidget(m_addNewTab);
m_toolBtnBack = new QToolButton(m_widget);
m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnBack->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnBack->setIcon(QIcon(":/back.png"));
m_toolBtnBack->setToolTip(tr("Go back"));
m_toolBtnBack->setDisabled(true);
m_toolBtnBack->hide();
m_toolBtnForward = new QToolButton(m_widget);
m_toolBtnForward->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnForward->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnForward->setIcon(QIcon(":/forward.png"));
m_toolBtnForward->setToolTip(tr("Go forward"));
m_toolBtnForward->setDisabled(true);
m_toolBtnForward->hide();
QPushButton *m_btnClose = new QPushButton(m_widget);
m_btnClose->setFixedHeight(PGA_BTN_SIZE);
m_btnClose->setFixedWidth(PGA_BTN_SIZE);
m_btnClose->setIcon(QIcon(":/close.png"));
m_btnClose->setToolTip(tr("Close tab"));
m_toolBtnClose = new QToolButton(m_widget);
m_toolBtnClose->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnClose->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnClose->setIcon(QIcon(":/close.png"));
m_toolBtnClose->setToolTip(tr("Close tab"));
m_horizontalLayout = new QHBoxLayout(m_widget);
m_horizontalLayout->setContentsMargins(0,1,0,0);
m_horizontalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_horizontalLayout->setSpacing(1);
m_horizontalLayout->addWidget(m_toolBtnBack);
@@ -1035,13 +1133,13 @@ void BrowserWindow::urlLinkClicked(const QUrl &name)
connect(m_addNewWebView, SIGNAL(titleChanged(const QString &)), SLOT(tabTitleChanged(const QString &)));
// Register the slot on toolbutton to show the previous history of web
connect(m_toolBtnBack, SIGNAL(clicked()), this, SLOT(goBackPage()));
connect(m_toolBtnBack, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoBackPage()));
// Register the slot on toolbutton to show the next history of web
connect(m_toolBtnForward, SIGNAL(clicked()), this, SLOT(goForwardPage()));
connect(m_toolBtnForward, SIGNAL(clicked()), m_tabWidget, SLOT(dockGoForwardPage()));
// Register the slot on close button , added manually
connect(m_btnClose, SIGNAL(clicked()), SLOT(closetabs()));
connect(m_toolBtnClose, SIGNAL(clicked()), m_tabWidget, SLOT(dockClosetabs()));
m_addNewGridLayout->addWidget(m_addNewWebView, 0, 0, 1, 1);
m_tabWidget->addTab(m_addNewTab, QString());
@@ -1050,7 +1148,7 @@ void BrowserWindow::urlLinkClicked(const QUrl &name)
// Set the back and forward button on tab
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::LeftSide, m_widget);
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::RightSide, m_btnClose);
m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::RightSide, m_toolBtnClose);
m_addNewWebView->setFirstLoadURL(name.host());
m_addNewWebView->setTabIndex((m_tabWidget->count() - 1));
@@ -1074,8 +1172,8 @@ void BrowserWindow::about()
}
// Zoom in
void BrowserWindow::zoomIn()
// Set Zoom Level
void BrowserWindow::setZoomLevel(int zoomFlag)
{
int tabCount = 0;
WebViewWindow *webviewPtr = NULL;
@@ -1097,55 +1195,27 @@ void BrowserWindow::zoomIn()
if (webviewPtr != NULL)
{
webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() + 0.1);
if (zoomFlag == 1) {
webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() + 0.1);
}
else if (zoomFlag == -1) {
webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() - 0.1);
}
else if(zoomFlag == 0) {
webviewPtr->setZoomFactor(1.0);
}
}
}
}
}
}
// Save the zoom factor for next time
// Set the zoom value for the next time
QSettings settings;
settings.setValue("Browser/Zoom", m_mainWebView->zoomFactor());
}
// Zoom out
void BrowserWindow::zoomOut()
{
int tabCount = 0;
WebViewWindow *webviewPtr = NULL;
// Loop through all the tabs
for (tabCount = 0; tabCount < m_tabWidget->count(); tabCount++)
{
QWidget *tab = m_tabWidget->widget(tabCount);
if (tab != NULL)
{
// Find and loop through any child controls
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
// If it's a web view control, set the zoom level based on the main view
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
{
webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() - 0.1);
}
}
}
}
}
// Save the zoom factor for next time
QSettings settings;
settings.setValue("Browser/Zoom", m_mainWebView->zoomFactor());
}
// Open an arbitrary URL
void BrowserWindow::openUrl()
{
+35 -16
View File
@@ -17,19 +17,31 @@
#include "WebViewWindow.h"
#if QT_VERSION >= 0x050000
#include <QtWidgets>
#ifdef PGADMIN4_USE_WEBENGINE
#include <QtWebEngineWidgets>
#include <QtWidgets>
#ifdef PGADMIN4_USE_WEBENGINE
#include <QtWebEngineWidgets>
#else
#include <QtWebKitWidgets>
#include <QNetworkCookieJar>
#include <QNetworkAccessManager>
#endif
#else
#include <QtWebKitWidgets>
#include <QMainWindow>
#ifdef PGADMIN4_USE_WEBENGINE
#include <QtWebEngineView>
#else
#include <QWebView>
#include <QNetworkCookieJar>
#include <QNetworkAccessManager>
#endif
#endif
#else
#include <QMainWindow>
#ifdef PGADMIN4_USE_WEBENGINE
#include <QtWebEngineView>
#include <QWebEngineHistory>
#else
#include <QWebView>
#endif
#include <QWebHistory>
#endif
QT_BEGIN_NAMESPACE
@@ -43,13 +55,13 @@ class BrowserWindow : public QMainWindow
public:
BrowserWindow(QString url);
~BrowserWindow();
protected:
void closeEvent(QCloseEvent *event);
protected slots:
void urlLinkClicked(const QUrl &);
void closetabs();
void tabTitleChanged(const QString &);
#ifdef __APPLE__
#ifdef PGADMIN4_USE_WEBENGINE
@@ -63,16 +75,12 @@ private slots:
void openUrl();
void preferences();
void about();
void zoomIn();
void zoomOut();
void setZoomLevel(int zoomFlag);
#ifdef PGADMIN4_USE_WEBENGINE
void downloadRequested(QWebEngineDownloadItem *download);
#endif
public slots:
void tabIndexChanged(int index);
void goBackPage();
void goForwardPage();
void download(const QNetworkRequest &request);
void unsupportedContent(QNetworkReply * reply);
void downloadFinished();
@@ -83,6 +91,8 @@ public slots:
void createNewTabWindow(QWebEnginePage * &);
void downloadEngineFileProgress(qint64 , qint64 );
void downloadEngineFinished();
#else
void createNewTabWindowKit(QWebPage * &);
#endif
private:
@@ -95,19 +105,23 @@ private:
QShortcut *aboutShortcut;
QShortcut *zoomInShortcut;
QShortcut *zoomOutShortcut;
QShortcut *zoomResetShortcut;
QSignalMapper *signalMapper;
QGridLayout *m_tabGridLayout;
QGridLayout *m_mainGridLayout;
TabWindow *m_tabWidget;
DockTabWidget *m_tabWidget;
QWidget *m_pgAdminMainTab;
QWidget *m_addNewTab;
QGridLayout *m_addNewGridLayout;
WebViewWindow *m_addNewWebView;
QHBoxLayout *m_horizontalLayout;
QWidget *m_widget;
QToolButton *m_toolBtnBack;
QToolButton *m_toolBtnForward;
QToolButton *m_toolBtnClose;
QString m_downloadFilename;
int m_downloadStarted;
@@ -118,13 +132,18 @@ private:
QString m_last_open_folder_path;
QString m_dir;
QNetworkReply *m_reply;
#ifdef PGADMIN4_USE_WEBENGINE
QWebEngineDownloadItem *m_download;
#else
QNetworkCookieJar *m_cookieJar;
QNetworkAccessManager *m_netAccessMan;
#endif
void createActions();
void pause(int seconds = 1);
int findURLTab(const QUrl &name);
void enableDisableToolButtons(WebViewWindow *webViewPtr);
#ifdef __APPLE__
#ifdef PGADMIN4_USE_WEBENGINE
+2 -2
View File
@@ -8,9 +8,9 @@
<key>CFBundleName</key>
<string>pgAdmin 4</string>
<key>CFBundleShortVersionString</key>
<string>1.4.0</string>
<string>2.0.0</string>
<key>CFBundleVersion</key>
<string>1.4.0</string>
<string>2.0.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.9</string>
<key>NSHumanReadableCopyright</key>
+3 -1
View File
@@ -63,6 +63,7 @@ Server::Server(quint16 port, QString key)
// Initialise Python
Py_NoSiteFlag=1;
Py_NoUserSiteDirectory=1;
Py_DontWriteBytecodeFlag=1;
PGA_APP_NAME_UTF8 = PGA_APP_NAME.toUtf8();
@@ -271,9 +272,10 @@ void Server::run()
return;
}
// Set the port number
// Set the port number and key, and force SERVER_MODE off.
PyRun_SimpleString(QString("PGADMIN_PORT = %1").arg(m_port).toLatin1());
PyRun_SimpleString(QString("PGADMIN_KEY = '%1'").arg(m_key).toLatin1());
PyRun_SimpleString(QString("SERVER_MODE = False").toLatin1());
// Run the app!
QByteArray m_appfile_utf8 = m_appfile.toUtf8();
+555 -25
View File
@@ -20,13 +20,23 @@
#include <QWebHistory>
#endif
TabWindow::TabWindow(QWidget *parent) :
DockTabWidget *DockTabWidget::mainTabWidget = NULL;
DockTabWidget::DockTabWidget(QWidget *parent) :
QTabWidget(parent)
{
floatingWidget = NULL;
floatingEnabled = false;
setParent(parent);
setTabsClosable(false);
setElideMode(Qt::ElideRight);
// set custom tab bar in tab widget to receive events for docking.
setTabBar(new DockTabBar(this));
setDocumentMode(true);
setAcceptDrops(true);
// Get the system colours we need
QPalette palette = QApplication::palette("QPushButton");
QColor activebg = palette.color(QPalette::Button);
@@ -45,11 +55,7 @@ TabWindow::TabWindow(QWidget *parent) :
"margin-top: 1px; "
#ifndef __APPLE__
"width: 15em; "
#ifdef _WIN32
"height: 1.5em; "
#else
"height: 1em; "
#endif
#endif
"} "
"QTabBar::tab:selected { "
@@ -64,17 +70,361 @@ TabWindow::TabWindow(QWidget *parent) :
"alignment: left; "
"}"
);
#ifdef __APPLE__
m_testTabBar = new TabBar();
setTabBar(m_testTabBar);
#endif
// Hide the default tab
tabBar()->setVisible(false);
if (mainTabWidget == NULL)
mainTabWidget = this;
}
DockTabWidget::DockTabWidget(DockTabWidget *other, QWidget *parent) :
QTabWidget(parent)
{
setFloatingBaseWidget(other->floatingBaseWidget());
setFloatingEnabled(other->isFloatingEnabled());
resize(other->size());
// set custom tab bar in tab widget to receive events for docking.
setTabBar(new DockTabBar(this));
setDocumentMode(true);
setAcceptDrops(true);
// Get the system colours we need
QPalette palette = QApplication::palette("QPushButton");
QColor activebg = palette.color(QPalette::Button);
QColor activefg = palette.color(QPalette::ButtonText);
QColor inactivebg = palette.color(QPalette::Dark);
QColor inactivefg = palette.color(QPalette::ButtonText);
QColor border = palette.color(QPalette::Mid);
setStyleSheet(
"QTabBar::tab { "
"background-color: " + inactivebg.name() + "; "
"color: " + inactivefg.name() + "; "
"border: 1px solid " + border.name() + "; "
"padding: 1px 0px; "
"margin-left: 0px; "
"margin-top: 1px; "
#ifndef __APPLE__
"width: 15em; "
"height: 1.5em; "
#else
"font: 11pt; "
"width: 19em; "
"height: 1.5em; "
#endif
"} "
"QTabBar::tab:selected { "
"background-color: " + activebg.name() + "; "
"color: " + activefg.name() + "; "
"border-bottom-style: none; "
"} "
"QTabWidget::pane { "
"border: 0; "
"} "
"QTabWidget::tab-bar {"
"alignment: left; "
"}"
);
}
void DockTabWidget::setFloatingBaseWidget(QWidget *widget)
{
floatingWidget = widget;
if (floatingEnabled && parentWidget() == 0)
setParent(widget);
}
void DockTabWidget::setFloatingEnabled(bool x)
{
floatingEnabled = x;
if (parent() == 0)
{
if (x)
setWindowFlags(Qt::Tool);
else
setWindowFlags(Qt::Window);
}
}
// Slot: go back to page and enable/disable toolbutton
void DockTabWidget::dockGoBackPage()
{
WebViewWindow *webviewPtr = NULL;
QWidget *tab = this->widget(this->currentIndex());
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
webviewPtr->back();
}
}
}
}
// Slot: go forward to page and enable/disable toolbutton
void DockTabWidget::dockGoForwardPage()
{
WebViewWindow *webviewPtr = NULL;
QWidget *tab = this->widget(this->currentIndex());
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
webviewPtr->forward();
}
}
}
}
// Close the tab and remove the memory of the given index tab
void DockTabWidget::dockClosetabs()
{
int totalTabs = 0;
QToolButton *btn = NULL;
QWidget *tab = NULL;
DockTabWidget *l_tab_widget = NULL;
QObject *senderPtr = QObject::sender();
if (senderPtr != NULL)
{
btn = dynamic_cast<QToolButton*>(senderPtr);
if (btn != NULL)
{
l_tab_widget = dynamic_cast<DockTabWidget*>(btn->parent()->parent());
int current_tab_index = 0;
if (l_tab_widget != NULL)
{
totalTabs = l_tab_widget->count();
for (int loopCount = l_tab_widget->count();loopCount >= 0;loopCount--)
{
QWidget *l_tab = l_tab_widget->tabBar()->tabButton(loopCount, QTabBar::RightSide);
if (l_tab != NULL)
{
QToolButton *nextBtnPtr = dynamic_cast<QToolButton*>(l_tab);
if (nextBtnPtr != NULL && btn != NULL && nextBtnPtr == btn)
current_tab_index = loopCount;
}
}
QList<QWidget*> widgetList = l_tab_widget->tabBar()->findChildren<QWidget*>();
foreach(QWidget* widgetPtr, widgetList)
{
if (widgetPtr != NULL)
{
QToolButton *toolBtnPtr = dynamic_cast<QToolButton*>(widgetPtr);
if (toolBtnPtr != NULL && toolBtnPtr == btn)
{
tab = l_tab_widget->widget(current_tab_index);
break;
}
}
}
}
if (tab != NULL)
tab->deleteLater();
// If user close the last tab then close the parent tab widget also.
if (totalTabs == 1 && l_tab_widget != NULL)
l_tab_widget->deleteLater();
}
}
if (tab != NULL)
{
WebViewWindow *webviewPtr = NULL;
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach (QWidget* widgetPtr, widgetList)
{
if (widgetPtr != NULL)
{
webviewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webviewPtr != NULL)
{
/* Trigger the action for tab window close so unload event will be called and
* resources will be freed properly.
* Trigger 'RequestClose' action from Qt5 onwards. Here we have triggerred the action
* 'ToggleVideoFullscreen + 1' because we do not know from which webkit
* version 'RequestClose' action was added so increment with previous enum value so that
* it will be backward webkit version compatible.
*/
#if QT_VERSION >= 0x050000
#ifndef PGADMIN4_USE_WEBENGINE
webviewPtr->page()->triggerAction(static_cast<QWebPage::WebAction>(QWebPage::ToggleVideoFullscreen + 1));
#endif
#endif
}
}
}
}
// Check if main pgAdmin4 application has only one tab then close tab bar.
// Here - check for count 2 because tab will be deleted later.
DockTabWidget *mainTab = DockTabWidget::getMainTabWidget();
if (mainTab != NULL && l_tab_widget != NULL && l_tab_widget == mainTab && mainTab->count() == 2)
mainTab->tabBar()->setVisible(false);
}
// This function is used to set back/forward/close buttons on new tabbar.
void DockTabWidget::setButtonsNewTabbar(int index)
{
QWidget *m_widget = new QWidget();
QToolButton *m_toolBtnBack = new QToolButton(m_widget);
m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnBack->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnBack->setIcon(QIcon(":/back.png"));
m_toolBtnBack->setToolTip(tr("Go back"));
QToolButton *m_toolBtnForward = new QToolButton(m_widget);
m_toolBtnForward->setFixedHeight(PGA_BTN_SIZE);
m_toolBtnForward->setFixedWidth(PGA_BTN_SIZE);
m_toolBtnForward->setIcon(QIcon(":/forward.png"));
m_toolBtnForward->setToolTip(tr("Go forward"));
QToolButton *m_btnClose = new QToolButton(m_widget);
m_btnClose->setFixedHeight(PGA_BTN_SIZE);
m_btnClose->setFixedWidth(PGA_BTN_SIZE);
m_btnClose->setIcon(QIcon(":/close.png"));
m_btnClose->setToolTip(tr("Close tab"));
QHBoxLayout *m_horizontalLayout = new QHBoxLayout(m_widget);
m_horizontalLayout->setContentsMargins(0,1,0,0);
m_horizontalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_horizontalLayout->setSpacing(1);
m_horizontalLayout->addWidget(m_toolBtnBack);
m_horizontalLayout->addWidget(m_toolBtnForward);
// Register the slot on toolbutton to show the previous history of web
connect(m_toolBtnBack, SIGNAL(clicked()), this, SLOT(dockGoBackPage()));
// Register the slot on toolbutton to show the next history of web
connect(m_toolBtnForward, SIGNAL(clicked()), this, SLOT(dockGoForwardPage()));
// Register the slot on close button , added manually
connect(m_btnClose, SIGNAL(clicked()), SLOT(dockClosetabs()));
// Register the slot on tab index change
connect(this, SIGNAL(currentChanged(int )), this,SLOT(tabIndexChanged(int )));
// Set the back and forward button on tab
this->tabBar()->setTabButton(index, QTabBar::LeftSide, m_widget);
this->tabBar()->setTabButton(index, QTabBar::RightSide, m_btnClose);
// find the webview and hide/show button depending on flag set with web view.
QWidget *tab = this->widget(index);
if (tab != NULL)
{
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
WebViewWindow *webViewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webViewPtr != NULL)
{
// If user open any file in query tool then "Query -" name will not appear
// but it is still query tool so hide the tool button.
if (!webViewPtr->getBackForwardButtonHidden())
{
m_toolBtnBack->show();
m_toolBtnForward->show();
}
else
{
m_toolBtnBack->hide();
m_toolBtnForward->hide();
}
break;
}
}
}
}
}
// This function is used to move to old tab widget to new tab widget.
void DockTabWidget::moveTab(DockTabWidget *source, int sourceIndex, DockTabWidget *dest, int destIndex)
{
if (source == dest && sourceIndex < destIndex)
destIndex--;
QWidget *widget = source->widget(sourceIndex);
QString text = source->tabText(sourceIndex);
source->removeTab(sourceIndex);
dest->insertTab(destIndex, widget, text);
dest->setCurrentIndex(destIndex);
}
// This function is used to decode actual drop event on tab widget.
void DockTabWidget::decodeTabDropEvent(QDropEvent *event, DockTabWidget **p_tabWidget, int *p_index)
{
DockTabBar *tabBar = qobject_cast<DockTabBar *>(event->source());
if (!tabBar)
{
*p_tabWidget = NULL;
*p_index = 0;
return;
}
QByteArray data = event->mimeData()->data(MIMETYPE_TABINDEX);
QDataStream stream(&data, QIODevice::ReadOnly);
int index;
stream >> index;
*p_tabWidget = tabBar->tabWidget();
*p_index = index;
}
// This function is used to check event is actually drop event or not.
bool DockTabWidget::eventIsTabDrag(QDragEnterEvent *event)
{
return event->mimeData()->hasFormat(MIMETYPE_TABINDEX) && qobject_cast<DockTabBar *>(event->source());
}
// This function is used to delete tab widget when there is no tab inside.
void DockTabWidget::deleteIfEmpty()
{
if (count() == 0)
{
emit willBeAutomaticallyDeleted(this);
deleteLater();
}
}
// This is function is used to create another tab widget from parent window.
DockTabWidget *DockTabWidget::createAnotherTabWidget(QWidget *parent)
{
DockTabWidget *tab_widget = new DockTabWidget(this, parent);
tab_widget->tabBar()->setVisible(true);
return tab_widget;
}
// Check wether tab is insertable or not.
bool DockTabWidget::isInsertable(QWidget *widget)
{
Q_UNUSED(widget)
return true;
}
// Hide the close button of given index displayed on right side of tab
void TabWindow::enableDisableToolButton(const int &index)
void DockTabWidget::enableDisableToolButton(const int &index)
{
QToolButton *toolBtnPtr = NULL;
WebViewWindow *tmpwebviewPtr = NULL;
@@ -127,31 +477,52 @@ void TabWindow::enableDisableToolButton(const int &index)
}
}
// Get the index of the pushbutton which is requested by user to close the tab
int TabWindow::getButtonIndex(QPushButton *btn)
// Slot: When the tab index change, hide/show the toolbutton displayed on tab
void DockTabWidget::tabIndexChanged(int index)
{
QPushButton *nextBtnPtr = NULL;
int loopCount = 0;
int totalTabs = this->count();
int tabCount = 0;
WebViewWindow *webViewPtr = NULL;
for (loopCount = 1;loopCount < totalTabs;loopCount++)
for (tabCount = 0; tabCount < this->count(); tabCount++)
{
QWidget *tab = tabBar()->tabButton(loopCount, QTabBar::RightSide);
// if main pgAdmin4 application tab then do nothing.
if (!QString::compare(this->tabText(tabCount), tr("pgAdmin 4"), Qt::CaseInsensitive))
continue;
QWidget *tab = this->widget(tabCount);
if (tab != NULL)
{
nextBtnPtr = dynamic_cast<QPushButton*>(tab);
if (nextBtnPtr != NULL && btn != NULL && nextBtnPtr == btn)
return loopCount;
QList<QWidget*> widgetList = tab->findChildren<QWidget*>();
foreach( QWidget* widgetPtr, widgetList )
{
if (widgetPtr != NULL)
{
webViewPtr = dynamic_cast<WebViewWindow*>(widgetPtr);
if (webViewPtr != NULL)
break;
}
}
}
if (tabCount != index)
this->showHideToolButton(tabCount, 0);
else
{
if (!webViewPtr->getBackForwardButtonHidden())
this->showHideToolButton(tabCount, 1);
else
this->showHideToolButton(tabCount, 0);
}
}
return 0;
// paint the tab text again as index of the tab widget changed.
this->tabBar()->update();
}
// Show and Hide the toolbutton once the tab is deselected depending on the option
// option 0: Hide the toolButton
// option 1: Show the toolButton
void TabWindow::showHideToolButton(const int &index, const int &option)
void DockTabWidget::showHideToolButton(const int &index, const int &option)
{
QToolButton *toolBtnPtr = NULL;
@@ -177,7 +548,166 @@ void TabWindow::showHideToolButton(const int &index, const int &option)
}
// Set the tab tool tip text
void TabWindow::setTabToolTipText(const int &index, const QString &toolTipString)
void DockTabWidget::setTabToolTipText(const int &index, const QString &toolTipString)
{
tabBar()->setTabToolTip(index, toolTipString);
}
// Implementation of custom tab bar for docking window.
DockTabBar::DockTabBar(DockTabWidget *tabWidget, QWidget *parent) :
QTabBar(parent),
tab_widget(tabWidget)
{
isStartingDrag = false;
setAcceptDrops(true);
}
// Insert new tab at specified index.
int DockTabBar::insertionIndexAt(const QPoint &pos)
{
int index = count();
for (int i = 0; i < count(); ++i)
{
QRect rect = tabRect(i);
QRect rect1(rect.x(), rect.y(), rect.width() / 2, rect.height());
QRect rect2(rect.x() + rect1.width(), rect.y(), rect.width() - rect1.width(), rect.height());
if (rect1.contains(pos))
{
index = i;
break;
}
if (rect2.contains(pos))
{
index = i + 1;
break;
}
}
return index;
}
// Mouse press event handler for tab drag.
void DockTabBar::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
dragStartPos = event->pos();
isStartingDrag = true;
}
QTabBar::mousePressEvent(event);
}
// Mouse move event handler for tab drag.
void DockTabBar::mouseMoveEvent(QMouseEvent *event)
{
if (!isStartingDrag)
return;
if ((!event->buttons()) && Qt::LeftButton)
return;
if ((event->pos() - dragStartPos).manhattanLength() < QApplication::startDragDistance())
return;
int index = tabAt(event->pos());
if (index < 0)
return;
// Don't allow to drag the pgAdmin4 main tab.
if (!QString::compare(tab_widget->tabText(index), tr("pgAdmin 4"), Qt::CaseInsensitive))
{
return;
}
// create data
QMimeData *mimeData = new QMimeData;
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << index;
mimeData->setData(MIMETYPE_TABINDEX, data);
// create pixmap
QRect rect = tabRect(index);
QPixmap pixmap(rect.size());
render(&pixmap, QPoint(), QRegion(rect));
// exec drag
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(pixmap);
QPoint offset = dragStartPos - rect.topLeft();
drag->setHotSpot(offset);
Qt::DropAction dropAction = drag->exec(Qt::MoveAction | Qt::IgnoreAction);
if (dropAction != Qt::MoveAction)
{
DockTabWidget *newTabWidget = tab_widget->createAnotherTabWidget();
if (!newTabWidget->isInsertable(tab_widget, index))
{
newTabWidget->deleteLater();
return;
}
DockTabWidget::moveTab(tab_widget, index, newTabWidget, 0);
newTabWidget->setButtonsNewTabbar(0);
newTabWidget->enableDisableToolButton(0);
QRect newGeometry = newTabWidget->geometry();
newGeometry.moveTopLeft(QCursor::pos() - offset);
newTabWidget->setGeometry(newGeometry);
newTabWidget->show();
// Check if main pgAdmin4 application has only one tab then close tab bar.
// Here - check for count 2 because tab will be deleted later.
DockTabWidget *mainTab = DockTabWidget::getMainTabWidget();
if (mainTab != NULL && tab_widget != NULL && tab_widget == mainTab && mainTab->count() == 1)
mainTab->tabBar()->setVisible(false);
}
tab_widget->deleteIfEmpty();
isStartingDrag = false;
}
// Actual tab drag started.
void DockTabBar::dragEnterEvent(QDragEnterEvent *event)
{
if (DockTabWidget::eventIsTabDrag(event))
event->acceptProposedAction();
}
// Drag event leave the actual area.
void DockTabBar::dragLeaveEvent(QDragLeaveEvent * event)
{
Q_UNUSED(event)
}
// Drop event handler for tabbar.
void DockTabBar::dropEvent(QDropEvent *event)
{
DockTabWidget *oldTabWidget = NULL;
int oldIndex;
DockTabWidget::decodeTabDropEvent(event, &oldTabWidget, &oldIndex);
if (oldTabWidget && tab_widget && tab_widget->isInsertable(oldTabWidget, oldIndex))
{
int newIndex = insertionIndexAt(event->pos());
DockTabWidget::moveTab(oldTabWidget, oldIndex, tab_widget, newIndex);
// create new back/forward/close buttons and register its events.
tab_widget->setButtonsNewTabbar(newIndex);
tab_widget->enableDisableToolButton(newIndex);
// Check if main pgAdmin4 application has only one tab then close tab bar.
// Here - check for count 2 because tab will be deleted later.
DockTabWidget *mainTab = DockTabWidget::getMainTabWidget();
if (mainTab != NULL && oldTabWidget != NULL && oldTabWidget == mainTab && mainTab->count() == 1)
mainTab->tabBar()->setVisible(false);
event->acceptProposedAction();
}
}
+141 -12
View File
@@ -22,26 +22,53 @@ const int PGA_BTN_SIZE = 18;
const int PGA_BTN_SIZE = 16;
#endif
class TabBar : public QTabBar
#include <QTabBar>
#include <QTabWidget>
#define MIMETYPE_TABINDEX "x-paintfield-tabindex"
class DockTabBar;
class DockTabWidget : public QTabWidget
{
Q_OBJECT
friend class DockTabBar;
public:
TabBar(QWidget* parent=0) : QTabBar(parent)
explicit DockTabWidget(QWidget *parent = 0);
DockTabWidget(DockTabWidget *other, QWidget *parent = 0);
// Drop event handlers of parent tab widget.
static void moveTab(DockTabWidget *source, int sourceIndex, DockTabWidget *dest, int destIndex);
static void decodeTabDropEvent(QDropEvent *event, DockTabWidget **p_tabWidget, int *p_index);
static bool eventIsTabDrag(QDragEnterEvent *event);
void setButtonsNewTabbar(int index);
static DockTabWidget *mainTabWidget;
static DockTabWidget* getMainTabWidget()
{
return mainTabWidget;
}
protected:
QSize tabSizeHint(int) const
void setFloatingBaseWidget(QWidget *widget);
QWidget *floatingBaseWidget()
{
return QSize(250, 24);
return floatingWidget;
}
};
class TabWindow : public QTabWidget
{
Q_OBJECT
public:
TabWindow(QWidget *parent = 0);
void setFloatingEnabled(bool x);
bool isFloatingEnabled() const
{
return floatingEnabled;
}
virtual bool isInsertable(QWidget *widget);
bool isInsertable(DockTabWidget *other, int index)
{
return isInsertable(other->widget(index));
}
virtual DockTabWidget *createAnotherTabWidget(QWidget *parent = 0);
int getButtonIndex(QPushButton *btn);
void showHideToolButton(const int &index,const int &option);
@@ -52,8 +79,110 @@ public:
return QTabWidget::tabBar();
}
signals:
void willBeAutomaticallyDeleted(DockTabWidget *widget);
public slots:
void deleteIfEmpty();
void dockClosetabs();
void dockGoBackPage();
void dockGoForwardPage();
void tabIndexChanged(int index);
private:
TabBar *m_testTabBar;
QWidget *floatingWidget;
bool floatingEnabled;
};
class DockTabBar : public QTabBar
{
Q_OBJECT
public:
DockTabBar(DockTabWidget *tabWidget, QWidget *parent = 0);
// return tab widget of respective tab bar widget.
DockTabWidget *tabWidget()
{
return tab_widget;
}
protected:
// re-implemnted mouse event to detect tab drag started or not.
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
// re-implemnted drag-drop event for docking of tabs.
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void dragLeaveEvent(QDragLeaveEvent * event);
// re-implemented paint event to draw the text on tab bar of tab widget control.
void paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
bool isToolBtnVisible = false;
DockTabWidget *l_tab_widget = dynamic_cast<DockTabWidget*>(this->parent());
if (l_tab_widget != NULL)
{
int current_index = l_tab_widget->currentIndex();
QStylePainter painter(this);
for(int i = 0; i < l_tab_widget->count(); ++i)
{
QString str = l_tab_widget->tabText(i);
if (!str.startsWith("pgAdmin 4") && !str.startsWith("Query -") && !str.startsWith("Debugger"))
isToolBtnVisible = true;
QStyleOptionTab option;
initStyleOption(&option, i);
QString tempText = this->tabText(i);
if (tempText.length() > 28)
{
tempText = tempText.mid(0,27);
tempText += QString("...");
}
QRect rect(option.rect);
// If toolButton is visible then only draw text after tool button pixel area.
// If tool button is not visible - draw the text after margin of 10px.
if (isToolBtnVisible)
{
if ((current_index != -1) && i == current_index)
{
if (str.startsWith("Query -") || str.startsWith("Debugger"))
rect.setX(option.rect.x() + 10);
else
rect.setX(option.rect.x() + 45);
}
else
rect.setX(option.rect.x() + 10);
}
else
rect.setX(option.rect.x() + 10);
rect.setY(option.rect.y() + 7);
option.text = QString();
painter.drawControl(QStyle::CE_TabBarTab, option);
painter.drawItemText(rect, 0, palette(), 1, tempText);
}
}
}
#ifdef __APPLE__
QSize tabSizeHint(int) const
{
return QSize(250, 26);
}
#endif
private:
int insertionIndexAt(const QPoint &pos);
DockTabWidget *tab_widget;
bool isStartingDrag;
QPoint dragStartPos;
};
#endif // TABWINDOW_H
+126
View File
@@ -13,6 +13,14 @@
// App headers
#include "WebViewWindow.h"
#include "TabWindow.h"
#ifndef PGADMIN4_USE_WEBENGINE
#include <QWebPage>
#include <QNetworkRequest>
#endif
WebViewWindow *WebViewWindow::mainWebViewWindow = NULL;
// Override QWebEnginePage to handle link delegation
#ifdef PGADMIN4_USE_WEBENGINE
@@ -46,6 +54,85 @@ WebViewWindow::WebViewWindow(QWidget *parent) :
{
m_url = QString("");
m_tabIndex = 0;
m_backForwardBtnHide = false;
// Accept drop event for only main pgAdmin4 application window.
if (mainWebViewWindow == NULL)
mainWebViewWindow = this;
setAcceptDrops(true);
}
// Actual tab drag started.
void WebViewWindow::dragEnterEvent(QDragEnterEvent *event)
{
//DockTabWidget *mainTabWidget = DockTabWidget::getMainTabWidget();
//if (this->parent()->parent()->parent() == mainTabWidget)
event->accept();
}
void WebViewWindow::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
}
// Drop event handler for tabbar.
void WebViewWindow::dropEvent(QDropEvent *event)
{
DockTabWidget *oldTabWidget;
int oldIndex;
DockTabWidget::decodeTabDropEvent(event, &oldTabWidget, &oldIndex);
//DockTabWidget *mainTabWidget = DockTabWidget::getMainTabWidget();
DockTabWidget *mainTabWidget = dynamic_cast<DockTabWidget*>(this->parent()->parent()->parent());
if (oldTabWidget && mainTabWidget && oldTabWidget != mainTabWidget)
//if (oldTabWidget && mainTabWidget)
{
mainTabWidget->tabBar()->setVisible(true);
QPoint pos = event->pos();
int index = mainTabWidget->tabBar()->count();
for (int i = 0; i < mainTabWidget->tabBar()->count(); ++i)
{
QRect rect = mainTabWidget->tabBar()->tabRect(i);
QRect rect1(rect.x(), rect.y(), rect.width() / 2, rect.height());
QRect rect2(rect.x() + rect1.width(), rect.y(), rect.width() - rect1.width(), rect.height());
if (rect1.contains(pos))
{
index = i;
break;
}
if (rect2.contains(pos))
{
index = i + 1;
break;
}
}
DockTabWidget::moveTab(oldTabWidget, oldIndex, mainTabWidget, index);
// create new back/forward/close buttons and register its events.
mainTabWidget->setButtonsNewTabbar(index);
mainTabWidget->enableDisableToolButton(index);
// Check if main pgAdmin4 application has only one tab then close tab bar.
// Here - check for count 2 because tab will be deleted later.
DockTabWidget *mainTab = DockTabWidget::getMainTabWidget();
if (mainTab != NULL && oldTabWidget != NULL && oldTabWidget == mainTab && mainTab->count() == 1)
mainTab->tabBar()->setVisible(false);
event->acceptProposedAction();
}
}
void WebViewWindow::setBackForwardButtonHidden(const bool hideButton)
{
m_backForwardBtnHide = hideButton;
}
bool WebViewWindow::getBackForwardButtonHidden() const
{
return m_backForwardBtnHide;
}
void WebViewWindow::setFirstLoadURL(const QString &url)
@@ -67,3 +154,42 @@ int WebViewWindow::getTabIndex() const
{
return m_tabIndex;
}
#ifndef PGADMIN4_USE_WEBENGINE
WebViewPage::WebViewPage(QObject *parent)
: QWebPage(parent)
{
}
bool WebViewPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type)
{
Q_UNUSED(type);
Q_UNUSED(request);
Q_UNUSED(frame);
return true;
}
QWebPage *WebViewPage::createWindow(QWebPage::WebWindowType type)
{
if (type == QWebPage::WebBrowserWindow)
{
QWebPage *_page = NULL;
emit createTabWindowKit(_page);
return _page;
}
return NULL;
}
bool WebViewPage::javaScriptConfirm(QWebFrame * frame, const QString & msg)
{
// If required, override the QDialog to give custom confirmation message to user.
Q_UNUSED(frame);
Q_UNUSED(msg);
return false;
}
WebViewPage::~WebViewPage()
{
}
#endif
+35 -1
View File
@@ -51,11 +51,45 @@ public:
QString getFirstLoadURL() const;
void setTabIndex(const int &tabIndex);
int getTabIndex() const;
void setBackForwardButtonHidden(const bool hideButton);
bool getBackForwardButtonHidden() const;
// Store main webview window of pgAdmin4 application.
static WebViewWindow *mainWebViewWindow;
static WebViewWindow* getMainWebViewWindow()
{
return mainWebViewWindow;
}
protected:
// re-implemnted drag-drop event for docking of tabs.
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
QString m_url;
int m_tabIndex;
bool m_backForwardBtnHide;
};
#ifndef PGADMIN4_USE_WEBENGINE
class WebViewPage : public QWebPage
{
Q_OBJECT
public:
WebViewPage(QObject *parent = 0);
~WebViewPage();
protected:
virtual bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
QWebPage *createWindow(QWebPage::WebWindowType type);
bool javaScriptConfirm(QWebFrame * frame, const QString & msg);
signals:
void createTabWindowKit(QWebPage * &);
};
#endif
#endif // WEBVIEWWINDOW_H
Regular → Executable
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 290 B

Regular → Executable
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 346 B

Regular → Executable
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 270 B

+86 -16
View File
@@ -175,6 +175,15 @@ void delay( int milliseconds )
int main(int argc, char * argv[])
{
/*
* Before starting main application, need to set 'QT_X11_NO_MITSHM=1'
* to make the runtime work with IBM PPC machine.
*/
#if defined (Q_OS_LINUX)
QByteArray val("1");
qputenv("QT_X11_NO_MITSHM", val);
#endif
// Create the QT application
QApplication app(argc, argv);
@@ -183,6 +192,48 @@ int main(int argc, char * argv[])
QCoreApplication::setOrganizationDomain("pgadmin.org");
QCoreApplication::setApplicationName(PGA_APP_NAME.toLower().replace(" ", ""));
#if QT_VERSION >= 0x050000
// Set high DPI pixmap to display icons clear on Qt widget.
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
/* In windows and linux, it is required to set application level proxy
* becuase socket bind logic to find free port gives socket creation error
* when system proxy is configured. We are also setting
* "setUseSystemConfiguration"=true to use the system proxy which will
* override this application level proxy. As this bug is fixed in Qt 5.9 so
* need to set application proxy for Qt version < 5.9.
*/
#ifndef PGADMIN4_USE_WEBENGINE
#if defined (Q_OS_WIN) && QT_VERSION <= 0x050800
// Give dummy URL required to find proxy server configured in windows.
QNetworkProxyQuery proxyQuery(QUrl("https://www.pgadmin.org"));
QNetworkProxy l_proxy;
QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery(proxyQuery);
if (listOfProxies.size())
{
l_proxy = listOfProxies[0];
// If host name is not empty means proxy server is configured.
if (!l_proxy.hostName().isEmpty()) {
QNetworkProxy::setApplicationProxy(QNetworkProxy());
}
}
#endif
#endif
#ifndef PGADMIN4_USE_WEBENGINE
#if defined (Q_OS_LINUX) && QT_VERSION <= 0x050800
QByteArray proxy_env;
proxy_env = qgetenv("http_proxy");
// If http_proxy environment is defined in linux then proxy server is configured.
if (!proxy_env.isEmpty()) {
QNetworkProxy::setApplicationProxy(QNetworkProxy());
}
#endif
#endif
// Display the spash screen
QSplashScreen *splash = new QSplashScreen();
splash->setPixmap(QPixmap(":/splash.png"));
@@ -199,6 +250,11 @@ int main(int argc, char * argv[])
{
#if QT_VERSION >= 0x050000
QTcpSocket socket;
#if QT_VERSION >= 0x050900
socket.setProxy(QNetworkProxy::NoProxy);
#endif
socket.bind(0, QTcpSocket::ShareAddress);
#else
QUdpSocket socket;
@@ -248,10 +304,6 @@ int main(int argc, char * argv[])
server->start();
// This is a hack. Wait a second and then check to see if the server thread
// is still running. If it's not, we probably had a startup error
delay(1000);
// Any errors?
if (server->isFinished() || server->getError().length() > 0)
{
@@ -295,30 +347,38 @@ int main(int argc, char * argv[])
// Generate the app server URL
QString appServerUrl = QString("http://localhost:%1/?key=%2").arg(port).arg(key);
QString appServerUrl = QString("http://127.0.0.1:%1/?key=%2").arg(port).arg(key);
// Read the server connection timeout from the registry or set the default timeout.
QSettings settings;
int timeout = settings.value("ConnectionTimeout", 30).toInt();
// Now the server should be up, we'll attempt to connect and get a response.
// We'll retry in a loop a few time before aborting if necessary.
int attempt = 0;
while (attempt++ < 30)
QTime endTime = QTime::currentTime().addSecs(timeout);
bool alive = false;
while(QTime::currentTime() <= endTime)
{
bool alive = PingServer(QUrl(appServerUrl));
alive = PingServer(QUrl(appServerUrl));
if (alive)
{
break;
}
if (attempt == 30)
{
splash->finish(NULL);
QString error(QWidget::tr("The application server could not be contacted."));
QMessageBox::critical(NULL, QString(QWidget::tr("Fatal Error")), error);
delay(200);
}
exit(1);
}
// Attempt to connect one more time in case of a long network timeout while looping
if(!alive && !PingServer(QUrl(appServerUrl)))
{
splash->finish(NULL);
QString error(QWidget::tr("The application server could not be contacted."));
QMessageBox::critical(NULL, QString(QWidget::tr("Fatal Error")), error);
delay(1000);
exit(1);
}
// Create & show the main window
@@ -329,6 +389,16 @@ int main(int argc, char * argv[])
// Go!
splash->finish(NULL);
// Set global application stylesheet.
QFile file(":/qss/pgadmin4.qss");
if(file.open(QFile::ReadOnly))
{
QString StyleSheet = QLatin1String(file.readAll());
qApp->setStyleSheet(StyleSheet);
file.close();
}
return app.exec();
}
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = 1.4.0.0
VERSION = 2.0.0.0
QMAKE_TARGET_COMPANY = "The pgAdmin Development Team"
QMAKE_TARGET_PRODUCT = "pgAdmin 4"
QMAKE_TARGET_DESCRIPTION = "pgAdmin 4 Desktop Runtime"
+1
View File
@@ -5,5 +5,6 @@
<file>forward.png</file>
<file>close.png</file>
<file>splash.png</file>
<file>qss/pgadmin4.qss</file>
</qresource>
</RCC>
+3
View File
@@ -0,0 +1,3 @@
QTabBar::tab {
background-color: #E8E8E8;
}
Regular → Executable
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 13 KiB

+30
View File
@@ -0,0 +1,30 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
# We recommend you to keep these unchanged
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 80
[*.py]
indent_size = 4
[*.js]
indent_size = 2
[*.css]
indent_size = 2
# Matches the exact file package.json
[{package.json}]
indent_size = 2
[*.md]
trim_trailing_whitespace = false
+48
View File
@@ -0,0 +1,48 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
'amd': true,
'jasmine': true,
},
'extends': [
'eslint:recommended',
"plugin:react/recommended",
],
'parserOptions': {
'ecmaFeatures': {
'experimentalObjectRestSpread': true,
'jsx': true
},
'sourceType': 'module'
},
'plugins': [
'react'
],
'globals': {
'_': true,
'module': true,
},
'rules': {
'indent': [
'error',
2
],
'linebreak-style': [
'error',
'unix'
],
'quotes': [
'error',
'single'
],
'semi': [
'error',
'always'
],
'comma-dangle': [
'error',
'always-multiline'
],
}
};
+79 -52
View File
@@ -11,9 +11,15 @@
#
##########################################################################
import logging
import os
import sys
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# We need to include the root directory in sys.path to ensure that we can
# find everything we need when running in the standalone runtime.
@@ -29,7 +35,7 @@ from pgadmin.utils import env, IS_PY2, IS_WIN, fs_short_path
# Name of the application to display in the UI
APP_NAME = 'pgAdmin 4'
APP_ICON = 'icon-postgres-alt'
APP_ICON = 'pg-icon'
##########################################################################
# Application settings
@@ -44,8 +50,8 @@ APP_ICON = 'icon-postgres-alt'
#
# Application version number components
APP_RELEASE = 1
APP_REVISION = 4
APP_RELEASE = 2
APP_REVISION = 0
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
# for GA releases.
@@ -54,9 +60,7 @@ APP_SUFFIX = ''
# Numeric application version for upgrade checks. Should be in the format:
# [X]XYYZZ, where X is the release version, Y is the revision, with a leading
# zero if needed, and Z represents the suffix, with a leading zero if needed
# Note that we messed this up in v1.x, where the format is [X]XYZZZ. This
# should be fixed for v2.x!!
APP_VERSION_INT = 14001
APP_VERSION_INT = 20003
# DO NOT CHANGE!
# The application version string, constructed from the components
@@ -93,46 +97,6 @@ MODULE_BLACKLIST = ['test']
NODE_BLACKLIST = []
# Data directory for storage of config settings etc. This shouldn't normally
# need to be changed - it's here as various other settings depend on it.
if IS_WIN:
# Use the short path on windows
DATA_DIR = os.path.realpath(
os.path.join(fs_short_path(env('APPDATA')), u"pgAdmin")
)
else:
DATA_DIR = os.path.realpath(os.path.expanduser(u'~/.pgadmin/'))
##########################################################################
# Log settings
##########################################################################
# Debug mode?
DEBUG = False
import logging
# Application log level - one of:
# CRITICAL 50
# ERROR 40
# WARNING 30
# SQL 25
# INFO 20
# DEBUG 10
# NOTSET 0
CONSOLE_LOG_LEVEL = logging.WARNING
FILE_LOG_LEVEL = logging.WARNING
# Log format.
CONSOLE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'
FILE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'
# Log file name
LOG_FILE = os.path.join(DATA_DIR, 'pgadmin4.log')
##########################################################################
# Server settings
##########################################################################
@@ -142,13 +106,25 @@ LOG_FILE = os.path.join(DATA_DIR, 'pgadmin4.log')
# default login.
#
# DO NOT DISABLE SERVER MODE IF RUNNING ON A WEBSERVER!!
SERVER_MODE = True
#
# We only set SERVER_MODE if it's not already set. That's to allow the
# runtime to force it to False.
#
# NOTE: If you change the value of SERVER_MODE in an included config file,
# you may also need to redefine any values below that are derived
# from it, notably various paths such as LOG_FILE and anything
# using DATA_DIR.
if builtins.SERVER_MODE is None:
SERVER_MODE = True
else:
SERVER_MODE = builtins.SERVER_MODE
# User ID (email address) to use for the default user in desktop mode.
# The default should be fine here, as it's not exposed in the app.
DESKTOP_USER = 'pgadmin4@pgadmin.org'
# This configuration otion allows the user to host the application on a LAN
# This option allows the user to host the application on a LAN
# Default hosting is on localhost (DEFAULT_SERVER='localhost').
# To host pgAdmin4 over LAN set DEFAULT_SERVER='0.0.0.0' (or a specific
# adaptor address.
@@ -156,7 +132,7 @@ DESKTOP_USER = 'pgadmin4@pgadmin.org'
# NOTE: This is NOT recommended for production use, only for debugging
# or testing. Production installations should be run as a WSGI application
# behind Apache HTTPD.
DEFAULT_SERVER = 'localhost'
DEFAULT_SERVER = '127.0.0.1'
# The default port on which the app server will listen if not set in the
# environment by the runtime
@@ -177,6 +153,52 @@ SECURITY_PASSWORD_HASH = 'pbkdf2_sha512'
# has no effect on <= Python 2.7.
MINIFY_PAGE = True
# Data directory for storage of config settings etc. This shouldn't normally
# need to be changed - it's here as various other settings depend on it.
# On Windows, we always store data in %APPDATA%\pgAdmin. On other platforms,
# if we're in server mode we use /var/lib/pgadmin, otherwise ~/.pgadmin
if IS_WIN:
# Use the short path on windows
DATA_DIR = os.path.realpath(
os.path.join(fs_short_path(env('APPDATA')), u"pgAdmin")
)
else:
if SERVER_MODE:
DATA_DIR = '/var/lib/pgadmin'
else:
DATA_DIR = os.path.realpath(os.path.expanduser(u'~/.pgadmin/'))
##########################################################################
# Log settings
##########################################################################
# Debug mode?
DEBUG = False
# Application log level - one of:
# CRITICAL 50
# ERROR 40
# WARNING 30
# SQL 25
# INFO 20
# DEBUG 10
# NOTSET 0
CONSOLE_LOG_LEVEL = logging.WARNING
FILE_LOG_LEVEL = logging.WARNING
# Log format.
CONSOLE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'
FILE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'
# Log file name. This goes in the data directory, except on non-Windows
# platforms in server mode.
if SERVER_MODE and not IS_WIN:
LOG_FILE = '/var/log/pgadmin/pgadmin4.log'
else:
LOG_FILE = os.path.join(DATA_DIR, 'pgadmin4.log')
##########################################################################
# Server Connection Driver Settings
##########################################################################
@@ -299,14 +321,13 @@ STORAGE_DIR = os.path.join(DATA_DIR, 'storage')
##########################################################################
DEFAULT_BINARY_PATHS = {
"pg": "",
"ppas": ""
"ppas": "",
"gpdb": ""
}
##########################################################################
# Test settings - used primarily by the regression suite, not for users
##########################################################################
# Set default testing mode
TESTING_MODE = False
# The default path for SQLite database for testing
TEST_SQLITE_PATH = os.path.join(DATA_DIR, 'test_pgadmin4.db')
@@ -323,6 +344,12 @@ THREADED_MODE = True
##########################################################################
SQLALCHEMY_TRACK_MODIFICATIONS = False
##########################################################################
# Number of records to fetch in one batch in query tool when query result
# set is large.
##########################################################################
ON_DEMAND_RECORD_COUNT = 1000
##########################################################################
# Local config settings
##########################################################################
+31 -36
View File
@@ -1,62 +1,57 @@
// Karma configuration
// Generated on Wed Mar 01 2017 14:19:28 GMT-0500 (EST)
const webpackConfig = require('./webpack.test.config.js');
module.exports = function(config) {
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
'regression/javascript/test-main.js',
{pattern: 'regression/javascript/**/*.js', included: false},
{pattern: 'pgadmin/static/vendor/**/*.js', included: false},
{pattern: 'pgadmin/static/js/**/*.js', included: false}
frameworks: ['jasmine'],
reporters: ['progress', 'kjhtml'],
plugins: [
'karma-webpack',
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-jasmine-html-reporter',
],
files: [
{pattern: 'pgadmin/static/**/*.js', included: false},
{pattern: 'pgadmin/static/vendor/**/*.js', included: false},
{pattern: 'pgadmin/browser/static/js/**/*.js', included: false},
'regression/javascript/**/*.jsx',
'regression/javascript/**/*.js',
'pgadmin/static/bundle/slickgrid.js',
],
// list of files to exclude
exclude: [
'pgadmin/static/js/pgadmin.js',
'pgadmin/static/vendor/**/*[Tt]est.js',
'pgadmin/static/vendor/**/*[Ss]pec.js'
'pgadmin/static/vendor/**/*[Ss]pec.js',
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'regression/javascript/**/*.js': ['webpack'],
'regression/javascript/**/*.jsx': ['webpack'],
'pgadmin/static/bundle/slickgrid.js': ['webpack'],
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only',
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
logLevel: config.LOG_WARN,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
autoWatch: true,
// start these browsers
@@ -66,10 +61,10 @@ module.exports = function(config) {
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}
concurrency: Infinity,
});
};
+54
View File
@@ -0,0 +1,54 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
+94
View File
@@ -0,0 +1,94 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
import logging
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
logger = logging.getLogger('alembic.env')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.readthedocs.org/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
engine = engine_from_config(config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
connection = engine.connect()
context.configure(connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args)
try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
+33
View File
@@ -0,0 +1,33 @@
##########################################################################
##
## pgAdmin 4 - PostgreSQL Tools
##
## Copyright (C) 2013 - 2017, The pgAdmin Development Team
## This software is released under the PostgreSQL Licence
##
##########################################################################
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}
+241
View File
@@ -0,0 +1,241 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Update DB to version 14
Revision ID: 09d53fca90c7
Revises: fdc58d9bd449
Create Date: 2017-03-13 12:27:30.543908
"""
import base64
import os
import sys
import config
from pgadmin.model import db, Server
from pgadmin.setup import get_version
# revision identifiers, used by Alembic.
revision = '09d53fca90c7'
down_revision = 'fdc58d9bd449'
branch_labels = None
depends_on = None
def upgrade():
version = get_version()
# Changes introduced in schema version 2
if version < 2:
# Create the 'server' table
db.metadata.create_all(db.engine, tables=[Server.__table__])
if version < 3:
db.engine.execute(
'ALTER TABLE server ADD COLUMN comment TEXT(1024)'
)
if version < 4:
db.engine.execute(
'ALTER TABLE server ADD COLUMN password TEXT(64)'
)
if version < 5:
db.engine.execute('ALTER TABLE server ADD COLUMN role text(64)')
if version < 6:
db.engine.execute("ALTER TABLE server RENAME TO server_old")
db.engine.execute("""
CREATE TABLE server (
id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
servergroup_id INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
host VARCHAR(128) NOT NULL,
port INTEGER NOT NULL CHECK (port >= 1024 AND port <= 65534),
maintenance_db VARCHAR(64) NOT NULL,
username VARCHAR(64) NOT NULL,
ssl_mode VARCHAR(16) NOT NULL CHECK (
ssl_mode IN (
'allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full'
)),
comment VARCHAR(1024), password TEXT(64), role text(64),
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES user (id),
FOREIGN KEY(servergroup_id) REFERENCES servergroup (id)
)""")
db.engine.execute("""
INSERT INTO server (
id, user_id, servergroup_id, name, host, port, maintenance_db, username,
ssl_mode, comment, password, role
) SELECT
id, user_id, servergroup_id, name, host, port, maintenance_db, username,
ssl_mode, comment, password, role
FROM server_old""")
db.engine.execute("DROP TABLE server_old")
if version < 8:
db.engine.execute("""
CREATE TABLE module_preference(
id INTEGER PRIMARY KEY,
name VARCHAR(256) NOT NULL
)""")
db.engine.execute("""
CREATE TABLE preference_category(
id INTEGER PRIMARY KEY,
mid INTEGER,
name VARCHAR(256) NOT NULL,
FOREIGN KEY(mid) REFERENCES module_preference(id)
)""")
db.engine.execute("""
CREATE TABLE preferences (
id INTEGER PRIMARY KEY,
cid INTEGER NOT NULL,
name VARCHAR(256) NOT NULL,
FOREIGN KEY(cid) REFERENCES preference_category (id)
)""")
db.engine.execute("""
CREATE TABLE user_preferences (
pid INTEGER,
uid INTEGER,
value VARCHAR(1024) NOT NULL,
PRIMARY KEY (pid, uid),
FOREIGN KEY(pid) REFERENCES preferences (pid),
FOREIGN KEY(uid) REFERENCES user (id)
)""")
if version < 9:
db.engine.execute("""
CREATE TABLE IF NOT EXISTS debugger_function_arguments (
server_id INTEGER ,
database_id INTEGER ,
schema_id INTEGER ,
function_id INTEGER ,
arg_id INTEGER ,
is_null INTEGER NOT NULL CHECK (is_null >= 0 AND is_null <= 1) ,
is_expression INTEGER NOT NULL CHECK (is_expression >= 0 AND is_expression <= 1) ,
use_default INTEGER NOT NULL CHECK (use_default >= 0 AND use_default <= 1) ,
value TEXT,
PRIMARY KEY (server_id, database_id, schema_id, function_id, arg_id)
)""")
if version < 10:
db.engine.execute("""
CREATE TABLE process(
user_id INTEGER NOT NULL,
pid TEXT NOT NULL,
desc TEXT NOT NULL,
command TEXT NOT NULL,
arguments TEXT,
start_time TEXT,
end_time TEXT,
logdir TEXT,
exit_code INTEGER,
acknowledge TEXT,
PRIMARY KEY(pid),
FOREIGN KEY(user_id) REFERENCES user (id)
)""")
if version < 11:
db.engine.execute("""
UPDATE role
SET name = 'Administrator',
description = 'pgAdmin Administrator Role'
WHERE name = 'Administrators'
""")
db.engine.execute("""
INSERT INTO role ( name, description )
VALUES ('User', 'pgAdmin User Role')
""")
if version < 12:
db.engine.execute("ALTER TABLE server RENAME TO server_old")
db.engine.execute("""
CREATE TABLE server (
id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
servergroup_id INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
host VARCHAR(128) NOT NULL,
port INTEGER NOT NULL CHECK (port >= 1024 AND port <= 65535),
maintenance_db VARCHAR(64) NOT NULL,
username VARCHAR(64) NOT NULL,
ssl_mode VARCHAR(16) NOT NULL CHECK (
ssl_mode IN (
'allow', 'prefer', 'require', 'disable', 'verify-ca', 'verify-full'
)),
comment VARCHAR(1024), password TEXT(64), role text(64),
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES user (id),
FOREIGN KEY(servergroup_id) REFERENCES servergroup (id)
)""")
db.engine.execute("""
INSERT INTO server (
id, user_id, servergroup_id, name, host, port, maintenance_db, username,
ssl_mode, comment, password, role
) SELECT
id, user_id, servergroup_id, name, host, port, maintenance_db, username,
ssl_mode, comment, password, role
FROM server_old""")
db.engine.execute("DROP TABLE server_old")
if version < 13:
db.engine.execute("""
ALTER TABLE SERVER
ADD COLUMN discovery_id TEXT
""")
if version < 14:
db.engine.execute("""
CREATE TABLE keys (
name TEST NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (name))
""")
sql = "INSERT INTO keys (name, value) VALUES ('CSRF_SESSION_KEY', '%s')" % base64.urlsafe_b64encode(
os.urandom(32)).decode()
db.engine.execute(sql)
sql = "INSERT INTO keys (name, value) VALUES ('SECRET_KEY', '%s')" % base64.urlsafe_b64encode(
os.urandom(32)).decode()
db.engine.execute(sql)
# If SECURITY_PASSWORD_SALT is not in the config, but we're upgrading, then it must (unless the
# user edited the main config - which they shouldn't have done) have been at it's default
# value, so we'll use that. Otherwise, use whatever we can find in the config.
if hasattr(config, 'SECURITY_PASSWORD_SALT'):
sql = "INSERT INTO keys (name, value) VALUES ('SECURITY_PASSWORD_SALT', '%s')" % config.SECURITY_PASSWORD_SALT
else:
sql = "INSERT INTO keys (name, value) VALUES ('SECURITY_PASSWORD_SALT', 'SuperSecret3')"
db.engine.execute(sql)
# Finally, update the schema version
# version.value = config.SETTINGS_SCHEMA_VERSION
db.engine.execute(
'UPDATE version set value="%s" WHERE name = "ConfigDB"' % config.SETTINGS_SCHEMA_VERSION
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
print(u"""
Cannot downgrade from this version
Exiting...""")
sys.exit(1)
# ### end Alembic commands ###
+26
View File
@@ -0,0 +1,26 @@
"""empty message
Revision ID: 3c1e4b6eda55
Revises: 09d53fca90c7
Create Date: 2017-06-13 17:05:30.671859
"""
from pgadmin.model import db
# revision identifiers, used by Alembic.
revision = '3c1e4b6eda55'
down_revision = '09d53fca90c7'
branch_labels = None
depends_on = None
def upgrade():
db.engine.execute(
'ALTER TABLE server ADD COLUMN hostaddr TEXT(1024)'
)
def downgrade():
pass
+26
View File
@@ -0,0 +1,26 @@
"""empty message
Revision ID: d85a62333272
Revises: 3c1e4b6eda55
Create Date: 2017-07-07 16:03:23.842734
"""
from pgadmin.model import db
# revision identifiers, used by Alembic.
revision = 'd85a62333272'
down_revision = 'f195f9a4923d'
branch_labels = None
depends_on = None
def upgrade():
db.engine.execute(
'ALTER TABLE server ADD COLUMN db_res TEXT'
)
def downgrade():
pass
+46
View File
@@ -0,0 +1,46 @@
"""empty message
Revision ID: ef590e979b0d
Revises: d85a62333272
Create Date: 2017-08-23 18:37:14.836988
"""
from alembic import op
import sqlalchemy as sa
from pgadmin.model import db
# revision identifiers, used by Alembic.
revision = 'ef590e979b0d'
down_revision = 'd85a62333272'
branch_labels = None
depends_on = None
def upgrade():
db.engine.execute(
'ALTER TABLE server ADD COLUMN passfile TEXT'
)
db.engine.execute(
'ALTER TABLE server ADD COLUMN sslcert TEXT'
)
db.engine.execute(
'ALTER TABLE server ADD COLUMN sslkey TEXT'
)
db.engine.execute(
'ALTER TABLE server ADD COLUMN sslrootcert TEXT'
)
db.engine.execute(
'ALTER TABLE server ADD COLUMN sslcrl TEXT'
)
db.engine.execute(
'ALTER TABLE server ADD COLUMN sslcompression '
'INTEGER default 0'
)
db.engine.execute(
'UPDATE server SET sslcompression=0'
)
def downgrade():
pass
+45
View File
@@ -0,0 +1,45 @@
"""Encrypt the existing user password.
Revision ID: f195f9a4923d
Revises: 3c1e4b6eda55
Create Date: 2017-06-15 17:18:50.667139
"""
import config
from flask import current_app
from flask_security import Security, SQLAlchemyUserDatastore
from flask_security.utils import verify_and_update_password
from pgadmin.model import Keys, db, User, Role
# revision identifiers, used by Alembic.
revision = 'f195f9a4923d'
down_revision = '3c1e4b6eda55'
branch_labels = None
depends_on = None
def upgrade():
app = current_app
db.session.flush()
current_salt = Keys.query.filter_by(name = 'SECURITY_PASSWORD_SALT').first().value
app.config.update(dict(SECURITY_PASSWORD_SALT=current_salt))
app.config['SECURITY_PASSWORD_HASH'] = config.SECURITY_PASSWORD_HASH
if app.extensions.get('security') is None:
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
Security(app, user_datastore, register_blueprint=False)
else:
app.config['SECURITY_PASSWORD_SALT'] = current_salt
users = User.query.all()
# This will upgrade the plaintext password of all the user as per the
# SECURITY_PASSWORD_HASH.
for user in users:
if user.password is not None:
verify_and_update_password(user.password, user)
db.session.commit()
def downgrade():
pass
+149
View File
@@ -0,0 +1,149 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Initial database creation
Revision ID: fdc58d9bd449
Revises:
Create Date: 2017-03-13 11:15:16.401139
"""
import base64
import os
import config
import sqlalchemy as sa
from alembic import op
from flask import current_app
from flask_security import Security, SQLAlchemyUserDatastore
from flask_security.utils import encrypt_password
from pgadmin.model import db, User, Role
from pgadmin.setup import get_version
from pgadmin.setup import user_info
# revision identifiers, used by Alembic.
revision = 'fdc58d9bd449'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
if get_version() != -1:
return
op.create_table('version',
sa.Column('name', sa.String(length=32), nullable=False),
sa.Column('value', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('name')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('email', sa.String(length=256), nullable=False),
sa.Column('password', sa.String(length=256), nullable=True),
sa.Column('active', sa.Boolean(), nullable=False),
sa.Column('confirmed_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email')
)
op.create_table('role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=128), nullable=False),
sa.Column('description', sa.String(length=256), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('setting',
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('setting', sa.String(length=256), nullable=False),
sa.Column('value', sa.String(length=1024), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('user_id', 'setting')
)
op.create_table('roles_users',
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('role_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['role.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], )
)
op.create_table('servergroup',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=128), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('user_id', 'name')
)
op.create_table('server',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('servergroup_id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=128), nullable=False),
sa.Column('host', sa.String(length=128), nullable=False),
sa.Column('port', sa.Integer(), nullable=False),
sa.Column('maintenance_db', sa.String(length=64), nullable=False),
sa.Column('username', sa.String(length=64), nullable=False),
sa.Column('ssl_mode', sa.String(length=16), nullable=False),
sa.ForeignKeyConstraint(['servergroup_id'], ['servergroup.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
db.engine.execute("""
INSERT INTO "role"
VALUES(1, 'Administrators', 'pgAdmin Administrators Role')
""")
db.engine.execute("""
INSERT INTO "roles_users"
VALUES(1, 1);
""")
db.engine.execute("""
INSERT INTO "servergroup"
VALUES(1, 1, 'Servers')
""")
email, password = user_info()
current_salt = getattr(
config, 'SECURITY_PASSWORD_SALT', base64.urlsafe_b64encode(
os.urandom(32)
).decode()
)
if current_app.extensions.get('security') is None:
current_app.config['SECURITY_PASSWORD_SALT'] = current_salt
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
Security(current_app, user_datastore, register_blueprint=False)
else:
current_app.config['SECURITY_PASSWORD_SALT'] = current_salt
setattr(config, 'SECURITY_PASSWORD_SALT', current_salt)
password = encrypt_password(password)
db.engine.execute("""
INSERT INTO "user"
VALUES(1, '%s',
'%s',
1, NULL)
""" % (email, password))
db.engine.execute("""
INSERT INTO "version"
VALUES('ConfigDB', 2);
""")
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('server')
op.drop_table('servergroup')
op.drop_table('roles_users')
op.drop_table('setting')
op.drop_table('role')
op.drop_table('user')
op.drop_table('version')
# ### end Alembic commands ###
+94 -6
View File
@@ -1,10 +1,98 @@
{
"devDependencies": {
"jasmine-core": "^2.5.2",
"karma": "^1.5.0",
"karma-jasmine": "^1.1.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-requirejs": "^1.1.0",
"requirejs": "^2.3.3"
"babel-core": "~6.24.0",
"babel-loader": "~6.4.1",
"babel-preset-es2015": "~6.24.0",
"babel-preset-react": "~6.23.0",
"cross-env": "^5.0.1",
"eclint": "^2.3.0",
"enzyme": "~2.8.2",
"enzyme-matchers": "^3.1.0",
"eslint": "3.19.0",
"eslint-plugin-react": "^6.10.3",
"extract-text-webpack-plugin": "^2.1.2",
"file-loader": "^0.11.2",
"image-webpack-loader": "^3.3.1",
"jasmine-core": "~2.5.2",
"jasmine-enzyme": "^3.1.0",
"karma": "~1.5.0",
"karma-babel-preprocessor": "^6.0.1",
"karma-browserify": "~5.1.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-phantomjs-launcher": "~1.0.2",
"karma-requirejs": "~1.1.0",
"karma-sourcemap-loader": "~0.3.7",
"karma-webpack": "~2.0.3",
"node-sass": "^4.5.3",
"optimize-css-assets-webpack-plugin": "^2.0.0",
"raw-loader": "^0.5.1",
"react-addons-test-utils": "~15.4.2",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"uglifyjs-webpack-plugin": "^0.4.6",
"url-loader": "^0.5.9",
"webpack": "^3.0.0"
},
"dependencies": {
"acitree": "git+https://github.com/imsurinder90/jquery-aciTree.git#rc.7",
"alertifyjs": "^1.10.0",
"axios": "^0.16.1",
"babel-plugin-transform-es2015-modules-amd": "^6.24.1",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015-without-strict": "~0.0.4",
"babelify": "~7.3.0",
"backbone": "1.1.2",
"backform": "^0.2.0",
"backgrid": "^0.3.8",
"backgrid-filter": "^0.3.7",
"backgrid-select-all": "^0.3.5",
"backgrid-sizeable-columns": "^0.1.1",
"bignumber.js": "^4.0.2",
"bootstrap": "^3.3.7",
"bootstrap-datepicker": "^1.7.0",
"bootstrap-switch": "3.3.2",
"bowser": "1.6.1",
"browserify": "~14.1.0",
"codemirror": "^5.29.0",
"css-loader": "0.14.0",
"cssnano": "^3.10.0",
"dropzone": "^5.1.1",
"eonasdan-bootstrap-datetimepicker": "^4.17.47",
"exports-loader": "~0.6.4",
"flotr2": "^0.1.0",
"font-awesome": "^4.7.0",
"hard-source-webpack-plugin": "^0.4.9",
"immutability-helper": "^2.2.0",
"imports-loader": "^0.7.1",
"jquery": "1.11.2",
"jquery-contextmenu": "^2.5.0",
"jquery-ui": "^1.12.1",
"moment": "^2.18.1",
"prop-types": "^15.5.10",
"react": "file:../web/pgadmin/static/vendor/react",
"react-dom": "file:../web/pgadmin/static/vendor/react-dom",
"react-split-pane": "^0.1.63",
"requirejs": "~2.3.3",
"select2": "^4.0.3",
"shim-loader": "^1.0.1",
"slickgrid": "git+https://github.com/6pac/SlickGrid.git#2.3.7",
"snapsvg": "^0.5.1",
"underscore": "^1.8.3",
"underscore.string": "^3.3.4",
"watchify": "~3.9.0",
"webcabin-docker": "^2.2.2"
},
"scripts": {
"linter": "yarn run eslint pgadmin/static/jsx/**/*.jsx pgadmin/static/js/selection/*.js regression/javascript/**/*.jsx regression/javascript/**/*.js *.js",
"webpacker": "yarn run webpack -- --config webpack.config.js --progress",
"webpacker:watch": "yarn run webpack -- --config webpack.config.js --progress --watch",
"bundle:watch": "yarn run linter && yarn run webpacker:watch",
"bundle:dev": "yarn run linter && yarn run webpacker",
"bundle": "cross-env NODE_ENV=production yarn run bundle:dev",
"test:karma-once": "yarn run linter && yarn run karma start -- --single-run",
"test:karma": "yarn run linter && yarn run karma start",
"test:feature": "yarn run bundle && python regression/runtests.py --pkg feature_tests",
"test": "yarn run test:karma-once && yarn run bundle && python regression/runtests.py"
}
}
+37 -3
View File
@@ -14,14 +14,29 @@ to start a web server."""
import os
import sys
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# We need to include the root directory in sys.path to ensure that we can
# find everything we need when running in the standalone runtime.
root = os.path.dirname(os.path.realpath(__file__))
if sys.path[0] != root:
sys.path.insert(0, root)
# Grab the SERVER_MODE if it's been set by the runtime
if 'SERVER_MODE' in globals():
builtins.SERVER_MODE = globals()['SERVER_MODE']
else:
builtins.SERVER_MODE = None
import config
from pgadmin import create_app
from pgadmin.utils import u, fs_encoding, file_quote
if config.DEBUG:
from pgadmin.utils.javascript.javascript_bundler import JavascriptBundler, JsState
# Get the config database schema version. We store this in pgadmin.model
# as it turns out that putting it in the config files isn't a great idea
@@ -34,16 +49,20 @@ config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
# Check if the database exists. If it does not, create it.
if not os.path.isfile(config.SQLITE_PATH):
from pgadmin.utils import u, fs_encoding, file_quote
setupfile = os.path.join(
os.path.dirname(os.path.realpath(u(__file__, fs_encoding))), u'setup.py'
)
exec(open(file_quote(setupfile), 'r').read())
##########################################################################
# Server starup
# Server startup
##########################################################################
# Build Javascript files
if config.DEBUG:
javascriptBundler = JavascriptBundler()
javascriptBundler.bundle()
# Create the app!
app = create_app()
@@ -52,6 +71,13 @@ if config.DEBUG:
else:
app.debug = False
# respond to JS
if config.DEBUG:
if javascriptBundler.report() == JsState.NONE:
app.logger.error("Unable to generate javascript")
app.logger.error("To run the app ensure that yarn install command runs successfully")
raise Exception("No generated javascript, aborting")
# Start the web server. The port number should have already been set by the
# runtime if we're running in desktop mode, otherwise we'll just use the
# Flask default.
@@ -104,11 +130,19 @@ if __name__ == '__main__':
if IS_WIN:
os.environ['PYTHONHOME'] = sys.prefix
# Initialize Flask service only once
# If `WERKZEUG_RUN_MAIN` is None, i.e: app is initializing for first time
# so set `use_reloader` = False, thus reload won't call.
# Reference:
# https://github.com/pallets/werkzeug/issues/220#issuecomment-11176538
try:
app.run(
host=config.DEFAULT_SERVER,
port=server_port,
use_reloader=((not PGADMIN_RUNTIME) and app.debug),
use_reloader=(
(not PGADMIN_RUNTIME) and app.debug
and os.environ.get("WERKZEUG_RUN_MAIN") is not None
),
threaded=config.THREADED_MODE
)
except IOError:
+28
View File
@@ -1,3 +1,12 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2017, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import os
import sys
@@ -5,4 +14,23 @@ root = os.path.dirname(os.path.realpath(__file__))
if sys.path[0] != root:
sys.path.insert(0, root)
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = True
import config
# When running it as a WSGI application, directory for the configuration file
# must present.
if not os.path.exists(os.path.dirname(config.SQLITE_PATH)):
raise Exception(
"""
Required configuration file is not present!
Please run setup.py first!"""
)
from pgAdmin4 import app as application
+86 -34
View File
@@ -10,18 +10,19 @@
"""The main pgAdmin module. This handles the application initialisation tasks,
such as setup of logging, dynamic loading of modules etc."""
import logging
import os, sys, time
import os, sys
from collections import defaultdict
from importlib import import_module
from flask import Flask, abort, request, current_app, session
from flask import Flask, abort, request, current_app, session, url_for
from flask_babel import Babel, gettext
from flask_htmlmin import HTMLMIN
from flask_login import user_logged_in
from flask_login import user_logged_in, user_logged_out
from flask_security import Security, SQLAlchemyUserDatastore
from flask_mail import Mail
from flask_security.utils import login_user
from werkzeug.datastructures import ImmutableDict
from flask_paranoid import Paranoid
from pgadmin.utils import PgAdminModule, driver
from pgadmin.utils.versioned_template_loader import VersionedTemplateLoader
@@ -31,7 +32,9 @@ from werkzeug.utils import find_modules
from pgadmin.utils.preferences import Preferences
from pgadmin.model import db, Role, Server, ServerGroup, User, Version, Keys
from pgadmin.model import db, Role, Server, ServerGroup, \
User, Keys, Version, SCHEMA_VERSION as CURRENT_SCHEMA_VERSION
# If script is running under python3, it will not have the xrange function
# defined
@@ -86,6 +89,42 @@ class PgAdmin(Flask):
messages.update(getattr(module, "messages", dict()))
return messages
@property
def exposed_endpoint_url_map(self):
#############################################################
# To handle WSGI paths
# If user has setup application under WSGI alias
# like 'localhost/pgadmin4' then we have to append '/pgadmin4'
# into endpoints
#############################################################
import config
is_wsgi_root_present = False
if config.SERVER_MODE:
pgadmin_root_path = url_for('browser.index')
if pgadmin_root_path != '/browser/':
is_wsgi_root_present = True
wsgi_root_path = pgadmin_root_path.replace(
'/browser/', ''
)
def get_full_url_path(url):
"""
Generate endpoint URL at per WSGI alias
"""
if is_wsgi_root_present and url:
return wsgi_root_path + url
else:
return url
# Fetch all endpoints and their respective url
for rule in current_app.url_map.iter_rules('static'):
yield rule.endpoint, get_full_url_path(rule.rule)
for module in self.submodules:
for endpoint in module.exposed_endpoints:
for rule in current_app.url_map.iter_rules(endpoint):
yield rule.endpoint, get_full_url_path(rule.rule)
@property
def javascripts(self):
scripts = []
@@ -160,6 +199,15 @@ def create_app(app_name=None):
logger = logging.getLogger('werkzeug')
logger.setLevel(logging.INFO)
# Set SQLITE_PATH to TEST_SQLITE_PATH while running test cases
if "PGADMIN_TESTING_MODE" in os. environ and \
os.environ["PGADMIN_TESTING_MODE"] == "1":
config.SQLITE_PATH = config.TEST_SQLITE_PATH
# Ensure the various working directories exist
from pgadmin.setup import create_app_data_directory, db_upgrade
create_app_data_directory(config)
# File logging
fh = logging.FileHandler(config.LOG_FILE, encoding='utf-8')
fh.setLevel(config.FILE_LOG_LEVEL)
@@ -233,6 +281,30 @@ def create_app(app_name=None):
# Create database connection object and mailer
db.init_app(app)
##########################################################################
# Upgrade the schema (if required)
##########################################################################
with app.app_context():
# Run migration for the first time i.e. create database
from config import SQLITE_PATH
if not os.path.exists(SQLITE_PATH):
db_upgrade(app)
else:
version = Version.query.filter_by(name='ConfigDB').first()
schema_version = version.value
# Run migration if current schema version is greater than the
# schema version stored in version table
if CURRENT_SCHEMA_VERSION >= schema_version:
db_upgrade(app)
# Update schema version to the latest
if CURRENT_SCHEMA_VERSION > schema_version:
version = Version.query.filter_by(name='ConfigDB').first()
version.value = CURRENT_SCHEMA_VERSION
db.session.commit()
Mail(app)
import pgadmin.utils.paths as paths
@@ -242,33 +314,6 @@ def create_app(app_name=None):
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(None, user_datastore)
# Upgrade the schema (if required)
with app.app_context():
try:
version = Version.query.filter_by(name='ConfigDB').first()
except:
backup_file = config.SQLITE_PATH + '.' + time.strftime("%Y%m%d%H%M%S")
app.logger.error(
"""The configuration database ({0}) appears to be corrupt.\n\n"""
"""The database will be moved to {1}.\n"""
"""Please restart {2} to create a new configuration database.\n""".format(
config.SQLITE_PATH, backup_file, config.APP_NAME
)
)
os.rename(config.SQLITE_PATH, backup_file)
exit(1)
# Pre-flight checks
if int(version.value) < int(config.SETTINGS_SCHEMA_VERSION):
app.logger.info(
"""Upgrading the database schema from version {0} to {1}.""".format(
version.value, config.SETTINGS_SCHEMA_VERSION
)
)
from setup import do_upgrade
do_upgrade(app, user_datastore, version)
##########################################################################
# Setup security
##########################################################################
@@ -283,10 +328,15 @@ def create_app(app_name=None):
app.config.update(dict(SECRET_KEY=config.SECRET_KEY))
app.config.update(dict(SECURITY_PASSWORD_SALT=config.SECURITY_PASSWORD_SALT))
security.init_app(app)
security.init_app(app, user_datastore)
app.session_interface = create_session_interface(app)
# Make the Session more secure against XSS & CSRF when running in web mode
if config.SERVER_MODE:
paranoid = Paranoid(app)
paranoid.redirect_view = 'browser.index'
##########################################################################
# Load all available server drivers
##########################################################################
@@ -318,7 +368,6 @@ def create_app(app_name=None):
##########################################################################
@user_logged_in.connect_via(app)
def on_user_logged_in(sender, user):
# Keep hold of the user ID
user_id = user.id
@@ -447,6 +496,10 @@ def create_app(app_name=None):
except:
pass
@user_logged_in.connect_via(app)
@user_logged_out.connect_via(app)
def force_session_write(app, user):
session.force_write = True
##########################################################################
# Load plugin modules
@@ -513,6 +566,5 @@ def create_app(app_name=None):
##########################################################################
# All done!
##########################################################################
app.logger.debug('URL map: %s' % app.url_map)
return app
+3 -1
View File
@@ -47,6 +47,8 @@ class AboutModule(PgAdminModule):
'when': None
}]
def get_exposed_url_endpoints(self):
return ['about.index']
blueprint = AboutModule(MODULE_NAME, __name__,
static_url_path='')
@@ -55,7 +57,7 @@ blueprint = AboutModule(MODULE_NAME, __name__,
##########################################################################
# A test page
##########################################################################
@blueprint.route("/")
@blueprint.route("/", endpoint='index')
@login_required
def index():
"""Render the about box."""
@@ -1,6 +1,8 @@
define(
['jquery', 'alertify', 'pgadmin', 'sources/gettext'],
function($, alertify, pgAdmin, gettext) {
['jquery', 'alertify', 'sources/pgadmin', 'underscore.string', 'sources/gettext',
'sources/url_for'
],
function($, alertify, pgAdmin, S, gettext, url_for) {
pgAdmin = pgAdmin || window.pgAdmin || {};
/* Return back, this has been called more than once */
@@ -39,9 +41,11 @@ define(
}
var content = '';
$.get("{{ url_for('about.index') }}",
$.get(url_for('about.index'),
function(data) {
alertify.aboutDialog(gettext("About %(appname)s", {appname: "{{ config.APP_NAME }}"}), data).resizeTo(800, 450);
alertify.aboutDialog(
S(gettext("About %s")).sprintf(pgAdmin.Browser.utils.app_name).value(), data
).resizeTo(800, 450);
});
}
};
+5 -5
View File
@@ -1,4 +1,4 @@
<div class="enable-selection">
<div class="container-fluid enable-selection">
<div class="row">
<div class="col-sm-3"><b>{{ _('Version') }}</b></div>
<div class="col-sm-9">{{ config.APP_VERSION }}</div>
@@ -23,9 +23,9 @@
<div class="col-sm-3"><b>{{ _('Current User') }}</b></div>
<div class="col-sm-9">{{ info.current_user }}</div>
</div>
</div>
<div class="row">
<div class="col-sm-3 pull-right"><img
<div class="row">
<div class="col-xs-12 text-right"><img
src="{{ url_for('static', filename='img/logo-right-128.png') }}"
alt="{{ config.APP_NAME }}"></div>
</div>
</div>
</div>
+57 -12
View File
@@ -12,7 +12,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty
import six
from flask import current_app, render_template, url_for, make_response, flash,\
Response, request
Response
from flask_babel import gettext
from flask_login import current_user
from flask_security import login_required
@@ -152,6 +152,7 @@ class BrowserModule(PgAdminModule):
for name, script in [
['pgadmin.browser', 'js/browser'],
['pgadmin.browser.endpoints', 'js/endpoints'],
['pgadmin.browser.error', 'js/error']]:
scripts.append({
'name': name,
@@ -181,7 +182,7 @@ class BrowserModule(PgAdminModule):
scripts.append({
'name': 'pgadmin.browser.node.ui',
'path': url_for('browser.static', filename='js/node.ui'),
'when': 'server-group'
'when': 'server_group'
})
for module in self.submodules:
@@ -195,6 +196,13 @@ class BrowserModule(PgAdminModule):
category_label=gettext('Display')
)
def get_exposed_url_endpoints(self):
"""
Returns:
list: a list of url endpoints exposed to the client.
"""
return ['browser.index', 'browser.nodes']
blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -251,6 +259,14 @@ class BrowserPluginModule(PgAdminModule):
"""
return []
@property
def module_use_template_javascript(self):
"""
Returns whether Jinja2 template is used for generating the javascript
module.
"""
return False
def get_own_javascripts(self):
"""
Returns the list of javascripts information used by the module.
@@ -272,14 +288,26 @@ class BrowserPluginModule(PgAdminModule):
"""
scripts = []
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load
}])
if self.module_use_template_javascript:
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load,
'is_template': True
}])
else:
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for(
'%s.static'% self.name, filename=('js/%s' % self.node_type)
),
'when': self.script_load,
'is_template': False
}])
for module in self.submodules:
scripts.extend(module.get_own_javascripts())
return scripts
def generate_browser_node(
@@ -495,9 +523,9 @@ def index():
return response
@blueprint.route("/js/browser.js")
@blueprint.route("/js/utils.js")
@login_required
def browser_js():
def utils():
layout = get_setting('Browser/Layout', default='')
snippets = []
@@ -521,11 +549,17 @@ def browser_js():
editor_wrap_code_pref = prefs.preference('wrap_code')
editor_wrap_code = editor_wrap_code_pref.get()
brace_matching_pref = prefs.preference('brace_matching')
brace_matching = brace_matching_pref.get()
insert_pair_brackets_perf = prefs.preference('insert_pair_brackets')
insert_pair_brackets = insert_pair_brackets_perf.get()
for submodule in current_blueprint.submodules:
snippets.extend(submodule.jssnippets)
return make_response(
render_template(
'browser/js/browser.js',
'browser/js/utils.js',
layout=layout,
jssnippets=snippets,
pg_help_path=pg_help_path,
@@ -533,11 +567,21 @@ def browser_js():
editor_tab_size=editor_tab_size,
editor_use_spaces=editor_use_spaces,
editor_wrap_code=editor_wrap_code,
_=gettext
editor_brace_matching=brace_matching,
editor_insert_pair_brackets=insert_pair_brackets,
app_name=config.APP_NAME
),
200, {'Content-Type': 'application/x-javascript'})
@blueprint.route("/js/endpoints.js")
def exposed_urls():
return make_response(
render_template('browser/js/endpoints.js'),
200, {'Content-Type': 'application/x-javascript'}
)
@blueprint.route("/js/error.js")
@login_required
def error_js():
@@ -605,11 +649,12 @@ def browser_css():
200, {'Content-Type': 'text/css'})
@blueprint.route("/nodes/")
@blueprint.route("/nodes/", endpoint="nodes")
@login_required
def get_nodes():
"""Build a list of treeview nodes from the child nodes."""
nodes = []
for submodule in current_blueprint.submodules:
nodes.extend(submodule.get_nodes())
return make_json_response(data=nodes)
+25 -5
View File
@@ -45,14 +45,34 @@ class CollectionNodeModule(PgAdminModule, PGChildModule):
"""
return []
@property
def module_use_template_javascript(self):
"""
Returns whether Jinja2 template is used for generating the javascript
module.
"""
return True
def get_own_javascripts(self):
scripts = []
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load
}])
if self.module_use_template_javascript:
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load,
'is_template': True
}])
else:
scripts.extend([{
'name': 'pgadmin.node.%s' % self.node_type,
'path': url_for(
'%s.static'% self.name, filename=('js/%s' % self.node_type)
),
'when': self.script_load,
'is_template': False
}])
for module in self.submodules:
scripts.extend(module.get_own_javascripts())
+19 -29
View File
@@ -13,20 +13,20 @@ import simplejson as json
from abc import ABCMeta, abstractmethod
import six
from flask import request, render_template, make_response, jsonify
from flask import request, render_template, make_response, jsonify, current_app
from flask_babel import gettext
from flask_security import current_user
from pgadmin.browser import BrowserPluginModule
from pgadmin.browser.utils import NodeView
from pgadmin.utils.ajax import make_json_response, gone, \
make_response as ajax_response
make_response as ajax_response, bad_request
from pgadmin.utils.menu import MenuItem
from sqlalchemy import exc
from pgadmin.model import db, ServerGroup
class ServerGroupModule(BrowserPluginModule):
NODE_TYPE = "server-group"
NODE_TYPE = "server_group"
def get_nodes(self, *arg, **kwargs):
"""Return a JSON document listing the server groups for the user"""
@@ -87,7 +87,7 @@ class ServerGroupPluginModule(BrowserPluginModule):
pass
blueprint = ServerGroupModule(__name__, static_url_path='')
blueprint = ServerGroupModule(__name__)
class ServerGroupView(NodeView):
@@ -174,6 +174,10 @@ class ServerGroupView(NodeView):
if u'name' in data:
servergroup.name = data[u'name']
db.session.commit()
except exc.IntegrityError:
return bad_request(gettext(
"The specified server group already exists."
))
except Exception as e:
return make_json_response(
status=410, success=0, errormsg=e.message
@@ -220,18 +224,6 @@ class ServerGroupView(NodeView):
)
if data[u'name'] != '':
try:
check_sg = ServerGroup.query.filter_by(
user_id=current_user.id,
name=data[u'name']).first()
# Throw error if server group already exists...
if check_sg is not None:
return make_json_response(
status=409,
success=0,
errormsg=gettext('Server group already exists')
)
sg = ServerGroup(
user_id=current_user.id,
name=data[u'name'])
@@ -248,9 +240,15 @@ class ServerGroupView(NodeView):
"icon-%s" % self.node_type,
True,
self.node_type,
can_delete=True # This is user created hence can deleted
# This is user created hence can deleted
can_delete=True
)
)
except exc.IntegrityError:
return bad_request(gettext(
"The specified server group already exists."
))
except Exception as e:
return make_json_response(
status=410,
@@ -278,16 +276,6 @@ class ServerGroupView(NodeView):
def dependents(self, gid):
return make_json_response(status=422)
def module_js(self, **kwargs):
"""
This property defines (if javascript) exists for this node.
Override this property for your own logic.
"""
return make_response(
render_template("server_groups/server_groups.js"),
200, {'Content-Type': 'application/x-javascript'}
)
def nodes(self, gid=None):
"""Return a JSON document listing the server groups for the user"""
nodes = []
@@ -309,7 +297,9 @@ class ServerGroupView(NodeView):
group = ServerGroup.query.filter_by(user_id=current_user.id,
id=gid).first()
if not group:
return gone(errormsg="Could not find the server group.")
return gone(
errormsg=gettext("Could not find the server group.")
)
nodes = self.blueprint.generate_browser_node(
"%d" % (group.id), None,
@@ -8,7 +8,7 @@
##########################################################################
import simplejson as json
import re
import pgadmin.browser.server_groups as sg
from flask import render_template, request, make_response, jsonify, \
current_app, url_for
@@ -25,7 +25,7 @@ import config
from config import PG_DEFAULT_DRIVER
from pgadmin.model import db, Server, ServerGroup, User
from pgadmin.utils.driver import get_driver
from pgadmin.utils import get_storage_directory
def has_any(data, keys):
"""
@@ -48,7 +48,7 @@ def recovery_state(connection, postgres_version):
recovery_check_sql = render_template("connect/sql/#{0}#/check_recovery.sql".format(postgres_version))
status, result = connection.execute_dict(recovery_check_sql)
if status:
if status and 'rows' in result and len(result['rows']) > 0:
in_recovery = result['rows'][0]['inrecovery']
wal_paused = result['rows'][0]['isreplaypaused']
else:
@@ -128,24 +128,23 @@ class ServerModule(sg.ServerGroupPluginModule):
scripts = []
scripts.extend([{
'name': 'pgadmin.node.server',
'path': url_for('browser.index') + '%s/module' % self.node_type,
'when': self.script_load
},
{
'name': 'pgadmin.browser.server.privilege',
'path': url_for('browser.index') + 'server/static/js/privilege',
'when': self.node_type,
'deps': ['pgadmin.browser.node.ui']
},
{
'name': 'pgadmin.browser.server.variable',
'path': url_for('browser.index') + 'server/static/js/variable',
'when': self.node_type
}])
for module in self.submodules:
scripts.extend(module.get_own_javascripts())
'name': 'pgadmin.browser.server.privilege',
'path': url_for('%s.static'% self.name, filename='js/privilege'),
'when': self.node_type,
'is_template': False,
'deps': ['pgadmin.browser.node.ui']
}, {
'name': 'pgadmin.browser.server.variable',
'path': url_for('%s.static'% self.name, filename='js/variable'),
'when': self.node_type,
'is_template': False
},{
'name': 'pgadmin.server.supported_servers',
'path': url_for('browser.index') + 'server/supported_servers',
'is_template': True,
'when': self.node_type
}])
scripts.extend(sg.ServerGroupPluginModule.get_own_javascripts(self))
return scripts
@@ -199,7 +198,7 @@ class ServerNode(PGChildNodeView):
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'children': [{'get': 'children'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'supported_servers.js': [{}, {}, {'get': 'supported_servers'}],
'reload':
[{'get': 'reload_configuration'}],
'restore_point':
@@ -212,6 +211,70 @@ class ServerNode(PGChildNodeView):
'delete': 'pause_wal_replay', 'put': 'resume_wal_replay'
}]
})
EXP_IP4 = "^\s*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."\
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."\
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."\
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\s*$"
EXP_IP6 = '^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|'\
'(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|'\
'2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|'\
'(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|'\
':((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|'\
'(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|'\
'2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|'\
'(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|'\
'[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|'\
'((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|'\
'(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|'\
'1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|'\
'((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$'
pat4 = re.compile(EXP_IP4)
pat6 = re.compile(EXP_IP6)
SSL_MODES = ['prefer','require', 'verify-ca', 'verify-full']
def check_ssl_fields(self, data):
"""
This function will allow us to check and set defaults for
SSL fields
Args:
data: Response data
Returns:
Flag and Data
"""
flag = False
if 'sslmode' in data and data['sslmode'] in self.SSL_MODES:
flag = True
ssl_fields = [
'sslcert', 'sslkey', 'sslrootcert', 'sslcrl', 'sslcompression'
]
# Required SSL fields for SERVER mode from user
required_ssl_fields_server_mode = ['sslcert', 'sslkey']
for field in ssl_fields:
if field not in data:
# In Server mode,
# we will set dummy SSL certificate file path which will
# prevent using default SSL certificates from web servers
if config.SERVER_MODE and \
field in required_ssl_fields_server_mode:
# Set file manager directory from preference
import os
storage_dir = get_storage_directory()
file_extn = '.key' if field.endswith('key') else '.crt'
dummy_ssl_file = os.path.join(
storage_dir, '.postgresql',
'postgresql' + file_extn
)
data[field] = dummy_ssl_file
# For Desktop mode, we will allow to default
else:
data[field] = None
return flag, data
def nodes(self, gid):
res = []
@@ -354,13 +417,21 @@ class ServerNode(PGChildNodeView):
config_param_map = {
'name': 'name',
'host': 'host',
'hostaddr': 'hostaddr',
'port': 'port',
'db': 'maintenance_db',
'username': 'username',
'sslmode': 'ssl_mode',
'gid': 'servergroup_id',
'comment': 'comment',
'role': 'role'
'role': 'role',
'db_res': 'db_res',
'passfile': 'passfile',
'sslcert': 'sslcert',
'sslkey': 'sslkey',
'sslrootcert': 'sslrootcert',
'sslcrl': 'sslcrl',
'sslcompression': 'sslcompression'
}
disp_lbl = {
@@ -378,6 +449,17 @@ class ServerNode(PGChildNodeView):
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
if 'db_res' in data:
data['db_res'] = ','.join(data['db_res'])
if 'hostaddr' in data and data['hostaddr'] != '':
if not self.pat4.match(data['hostaddr']):
if not self.pat6.match(data['hostaddr']):
return make_json_response(
success=0,
status=400,
errormsg=gettext('Host address not valid')
)
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
conn = manager.connection()
@@ -385,7 +467,7 @@ class ServerNode(PGChildNodeView):
if connected:
for arg in (
'host', 'port', 'db', 'username', 'sslmode', 'role'
'host', 'hostaddr', 'port', 'db', 'username', 'sslmode', 'role'
):
if arg in data:
return forbidden(
@@ -396,7 +478,12 @@ class ServerNode(PGChildNodeView):
for arg in config_param_map:
if arg in data:
setattr(server, config_param_map[arg], data[arg])
value = data[arg]
# sqlite3 do not have boolean type so we need to convert
# it manually to integer
if arg == 'sslcompression':
value = 1 if value else 0
setattr(server, config_param_map[arg], value)
idx += 1
if idx == 0:
@@ -466,7 +553,8 @@ class ServerNode(PGChildNodeView):
'role': server.role,
'connected': connected,
'version': manager.ver,
'server_type': manager.server_type if connected else 'pg'
'server_type': manager.server_type if connected else 'pg',
'db_res': server.db_res.split(',') if server.db_res else None
})
return ajax_response(
@@ -497,11 +585,14 @@ class ServerNode(PGChildNodeView):
conn = manager.connection()
connected = conn.connected()
is_ssl = True if server.ssl_mode in self.SSL_MODES else False
return ajax_response(
response={
'id': server.id,
'name': server.name,
'host': server.host,
'hostaddr': server.hostaddr,
'port': server.port,
'db': server.maintenance_db,
'username': server.username,
@@ -512,7 +603,15 @@ class ServerNode(PGChildNodeView):
'connected': connected,
'version': manager.ver,
'sslmode': server.ssl_mode,
'server_type': manager.server_type if connected else 'pg'
'server_type': manager.server_type if connected else 'pg',
'db_res': server.db_res.split(',') if server.db_res else None,
'passfile': server.passfile if server.passfile else None,
'sslcert': server.sslcert if is_ssl else None,
'sslkey': server.sslkey if is_ssl else None,
'sslrootcert': server.sslrootcert if is_ssl else None,
'sslcrl': server.sslcrl if is_ssl else None,
'sslcompression': True if is_ssl and server.sslcompression
else False
}
)
@@ -542,6 +641,18 @@ class ServerNode(PGChildNodeView):
)
)
if 'hostaddr' in data and data['hostaddr'] != '':
if not self.pat4.match(data['hostaddr']):
if not self.pat6.match(data['hostaddr']):
return make_json_response(
success=0,
status=400,
errormsg=gettext('Host address not valid')
)
# To check ssl configuration
is_ssl, data = self.check_ssl_fields(data)
server = None
try:
@@ -550,18 +661,24 @@ class ServerNode(PGChildNodeView):
servergroup_id=data[u'gid'] if u'gid' in data else gid,
name=data[u'name'],
host=data[u'host'],
hostaddr=data[u'hostaddr'] if u'hostaddr' in data else None,
port=data[u'port'],
maintenance_db=data[u'db'],
username=data[u'username'],
ssl_mode=data[u'sslmode'],
comment=data[u'comment'] if u'comment' in data else None,
role=data[u'role'] if u'role' in data else None
role=data[u'role'] if u'role' in data else None,
db_res=','.join(data[u'db_res']) if u'db_res' in data else None,
sslcert=data['sslcert'] if is_ssl else None,
sslkey=data['sslkey'] if is_ssl else None,
sslrootcert=data['sslrootcert'] if is_ssl else None,
sslcrl=data['sslcrl'] if is_ssl else None,
sslcompression=1 if is_ssl and data['sslcompression'] else 0
)
db.session.add(server)
db.session.commit()
connected = False
icon = "icon-server-not-connected"
user = None
manager = None
@@ -574,14 +691,21 @@ class ServerNode(PGChildNodeView):
if 'password' in data and data["password"] != '':
# login with password
have_password = True
passfile = None
password = data['password']
password = encrypt(password, current_user.password)
elif 'passfile' in data and data["passfile"] != '':
passfile = data['passfile']
setattr(server, 'passfile', passfile)
db.session.commit()
else:
# Attempt password less login
password = None
passfile = None
status, errmsg = conn.connect(
password=password,
passfile=passfile,
server_types=ServerType.types()
)
if hasattr(str, 'decode') and errmsg is not None:
@@ -663,21 +787,16 @@ class ServerNode(PGChildNodeView):
def dependents(self, gid, sid):
return make_json_response(data='')
def module_js(self, **kwargs):
def supported_servers(self, **kwargs):
"""
This property defines (if javascript) exists for this node.
Override this property for your own logic.
"""
username = 'postgres'
if config.SERVER_MODE is True:
username = current_user.email.split('@')[0]
return make_response(
render_template(
"servers/servers.js",
server_types=ServerType.types(),
_=gettext,
username=username,
"servers/supported_servers.js",
server_types=ServerType.types()
),
200, {'Content-Type': 'application/x-javascript'}
)
@@ -732,6 +851,7 @@ class ServerNode(PGChildNodeView):
) if request.data else {}
password = None
passfile = None
save_password = False
# Connect the Server
@@ -740,7 +860,8 @@ class ServerNode(PGChildNodeView):
if 'password' not in data:
conn_passwd = getattr(conn, 'password', None)
if conn_passwd is None and server.password is None:
if conn_passwd is None and server.password is None and \
server.passfile is None:
# Return the password template in case password is not
# provided, or password has not been saved earlier.
return make_json_response(
@@ -753,6 +874,10 @@ class ServerNode(PGChildNodeView):
_=gettext
)
)
elif server.passfile and server.passfile != '':
passfile = server.passfile
else:
password = conn_passwd or server.password
else:
password = data['password'] if 'password' in data else None
save_password = \
@@ -771,6 +896,7 @@ class ServerNode(PGChildNodeView):
try:
status, errmsg = conn.connect(
password=password,
passfile=passfile,
server_types=ServerType.types()
)
except Exception as e:
@@ -1052,17 +1178,21 @@ class ServerNode(PGChildNodeView):
# Execute SQL to pause or resume WAL replay
if conn.connected():
if pause:
status, res = conn.execute_scalar(
"SELECT pg_xlog_replay_pause();"
)
sql = "SELECT pg_xlog_replay_pause();"
if manager.version >= 100000:
sql = "SELECT pg_wal_replay_pause();"
status, res = conn.execute_scalar(sql)
if not status:
return internal_server_error(
errormsg=str(res)
)
else:
status, res = conn.execute_scalar(
"SELECT pg_xlog_replay_resume();"
)
sql = "SELECT pg_xlog_replay_resume();"
if manager.version >= 100000:
sql = "SELECT pg_wal_replay_resume();"
status, res = conn.execute_scalar(sql)
if not status:
return internal_server_error(
errormsg=str(res)
@@ -14,7 +14,7 @@ import re
from functools import wraps
import pgadmin.browser.server_groups.servers as servers
from flask import render_template, make_response, current_app, request, jsonify
from flask import render_template, current_app, request, jsonify
from flask_babel import gettext as _
from pgadmin.browser.collection import CollectionNodeModule
from pgadmin.browser.server_groups.servers.databases.utils import \
@@ -78,6 +78,13 @@ class DatabaseModule(CollectionNodeModule):
return snippets
@property
def module_use_template_javascript(self):
"""
Returns whether Jinja2 template is used for generating the javascript
module.
"""
return False
blueprint = DatabaseModule(__name__)
@@ -106,7 +113,6 @@ class DatabaseView(PGChildNodeView):
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'children': [{'get': 'children'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'connect': [{
'get': 'connect_status', 'post': 'connect', 'delete': 'disconnect'
}],
@@ -137,8 +143,8 @@ class DatabaseView(PGChildNodeView):
self.db_allow_connection = True
# If connection to database is not allowed then
# provide generic connection
if kwargs['did'] in self.conn.manager.db_info:
self._db = self.conn.manager.db_info[kwargs['did']]
if kwargs['did'] in self.manager.db_info:
self._db = self.manager.db_info[kwargs['did']]
if self._db['datallowconn'] is False:
self.conn = self.manager.connection()
self.db_allow_connection = False
@@ -160,11 +166,18 @@ class DatabaseView(PGChildNodeView):
(self.manager.db_info[self.manager.did])['datlastsysoid'] \
if self.manager.db_info is not None and \
self.manager.did in self.manager.db_info else 0
db_disp_res = None
params = None
if self.manager and self.manager.db_res:
db_disp_res = ", ".join(['%s'] * len(self.manager.db_res.split(',')))
params = tuple(self.manager.db_res.split(','))
SQL = render_template(
"/".join([self.template_path, 'properties.sql']),
conn=self.conn, last_system_oid=last_system_oid
conn=self.conn, last_system_oid=last_system_oid, db_restrictions=db_disp_res
)
status, res = self.conn.execute_dict(SQL)
status, res = self.conn.execute_dict(SQL, params)
if not status:
return internal_server_error(errormsg=res)
@@ -182,12 +195,19 @@ class DatabaseView(PGChildNodeView):
if self.manager.db_info is not None and \
self.manager.did in self.manager.db_info else 0
)
server_node_res = self.manager
db_disp_res = None
params = None
if server_node_res and server_node_res.db_res:
db_disp_res = ", ".join(['%s']*len(server_node_res.db_res.split(',')))
params = tuple(server_node_res.db_res.split(','))
SQL = render_template(
"/".join([self.template_path, 'nodes.sql']),
last_system_oid=last_system_oid
last_system_oid=last_system_oid,
db_restrictions=db_disp_res
)
status, rset = self.conn.execute_dict(SQL)
status, rset = self.conn.execute_dict(SQL, params)
if not status:
return internal_server_error(errormsg=rset)
@@ -275,27 +295,26 @@ class DatabaseView(PGChildNodeView):
@check_precondition(action="properties")
def properties(self, gid, sid, did):
conn = self.manager.connection()
SQL = render_template(
"/".join([self.template_path, 'properties.sql']),
did=did, conn=conn, last_system_oid=0
did=did, conn=self.conn, last_system_oid=0
)
status, res = conn.execute_dict(SQL)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
_("Could not find the database on the server.")
)
if not status:
return internal_server_error(errormsg=res)
SQL = render_template(
"/".join([self.template_path, 'acl.sql']),
did=did, conn=conn
did=did, conn=self.conn
)
status, dataclres = conn.execute_dict(SQL)
status, dataclres = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
@@ -303,9 +322,9 @@ class DatabaseView(PGChildNodeView):
SQL = render_template(
"/".join([self.template_path, 'defacl.sql']),
did=did, conn=conn
did=did, conn=self.conn
)
status, defaclres = conn.execute_dict(SQL)
status, defaclres = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
@@ -315,10 +334,10 @@ class DatabaseView(PGChildNodeView):
# Fetching variable for database
SQL = render_template(
"/".join([self.template_path, 'get_variables.sql']),
did=did, conn=conn
did=did, conn=self.conn
)
status, res1 = conn.execute_dict(SQL)
status, res1 = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res1)
@@ -345,19 +364,6 @@ class DatabaseView(PGChildNodeView):
res['rows'][0].setdefault(row['deftype'], []).append(priv)
return res
def module_js(self):
"""
This property defines (if javascript) exists for this node.
Override this property for your own logic.
"""
return make_response(
render_template(
"databases/js/databases.js",
_=_
),
200, {'Content-Type': 'application/x-javascript'}
)
def connect(self, gid, sid, did):
"""Connect the Database."""
from pgadmin.utils.driver import get_driver
@@ -605,17 +611,44 @@ class DatabaseView(PGChildNodeView):
# used for offline updates
self.manager.release(conn_id="db_offline_update")
# Fetch the new data again after update for proper node
# generation
status, rset = self.conn.execute_dict(
render_template(
"/".join([self.template_path, 'nodes.sql']),
did=did, conn=self.conn, last_system_oid=0
)
)
if not status:
return internal_server_error(errormsg=rset)
if len(rset['rows']) == 0:
return gone(
_("Could not find the database on the server.")
)
res = rset['rows'][0]
canDrop = canDisConn = True
if self.manager.db == res['name']:
canDrop = canDisConn = False
return jsonify(
node=self.blueprint.generate_browser_node(
did,
sid,
data['name'],
"pg-icon-{0}".format(self.node_type) if
self._db['datallowconn'] else
res['name'],
icon="pg-icon-{0}".format(self.node_type) if
self._db['datallowconn'] and self.conn.connected() else
"icon-database-not-connected",
connected=self.conn.connected() if
self._db['datallowconn'] else False,
allowConn=self._db['datallowconn']
tablespace=res['spcname'],
allowConn=res['datallowconn'],
canCreate=res['cancreate'],
canDisconn=canDisConn,
canDrop=canDrop,
inode=True if res['datallowconn'] else False
)
)
@@ -831,12 +864,17 @@ class DatabaseView(PGChildNodeView):
if self.manager.db_info is not None and \
self.manager.did in self.manager.db_info else 0
db_disp_res = None
params = None
if self.manager and self.manager.db_res:
db_disp_res = ", ".join(['%s'] * len(self.manager.db_res.split(',')))
params = tuple(self.manager.db_res.split(','))
conn = self.manager.connection()
status, res = conn.execute_dict(
render_template(
"/".join([self.template_path, 'stats.sql']),
did=did, conn=conn, last_system_oid=last_system_oid
)
status, res = conn.execute_dict(render_template(
"/".join([self.template_path, 'stats.sql']),
did=did, conn=conn, last_system_oid=last_system_oid, db_restrictions=db_disp_res
),params
)
if not status:
@@ -859,9 +897,15 @@ class DatabaseView(PGChildNodeView):
did=did, conn=conn, last_system_oid=0
)
status, res = conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
_("Could not find the database on the server.")
)
SQL = render_template(
"/".join([self.template_path, 'acl.sql']),
did=did, conn=self.conn
@@ -13,16 +13,18 @@ import simplejson as json
from functools import wraps
import pgadmin.browser.server_groups.servers.databases as databases
from flask import render_template, make_response, request, jsonify
from flask import render_template, request, jsonify
from flask_babel import gettext
from pgadmin.browser.collection import CollectionNodeModule
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class CastModule(CollectionNodeModule):
"""
@@ -51,6 +53,7 @@ class CastModule(CollectionNodeModule):
def __init__(self, *args, **kwargs):
super(CastModule, self).__init__(*args, **kwargs)
self.min_gpdbver = 1000000000
def get_nodes(self, gid, sid, did):
"""
@@ -76,6 +79,14 @@ class CastModule(CollectionNodeModule):
"""
return databases.DatabaseModule.NODE_TYPE
@property
def module_use_template_javascript(self):
"""
Returns whether Jinja2 template is used for generating the javascript
module.
"""
return False
blueprint = CastModule(__name__)
@@ -93,10 +104,6 @@ class CastView(PGChildNodeView):
* __init__(**kwargs)
- Method is used to initialize the CastView and it's base view.
* module_js()
- This property defines (if javascript) exists for this node.
Override this property for your own logic
* check_precondition()
- This function will behave as a decorator which will checks
database connection before running view, it will also attaches
@@ -164,7 +171,6 @@ class CastView(PGChildNodeView):
'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'get_type': [{'get': 'get_src_and_trg_type'}, {'get': 'get_src_and_trg_type'}],
'get_functions': [{'post': 'get_functions'}, {'post': 'get_functions'}]
})
@@ -175,18 +181,6 @@ class CastView(PGChildNodeView):
self.manager = None
super(CastView, self).__init__(**kwargs)
def module_js(self):
"""
This property defines whether javascript exists for this node.
"""
return make_response(
render_template(
"cast/js/casts.js",
_=gettext
),
200, {'Content-Type': 'application/x-javascript'}
)
def check_precondition(f):
"""
This function will behave as a decorator which will check the
@@ -413,6 +407,9 @@ class CastView(PGChildNodeView):
)
try:
sql, name = self.get_sql(gid, sid, did, data, cid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
return sql
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
@@ -503,6 +500,9 @@ class CastView(PGChildNodeView):
"""
data = request.args
sql, name = self.get_sql(gid, sid, did, data, cid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
return sql
sql = sql.strip('\n').strip(' ')
if sql == '':
sql = "--modified SQL"
@@ -536,6 +536,11 @@ class CastView(PGChildNodeView):
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
_("Could not find the specified cast on the server.")
)
old_data = res['rows'][0]
sql = render_template(
"/".join([self.template_path, 'update.sql']),
Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#def4fd;}.cls-2{fill:#354a5f;}.cls-3{fill:#2880b9;}.cls-4,.cls-6{fill:#2980b9;}.cls-4,.cls-5{stroke:#2980b9;}.cls-4,.cls-5,.cls-6,.cls-7{stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75px;}.cls-5,.cls-7{fill:none;}.cls-6,.cls-7{stroke:#354a5f;}</style></defs><title>cast</title><g id="_3" data-name="3"><rect class="cls-1" x="8.99" y="2.39" width="4.65" height="4.65" rx="0.63" ry="0.63"/><path class="cls-2" d="M13,2.77a.25.25,0,0,1,.25.25v3.4a.25.25,0,0,1-.25.25H9.62a.25.25,0,0,1-.25-.25V3a.25.25,0,0,1,.25-.25H13M13,2H9.62a1,1,0,0,0-1,1v3.4a1,1,0,0,0,1,1H13a1,1,0,0,0,1-1V3a1,1,0,0,0-1-1Z"/><rect class="cls-1" x="2.36" y="8.96" width="4.65" height="4.65" rx="0.63" ry="0.63"/><path class="cls-3" d="M6.38,9.33a.25.25,0,0,1,.25.25V13a.25.25,0,0,1-.25.25H3A.25.25,0,0,1,2.73,13V9.58A.25.25,0,0,1,3,9.33h3.4m0-.75H3a1,1,0,0,0-1,1V13a1,1,0,0,0,1,1h3.4a1,1,0,0,0,1-1V9.58a1,1,0,0,0-1-1Z"/><polygon class="cls-4" points="4.67 7.83 3.69 6.82 5.68 6.85 4.67 7.83"/><path class="cls-5" d="M4.77,7.33c-.65-2.21,1-3.5,2.92-2.7"/><polygon class="cls-6" points="11.25 8.23 12.23 9.25 10.23 9.21 11.25 8.23"/><path class="cls-7" d="M11.14,8.74c.65,2.21-1,3.5-2.92,2.7"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#def4fd;}.cls-2{fill:#717f8e;}.cls-3{fill:#354a5f;}.cls-4{fill:#2880b9;}.cls-5,.cls-7{fill:#2980b9;}.cls-5,.cls-6{stroke:#2980b9;}.cls-5,.cls-6,.cls-7,.cls-8{stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75px;}.cls-6,.cls-8{fill:none;}.cls-7,.cls-8{stroke:#354a5f;}</style></defs><title>coll-cast</title><g id="_3" data-name="3"><rect class="cls-1" x="2.26" y="2.25" width="10.53" height="10.53" rx="0.75" ry="0.75"/><path class="cls-2" d="M12,2.5a.5.5,0,0,1,.5.5v9a.5.5,0,0,1-.5.5H3a.5.5,0,0,1-.5-.5V3A.5.5,0,0,1,3,2.5h9M12,2H3A1,1,0,0,0,2,3v9a1,1,0,0,0,1,1h9a1,1,0,0,0,1-1V3a1,1,0,0,0-1-1Z"/><rect class="cls-1" x="3.21" y="3.21" width="10.53" height="10.53" rx="0.75" ry="0.75"/><path class="cls-3" d="M13,3.46a.5.5,0,0,1,.5.5v9a.5.5,0,0,1-.5.5H4a.5.5,0,0,1-.5-.5V4a.5.5,0,0,1,.5-.5h9M13,3H4A1,1,0,0,0,3,4v9a1,1,0,0,0,1,1h9a1,1,0,0,0,1-1V4a1,1,0,0,0-1-1Z"/><rect class="cls-1" x="9.28" y="4.67" width="3.03" height="3.03" rx="0.63" ry="0.63"/><path class="cls-3" d="M11.69,5a.25.25,0,0,1,.25.25V7.07a.25.25,0,0,1-.25.25H9.91a.25.25,0,0,1-.25-.25V5.29A.25.25,0,0,1,9.91,5h1.78m0-.75H9.91a1,1,0,0,0-1,1V7.07a1,1,0,0,0,1,1h1.78a1,1,0,0,0,1-1V5.29a1,1,0,0,0-1-1Z"/><rect class="cls-1" x="4.64" y="9.26" width="3.03" height="3.03" rx="0.63" ry="0.63"/><path class="cls-4" d="M7,9.64a.25.25,0,0,1,.25.25v1.78a.25.25,0,0,1-.25.25H5.26A.25.25,0,0,1,5,11.67V9.89a.25.25,0,0,1,.25-.25H7m0-.75H5.26a1,1,0,0,0-1,1v1.78a1,1,0,0,0,1,1H7a1,1,0,0,0,1-1V9.89a1,1,0,0,0-1-1Z"/><polygon class="cls-5" points="6.14 8.36 5.46 7.66 6.85 7.68 6.14 8.36"/><path class="cls-6" d="M6.21,8c-.45-1.55.71-2.45,2-1.89"/><polygon class="cls-7" points="10.75 8.65 11.43 9.36 10.04 9.33 10.75 8.65"/><path class="cls-8" d="M10.67,9c.45,1.55-.71,2.45-2,1.89"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -1,13 +1,13 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, alertify) {
define('pgadmin.node.cast', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'underscore.string', 'sources/pgadmin',
'pgadmin.browser', 'pgadmin.alertifyjs', 'pgadmin.browser.collection'
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, alertify) {
// Extend the collection class for cast
if (!pgBrowser.Nodes['coll-cast']) {
var casts = pgAdmin.Browser.Nodes['coll-cast'] =
pgAdmin.Browser.Collection.extend({
node: 'cast',
label: '{{ _('Casts') }}',
label: gettext('Casts'),
type: 'coll-cast',
columns: ['name', 'description']
});
@@ -20,10 +20,10 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
type: 'cast',
sqlAlterHelp: 'sql-altercast.html',
sqlCreateHelp: 'sql-createcast.html',
dialogHelp: '{{ url_for('help.static', filename='cast_dialog.html') }}',
dialogHelp: url_for('help.static', {'filename': 'cast_dialog.html'}),
canDrop: true,
canDropCascade: true,
label: '{{ _('Cast') }}',
label: gettext('Cast'),
hasSQL: true,
hasDepends: true,
Init: function() {
@@ -38,18 +38,18 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
pgBrowser.add_menus([{
name: 'create_cast_on_database', node: 'database', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
category: 'create', priority: 4, label: gettext('Cast...'),
icon: 'wcTabIcon icon-cast', data: {action: 'create'},
enable: pgBrowser.Nodes['database'].is_conn_allow
},{
name: 'create_cast_on_coll', node: 'coll-cast', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
category: 'create', priority: 4, label: gettext('Cast...'),
icon: 'wcTabIcon icon-cast', data: {action: 'create'}
},{
name: 'create_cast', node: 'cast', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
category: 'create', priority: 4, label: gettext('Cast...'),
icon: 'wcTabIcon icon-cast', data: {action: 'create'}
}]);
@@ -70,14 +70,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
// Define the schema for cast
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
id: 'name', label: gettext('Name'), cell: 'string',
editable: false, type: 'text', disabled: true, cellHeaderClasses: 'width_percent_50'
},{
id: 'oid', label:'{{ _('OID') }}', cell: 'string',
id: 'oid', label: gettext('OID'), cell: 'string',
editable: false, type: 'text', disabled: true, mode: ['properties'],
},{
id: 'srctyp', label:'{{ _('Source type') }}', url: 'get_type',
type: 'text', group: 'Definition', disabled: function(m) {
id: 'srctyp', label: gettext('Source type'), url: 'get_type',
type: 'text', group: gettext('Definition'), disabled: function(m) {
return !m.isNew()
}, mode: ['create'],
@@ -120,11 +120,11 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
* edit mode only
*/
{
id: 'srctyp', label:'{{ _('Source type') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
id: 'srctyp', label: gettext('Source type'), type: 'text',
group: gettext('Definition'), disabled: true, mode:['properties','edit']
},{
id: 'trgtyp', label:'{{ _('Target type') }}', url: 'get_type',
type: 'text', group: 'Definition', disabled: function(m) {
id: 'trgtyp', label: gettext('Target type'), url: 'get_type',
type: 'text', group: gettext('Definition'), disabled: function(m) {
return !m.isNew()
}, mode: ['create'],
transform: function(rows) {
@@ -165,8 +165,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
* edit mode only
*/
{
id: 'trgtyp', label:'{{ _('Target type') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
id: 'trgtyp', label: gettext('Target type'), type: 'text',
group: gettext('Definition'), disabled: true, mode:['properties','edit']
},
/*
@@ -175,9 +175,9 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
* associated functions will be fetch using ajax call
*/
{
id: 'proname', label:'{{ _('Function') }}', deps:['srctyp', 'trgtyp'],
id: 'proname', label: gettext('Function'), deps:['srctyp', 'trgtyp'],
type: 'text', disabled: function(m) { return !m.isNew(); },
group: 'Definition', mode: ['create'],
group: gettext('Definition'), mode: ['create'],
control: 'node-ajax-options',
options: function(control) {
var srcTyp = control.model.get('srctyp');
@@ -226,12 +226,12 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
* edit mode only
*/
{
id: 'proname', label:'{{ _('Function') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
id: 'proname', label: gettext('Function'), type: 'text',
group: gettext('Definition'), disabled: true, mode:['properties','edit']
},{
id: 'castcontext', label:'{{ _('Context') }}',
id: 'castcontext', label: gettext('Context'),
options:{'onText':'IMPLICIT','offText':'EXPLICIT'},
editable: false, type: 'string', group: 'Definition',
editable: false, type: 'string', group: gettext('Definition'),
mode:['create'],
control: Backform.SwitchControl.extend({
getValueFromDOM: function() {
@@ -244,17 +244,17 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
* edit mode
*/
{
id: 'castcontext', label:'{{ _('Context') }}', disabled: true,
id: 'castcontext', label: gettext('Context'), disabled: true,
options:[{
label: 'IMPLICIT', value: 'IMPLICIT'
},{
label: 'EXPLICIT', value: 'EXPLICIT'
},{
label: 'ASSIGNMENT', value: 'ASSIGNMENT'
}], editable: false, type: 'select2', group: 'Definition',
}], editable: false, type: 'select2', group: gettext('Definition'),
mode:['properties', 'edit']
},{
id: 'syscast', label:'{{ _('System cast?') }}',
id: 'syscast', label: gettext('System cast?'),
cell: 'switch', type: 'switch', mode: ['properties'], disabled: true,
options: {
'onText': 'Yes', 'offText': 'No',
@@ -262,7 +262,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
'size': 'small'
}
},{
id: 'description', label:'{{ _('Comment') }}',type: 'text',
id: 'description', label: gettext('Comment'),type: 'text',
type: 'multiline', cellHeaderClasses: 'width_percent_50'
}
],
@@ -279,7 +279,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
// validate source type control
if (_.isUndefined(srctype) || _.isNull(srctype) || String(srctype).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Source type must be selected.') }}';
var msg = gettext('Source type must be selected.');
this.errorModel.set('srctyp', msg);
return msg;
}
@@ -290,7 +290,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
// validate target type control
if (_.isUndefined(trgtype) || _.isNull(trgtype) || String(trgtype).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Target type must be selected.') }}';
var msg = gettext('Target type must be selected.');
this.errorModel.set('trgtyp', msg);
return msg;
}
@@ -52,7 +52,8 @@ class CastsAddTestCase(BaseTestGenerator):
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'])
self.server['port'],
self.server['sslmode'])
cast_utils.drop_cast(connection, self.data["srctyp"],
self.data["trgtyp"])
database_utils.disconnect_database(self, self.server_id,
@@ -48,7 +48,8 @@ class CastsDeleteTestCase(BaseTestGenerator):
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'])
self.server['port'],
self.server['sslmode'])
response = cast_utils.verify_cast(connection, self.source_type,
self.target_type)
if len(response) == 0:
@@ -58,7 +58,8 @@ class CastsGetTestCase(BaseTestGenerator):
self.server['username'],
self.server['db_password'],
self.server['host'],
self.server['port'])
self.server['port'],
self.server['sslmode'])
cast_utils.drop_cast(connection, self.source_type,
self.target_type)
database_utils.disconnect_database(self, self.server_id,
@@ -43,7 +43,8 @@ def create_cast(server, source_type, target_type):
server['username'],
server['db_password'],
server['host'],
server['port'])
server['port'],
server['sslmode'])
old_isolation_level = connection.isolation_level
connection.set_isolation_level(0)
pg_cursor = connection.cursor()
@@ -12,16 +12,18 @@ import re
from functools import wraps
import pgadmin.browser.server_groups.servers.databases as database
from flask import render_template, make_response, request, jsonify
from flask import render_template, request, jsonify
from flask_babel import gettext
from pgadmin.browser.collection import CollectionNodeModule
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from pgadmin.utils.ajax import gone
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class EventTriggerModule(CollectionNodeModule):
@@ -58,6 +60,7 @@ class EventTriggerModule(CollectionNodeModule):
super(EventTriggerModule, self).__init__(*args, **kwargs)
self.min_ver = 90300
self.max_ver = None
self.min_gpdbver = 1000000000
def get_nodes(self, gid, sid, did):
"""
@@ -81,6 +84,14 @@ class EventTriggerModule(CollectionNodeModule):
"""
return database.DatabaseModule.NODE_TYPE
@property
def module_use_template_javascript(self):
"""
Returns whether Jinja2 template is used for generating the javascript
module.
"""
return False
blueprint = EventTriggerModule(__name__)
@@ -99,9 +110,6 @@ class EventTriggerView(PGChildNodeView):
* __init__(**kwargs)
- Method is used to initialize the EventTriggerView and it's base view.
* module_js()
- Returns the javascript module for event trigger.
* check_precondition()
- This function will behave as a decorator which will checks
database connection before running view, it will also attaches
@@ -163,22 +171,9 @@ class EventTriggerView(PGChildNodeView):
'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'fopts': [{'get': 'get_event_funcs'}, {'get': 'get_event_funcs'}]
})
def module_js(self):
"""
Returns the javascript module for event trigger.
"""
return make_response(
render_template(
"event_triggers/js/event_trigger.js",
_=gettext
),
200, {'Content-Type': 'application/x-javascript'}
)
def check_precondition(f):
"""
This function will behave as a decorator which will checks
@@ -427,6 +422,9 @@ class EventTriggerView(PGChildNodeView):
try:
sql = self.get_sql(data, etid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
return sql
sql = sql.strip('\n').strip(' ')
if sql != "":
status, res = self.conn.execute_scalar(sql)
@@ -539,7 +537,11 @@ class EventTriggerView(PGChildNodeView):
data[k] = v
try:
sql = self.get_sql(data, etid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
return sql
sql = sql.strip('\n').strip(' ')
sql = re.sub('\n{2,}', '\n\n', sql)
if sql == '':
sql = "--modified SQL"
return make_json_response(
@@ -628,6 +630,11 @@ class EventTriggerView(PGChildNodeView):
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
_("Could not find the specified event trigger on the server.")
)
result = res['rows'][0]
result = self._formatter(result)
@@ -648,6 +655,7 @@ class EventTriggerView(PGChildNodeView):
sql_header += "\n"
sql = sql_header + sql
sql = re.sub('\n{2,}', '\n\n', sql)
return ajax_response(response=sql)
Loaded 100 of 1533 files, more files were not shown because too many files have changed in this diff. Show more