mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-28 15:40:06 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
490999f528 | ||
|
|
ceb0e39e14 | ||
|
|
3bed332439 | ||
|
|
c21ea3c342 | ||
|
|
84ecffa4d9 | ||
|
|
9bff6c7157 | ||
|
|
5c4c09f237 | ||
|
|
f706f7ed0c | ||
|
|
fb12b2e2fc | ||
|
|
badbbade08 |
No files matched your search
@@ -11,6 +11,7 @@ notes for it.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_4_5
|
||||
release_notes_4_4
|
||||
release_notes_4_3
|
||||
release_notes_4_2
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
***********
|
||||
Version 4.5
|
||||
***********
|
||||
|
||||
Release date: 2019-04-10
|
||||
|
||||
This release contains a number of new features and fixes reported since the
|
||||
release of pgAdmin4 4.4.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Bug #2214 <https://redmine.postgresql.org/issues/2214>`_ - Fixed 'Change Password' issue for SCRAM authentication.
|
||||
| `Bug #3656 <https://redmine.postgresql.org/issues/3656>`_ - Ensure that two consecutive SELECT statements should work properly.
|
||||
| `Bug #4131 <https://redmine.postgresql.org/issues/4131>`_ - Relabel the Save button on the datagrid text editor to avoid confusion with the actual Save button that updates the database.
|
||||
| `Bug #4142 <https://redmine.postgresql.org/issues/4142>`_ - Added recommended ESLinter checks.
|
||||
| `Bug #4143 <https://redmine.postgresql.org/issues/4143>`_ - Ensure that pgAdmin4 should work properly with psycopg2 v2.8
|
||||
+1
-1
@@ -21,7 +21,7 @@ sqlparse==0.2.4
|
||||
WTForms==2.2.1
|
||||
Flask-Paranoid==0.2.0
|
||||
psutil==5.5.1
|
||||
psycopg2>=2.7.7
|
||||
psycopg2>=2.8
|
||||
python-dateutil>=2.8.0
|
||||
htmlmin==0.1.12
|
||||
Flask-HTMLmin==1.5.0
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>pgAdmin 4</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.4.0</string>
|
||||
<string>4.5.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.4.0</string>
|
||||
<string>4.5.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION = 4.4.0.0
|
||||
VERSION = 4.5.0.0
|
||||
QMAKE_TARGET_COMPANY = "The pgAdmin Development Team"
|
||||
QMAKE_TARGET_PRODUCT = "pgAdmin 4"
|
||||
QMAKE_TARGET_DESCRIPTION = "pgAdmin 4 Desktop Runtime"
|
||||
|
||||
@@ -14,6 +14,9 @@ module.exports = {
|
||||
'amd': true,
|
||||
'jasmine': true,
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
],
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 2018,
|
||||
'sourceType': 'module',
|
||||
@@ -43,5 +46,7 @@ module.exports = {
|
||||
'always-multiline'
|
||||
],
|
||||
'no-console': ["error", { allow: ["warn", "error"] }],
|
||||
// We need to exclude below for RegEx case
|
||||
"no-useless-escape": 0,
|
||||
},
|
||||
};
|
||||
+2
-2
@@ -50,7 +50,7 @@ APP_ICON = 'pg-icon'
|
||||
|
||||
# Application version number components
|
||||
APP_RELEASE = 4
|
||||
APP_REVISION = 4
|
||||
APP_REVISION = 5
|
||||
|
||||
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
|
||||
# for GA releases.
|
||||
@@ -59,7 +59,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
|
||||
APP_VERSION_INT = 40400
|
||||
APP_VERSION_INT = 40500
|
||||
|
||||
# DO NOT CHANGE!
|
||||
# The application version string, constructed from the components
|
||||
|
||||
-1
@@ -240,7 +240,6 @@ define('pgadmin.node.column', [
|
||||
return false;
|
||||
},
|
||||
editable: function(m) {
|
||||
var name = m.get('name');
|
||||
// If HeaderCell then allow True
|
||||
if(m instanceof Backbone.Collection) {
|
||||
return true;
|
||||
|
||||
@@ -1070,7 +1070,6 @@ define('pgadmin.browser', [
|
||||
var loaded = this.t.wasLoad(parent),
|
||||
onLoad = function() {
|
||||
self.i = parent;
|
||||
self.d = self.d;
|
||||
self.pathOfTreeItems.push({coll: false, item: parent, d: self.d});
|
||||
self.success();
|
||||
return;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
import random
|
||||
|
||||
from regression.python_test_utils import test_utils
|
||||
from regression.feature_utils.base_feature_test import BaseFeatureTest
|
||||
@@ -19,35 +20,40 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
|
||||
dict())
|
||||
]
|
||||
|
||||
role = ""
|
||||
|
||||
def before(self):
|
||||
with test_utils.Database(self.server) as (connection, _):
|
||||
if connection.server_version < 90100:
|
||||
self.skipTest(
|
||||
"Membership is not present in Postgres below PG v9.1")
|
||||
|
||||
# create role
|
||||
self.role = "test_role" + str(random.randint(10000, 65535))
|
||||
|
||||
# Some test function is needed for debugger
|
||||
test_utils.create_role(self.server, "postgres",
|
||||
"test_role")
|
||||
self.role)
|
||||
test_utils.create_role(self.server, "postgres",
|
||||
"<h1>test</h1>")
|
||||
|
||||
def runTest(self):
|
||||
self.page.wait_for_spinner_to_disappear()
|
||||
self.page.add_server(self.server)
|
||||
self._role_node_expandable()
|
||||
self._role_node_expandable(self.role)
|
||||
self._check_role_membership_control()
|
||||
|
||||
def after(self):
|
||||
self.page.remove_server(self.server)
|
||||
test_utils.drop_role(self.server, "postgres",
|
||||
"test_role")
|
||||
self.role)
|
||||
test_utils.drop_role(self.server, "postgres",
|
||||
"<h1>test</h1>")
|
||||
|
||||
def _role_node_expandable(self):
|
||||
def _role_node_expandable(self, role):
|
||||
self.page.toggle_open_server(self.server['name'])
|
||||
self.page.toggle_open_tree_item('Login/Group Roles')
|
||||
self.page.select_tree_item("test_role")
|
||||
self.page.select_tree_item(role)
|
||||
|
||||
def _check_role_membership_control(self):
|
||||
self.page.driver.find_element_by_link_text("Object").click()
|
||||
|
||||
@@ -24,4 +24,4 @@ export function getHelpUrl(base_path, file, version) {
|
||||
}
|
||||
|
||||
return url + file;
|
||||
};
|
||||
}
|
||||
+1317
-6473
File diff suppressed because it is too large.
Load diff
@@ -38,7 +38,12 @@ define([], function() {
|
||||
var o, n, i, l, d, c = /^top|bottom/,
|
||||
f = ['paddingTop', 'paddingBottom', 'borderTop', 'borderBottom'],
|
||||
u = 4;
|
||||
if (o = m ? m(t)[e] : (n = t.style['pixel' + e.charAt(0).toUpperCase() + e.slice(1)]) ? n + 'px' : 'fontSize' === e ? r(t, '1em', 'left', 1) + 'px' : t.currentStyle[e], i = (o.match(s) || [])[2], '%' === i && p)
|
||||
|
||||
n = t.style['pixel' + e.charAt(0).toUpperCase() + e.slice(1)];
|
||||
o = m ? m(t)[e] : (n) ? n + 'px' : 'fontSize' === e ? r(t, '1em', 'left', 1) + 'px' : t.currentStyle[e];
|
||||
i = (o.match(s) || [])[2];
|
||||
|
||||
if ('%' === i && p)
|
||||
if (c.test(e)) {
|
||||
for (l = (d = t.parentNode || t).offsetHeight; u--;) l -= parseFloat(a(d, f[u]));
|
||||
o = parseFloat(o) / 100 * l + 'px';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
import JSONBigNumber from 'json-bignumber';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
(function($, JSONBigNumber) {
|
||||
// register namespace
|
||||
@@ -46,7 +47,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
// Generate and return editor buttons
|
||||
function getButtons(editable) {
|
||||
var $buttons = $('<div class=\'pg_buttons\' />'),
|
||||
label = editable ? 'Cancel' : 'OK',
|
||||
label = editable ? gettext('Cancel') : gettext('OK'),
|
||||
button_type = editable ? 'btn-secondary' : 'btn-primary',
|
||||
button_icon = editable ? 'fa-times' : 'fa-check';
|
||||
|
||||
@@ -56,8 +57,8 @@ import JSONBigNumber from 'json-bignumber';
|
||||
.appendTo($buttons);
|
||||
|
||||
if (editable) {
|
||||
$('<button class=\'btn btn-primary long_text_editor\' data-label="Save">'+
|
||||
'<span class="fa fa-save pg-alertify-button"></span> Save'+
|
||||
$('<button class=\'btn btn-primary long_text_editor\' data-label="' + gettext('OK') + '">'+
|
||||
'<span class="fa fa-check pg-alertify-button"></span> ' + gettext('OK') +
|
||||
'</button>')
|
||||
.appendTo($buttons);
|
||||
}
|
||||
@@ -276,7 +277,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
if (args.column.is_array && !is_valid_array($input.val())) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: 'Array must start with \'{\' and end with \'}\'',
|
||||
msg: gettext('Arrays must start with "{" and end with "}"'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -640,7 +641,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
var defaultValue;
|
||||
|
||||
this.init = function() {
|
||||
$input = $('<INPUT type=text class=\'editor-text\' readonly/>')
|
||||
$input = $('<input type=text class=\'editor-text\' readonly/>')
|
||||
.appendTo(args.container)
|
||||
.on('keydown.nav', function(e) {
|
||||
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
|
||||
@@ -710,7 +711,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
var defaultValue;
|
||||
|
||||
this.init = function() {
|
||||
$select = $('<INPUT type=checkbox value=\'true\' class=\'editor-checkbox\' hideFocus disabled>');
|
||||
$select = $('<input type=checkbox value=\'true\' class=\'editor-checkbox\' hideFocus disabled>');
|
||||
$select.appendTo(args.container);
|
||||
$select.trigger('focus');
|
||||
};
|
||||
@@ -773,7 +774,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
var defaultValue;
|
||||
|
||||
this.init = function() {
|
||||
$input = $('<INPUT type=text class=\'editor-text\' />');
|
||||
$input = $('<input type=text class=\'editor-text\' />');
|
||||
|
||||
$input.on('keydown.nav', function(e) {
|
||||
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
|
||||
@@ -836,7 +837,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
if (!args.column.is_array && isNaN(value)) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: 'Please enter a valid number',
|
||||
msg: gettext('Please enter a valid number'),
|
||||
};
|
||||
}
|
||||
if (args.column.validator) {
|
||||
@@ -850,7 +851,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
if (!is_valid_array(value)) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: 'Array must start with \'{\' and end with \'}\'',
|
||||
msg: gettext('Arrays must start with "{" and end with "}"'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -867,7 +868,7 @@ import JSONBigNumber from 'json-bignumber';
|
||||
if (isNaN(arr[k])) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: 'Please enter a valid numbers',
|
||||
msg: gettext('Please enter a valid number'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
##########################################################################
|
||||
|
||||
import sys
|
||||
import random
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from regression.python_test_utils import test_utils
|
||||
from pgadmin.utils import server_utils
|
||||
@@ -56,7 +58,8 @@ class TestSQLASCIIEncoding(BaseTestGenerator):
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
self.encode_db_name = 'test_encoding_' + self.db_encoding
|
||||
self.encode_db_name = 'test_encoding_' + self.db_encoding + \
|
||||
str(random.randint(1000, 65535))
|
||||
self.encode_sid = self.server_information['server_id']
|
||||
|
||||
server_con = server_utils.connect_server(self, self.encode_sid)
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -18,6 +18,8 @@ try:
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict
|
||||
|
||||
import psycopg2
|
||||
|
||||
from psycopg2.extensions import cursor as _cursor, encodings
|
||||
from .encoding import configureDriverEncodings
|
||||
|
||||
@@ -91,7 +93,25 @@ class _WrapperColumn(object):
|
||||
Generates an OrderedDict from the fields of the original objects
|
||||
with avoiding the duplicate name.
|
||||
"""
|
||||
ores = OrderedDict(self.orig_col._asdict())
|
||||
|
||||
# In psycopg2 2.8, the description of one result column,
|
||||
# exposed as items of the cursor.description sequence.
|
||||
# Before psycopg2 2.8 the description attribute was a sequence
|
||||
# of simple tuples or namedtuples.
|
||||
if psycopg2.__version__.find('2.8') != -1:
|
||||
ores = OrderedDict()
|
||||
ores['name'] = self.orig_col.name
|
||||
ores['type_code'] = self.orig_col.type_code
|
||||
ores['display_size'] = self.orig_col.display_size
|
||||
ores['internal_size'] = self.orig_col.internal_size
|
||||
ores['precision'] = self.orig_col.precision
|
||||
ores['scale'] = self.orig_col.scale
|
||||
ores['null_ok'] = self.orig_col.null_ok
|
||||
ores['table_oid'] = self.orig_col.table_oid
|
||||
ores['table_column'] = self.orig_col.table_column
|
||||
else:
|
||||
ores = OrderedDict(self.orig_col._asdict())
|
||||
|
||||
name = ores['name']
|
||||
if self.dummy_name:
|
||||
ores['name'] = self.dummy_name
|
||||
|
||||
@@ -182,7 +182,7 @@ class PgadminPage:
|
||||
ActionChains(self.driver).double_click(item).perform()
|
||||
|
||||
def toggle_open_tables_node(self):
|
||||
"""The function will be used for opening Trees node only"""
|
||||
"""The function will be used for opening Tables node only"""
|
||||
|
||||
# get the element which contains 'aria-expanded' info
|
||||
tables_expansion_ele = self.find_by_xpath("//div[div[div[div[div[div"
|
||||
@@ -479,7 +479,7 @@ class PgadminPage:
|
||||
return element_selector(self.driver)
|
||||
|
||||
def _wait_for(self, waiting_for_message, condition_met_function,
|
||||
timeout=None):
|
||||
timeout=3):
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
return WebDriverWait(self.driver, timeout, 0.01).until(
|
||||
|
||||
@@ -26,8 +26,19 @@ def close_bgprocess_popup(tester):
|
||||
# In cases where restore div is not closed (sometime due to some error)
|
||||
try:
|
||||
if tester.driver.find_element_by_xpath(
|
||||
"//div[@class='card-header bg-primary d-flex']/div[contains("
|
||||
"text(), 'Restoring backup')]"):
|
||||
"//div[@class='card-header bg-primary d-flex']/div"
|
||||
"[contains(text(), 'Restoring backup')]"):
|
||||
tester.driver.find_element_by_css_selector(
|
||||
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# In cases where maintenance window is not closed (sometime due to some
|
||||
# error)
|
||||
try:
|
||||
if tester.driver.find_element_by_xpath(
|
||||
"//div[@class='card-header bg-primary d-flex']/div"
|
||||
"[contains(text(), 'Maintenance')]"):
|
||||
tester.driver.find_element_by_css_selector(
|
||||
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
|
||||
except Exception:
|
||||
|
||||
@@ -219,6 +219,9 @@ def get_test_modules(arguments):
|
||||
options.add_argument("--window-size=1280,1024")
|
||||
driver = webdriver.Chrome(chrome_options=options)
|
||||
|
||||
# maximize browser window
|
||||
driver.maximize_window()
|
||||
|
||||
app_starter = AppStarter(driver, config)
|
||||
app_starter.start_app()
|
||||
|
||||
|
||||
Reference in new issue
Block a user