mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added React framework for the properties dialog and port Server Group, Server, and Database dialogs.
Following changes done for the framework: - Framework for creating React based dynamic form view out of a pre-defined UI schema. Previously, it was based on Backform/Backbone. - The new framework and components will use MaterialUI as the base. Previously, Bootstrap/Backform/jQuery components were used. - The new code uses JSS instead of CSS since material UI and most modern React libraries also use JSS. In the future, this will allow us to change the theme in real-time without refresh. - 90% code covered by 80-85 new jasmine test cases. - Server group node UI Schema migration to new, with schema test cases. - Server node UI Schema migration to new, with schema test cases. - Database node UI Schema migration to new, with schema test cases. - Few other UI changes. Fixes #6130
This commit is contained in:
committed by
Akshay Joshi
parent
a10b0c7786
commit
764677431f
@@ -0,0 +1,82 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import { getNodeListByName } from '../../../../static/js/node_ajax';
|
||||
|
||||
export function getNodePrivilegeRoleSchema(nodeObj, treeNodeInfo, itemNodeData, privileges) {
|
||||
let keys = ['grantee', 'privileges', 'grantor'];
|
||||
return new PrivilegeRoleSchema(
|
||||
()=>getNodeListByName('role', treeNodeInfo, itemNodeData, ()=>true, (res)=>{
|
||||
res.unshift({label: 'PUBLIC', value: 'PUBLIC'});
|
||||
return res;
|
||||
}),
|
||||
()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
keys,
|
||||
treeNodeInfo,
|
||||
privileges
|
||||
);
|
||||
}
|
||||
|
||||
export default class PrivilegeRoleSchema extends BaseUISchema {
|
||||
constructor(granteeOptions, grantorOptions, keys, nodeInfo, supportedPrivs) {
|
||||
super({
|
||||
grantee: undefined,
|
||||
grantor: nodeInfo?.server?.user?.name,
|
||||
privileges: undefined,
|
||||
});
|
||||
this.granteeOptions = granteeOptions;
|
||||
this.grantorOptions = grantorOptions;
|
||||
this.nodeInfo = nodeInfo;
|
||||
this.supportedPrivs = supportedPrivs || [];
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
|
||||
return [{
|
||||
id: 'grantee', label: gettext('Grantee'), type:'text',
|
||||
editable: true,
|
||||
cell: ()=>({
|
||||
cell: 'select', options: this.granteeOptions,
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
}
|
||||
}),
|
||||
noEmpty: true,
|
||||
},
|
||||
{
|
||||
id: 'privileges', label: gettext('Privileges'),
|
||||
type: 'text', group: null,
|
||||
cell: ()=>({cell: 'privilege', controlProps: {
|
||||
supportedPrivs: this.supportedPrivs,
|
||||
}}), minWidth: 280,
|
||||
disabled : function(state) {
|
||||
return !(
|
||||
obj.nodeInfo &&
|
||||
obj.nodeInfo.server.user.name == state['grantor']
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'grantor', label: gettext('Grantor'), type: 'text', readonly: true,
|
||||
cell: ()=>({cell: 'select', options: obj.grantorOptions}),
|
||||
}];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
if((state.privileges || []).length <= 0) {
|
||||
setError('privileges', gettext('At least one privilege should be selected.'));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
|
||||
export default class SecLabelSchema extends BaseUISchema {
|
||||
constructor() {
|
||||
super({
|
||||
provider: undefined,
|
||||
label: undefined,
|
||||
});
|
||||
this.keys = ['provider', 'label'];
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return [{
|
||||
id: 'provider', label: gettext('Provider'),
|
||||
type: 'text', editable: true, cell: 'text',
|
||||
},
|
||||
{
|
||||
id: 'label', label: gettext('Security label'),
|
||||
type: 'text', editable: true, cell: 'text', noEmpty: true,
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -7,23 +7,22 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeListById } from '../../../../static/js/node_ajax';
|
||||
import ServerSchema from './server.ui';
|
||||
|
||||
define('pgadmin.node.server', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.server.supported_servers', 'pgadmin.user_management.current_user',
|
||||
'pgadmin.user_management.current_user',
|
||||
'pgadmin.alertifyjs', 'pgadmin.backform',
|
||||
'sources/browser/server_groups/servers/model_validation',
|
||||
'pgadmin.authenticate.kerberos',
|
||||
'pgadmin.browser.server.privilege',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser,
|
||||
supported_servers, current_user, Alertify, Backform,
|
||||
modelValidation, Kerberos,
|
||||
current_user, Alertify, Backform, Kerberos,
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['server']) {
|
||||
var SSL_MODES = ['prefer', 'require', 'verify-ca', 'verify-full'];
|
||||
|
||||
pgBrowser.SecLabelModel = pgBrowser.Node.Model.extend({
|
||||
defaults: {
|
||||
provider: undefined,
|
||||
@@ -738,469 +737,15 @@ define('pgadmin.node.server', [
|
||||
pgBrowser.psql.psql_tool(d, i, true);
|
||||
}
|
||||
},
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
gid: undefined,
|
||||
id: undefined,
|
||||
name: '',
|
||||
sslmode: 'prefer',
|
||||
host: '',
|
||||
hostaddr: '',
|
||||
port: 5432,
|
||||
db: 'postgres',
|
||||
username: current_user.name,
|
||||
role: null,
|
||||
connect_now: true,
|
||||
password: undefined,
|
||||
save_password: false,
|
||||
db_res: '',
|
||||
passfile: undefined,
|
||||
sslcompression: false,
|
||||
sslcert: undefined,
|
||||
sslkey: undefined,
|
||||
sslrootcert: undefined,
|
||||
sslcrl: undefined,
|
||||
service: undefined,
|
||||
use_ssh_tunnel: 0,
|
||||
tunnel_host: undefined,
|
||||
tunnel_port: 22,
|
||||
tunnel_username: undefined,
|
||||
tunnel_identity_file: undefined,
|
||||
tunnel_password: undefined,
|
||||
tunnel_authentication: 0,
|
||||
save_tunnel_password: false,
|
||||
connect_timeout: 10,
|
||||
},
|
||||
// Default values!
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
|
||||
if (isNew) {
|
||||
this.set({'gid': args.node_info['server_group']._id});
|
||||
getSchema: (treeNodeInfo, itemNodeData)=>{
|
||||
let schema = new ServerSchema(
|
||||
getNodeListById(pgBrowser.Nodes['server_group'], treeNodeInfo, itemNodeData),
|
||||
{
|
||||
gid: treeNodeInfo['server_group']._id,
|
||||
}
|
||||
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
schema: [{
|
||||
id: 'id', label: gettext('ID'), type: 'int', mode: ['properties'],
|
||||
visible: function(model){
|
||||
if (model.attributes.user_id != current_user.id && pgAdmin.server_mode == 'True')
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
},{
|
||||
id: 'name', label: gettext('Name'), type: 'text',
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isShared',
|
||||
},
|
||||
{
|
||||
id: 'gid', label: gettext('Server group'), type: 'int',
|
||||
control: 'node-list-by-id', node: 'server_group',
|
||||
mode: ['create', 'edit'], select2: {allowClear: false}, disabled: 'isShared',
|
||||
},
|
||||
{
|
||||
id: 'server_owner', label: gettext('Shared Server Owner'), type: 'text', mode: ['properties'],
|
||||
visible:function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (model.attributes.shared && serverOwner != current_user.id && pgAdmin.server_mode == 'True'){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'server_type', label: gettext('Server type'), type: 'options',
|
||||
mode: ['properties'], visible: 'isConnected',
|
||||
'options': supported_servers,
|
||||
},{
|
||||
id: 'connected', label: gettext('Connected?'), type: 'switch',
|
||||
mode: ['properties'], group: gettext('Connection'), 'options': {
|
||||
'onText': gettext('True'), 'offText': gettext('False'), 'size': 'mini',
|
||||
},
|
||||
},{
|
||||
id: 'version', label: gettext('Version'), type: 'text', group: null,
|
||||
mode: ['properties'], visible: 'isConnected',
|
||||
},{
|
||||
id: 'bgcolor', label: gettext('Background'), type: 'color',
|
||||
group: null, mode: ['edit', 'create'], disabled: 'isfgColorSet',
|
||||
deps: ['fgcolor'],
|
||||
},{
|
||||
id: 'fgcolor', label: gettext('Foreground'), type: 'color',
|
||||
group: null, mode: ['edit', 'create'], disabled: 'isConnected',
|
||||
},{
|
||||
id: 'connect_now', controlLabel: gettext('Connect now?'), type: 'checkbox',
|
||||
group: null, mode: ['create'],
|
||||
},{
|
||||
id: 'shared', label: gettext('Shared?'), type: 'switch',
|
||||
mode: ['properties', 'create', 'edit'], 'options': {'size': 'mini'},
|
||||
readonly: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},visible: function(){
|
||||
if (current_user.is_admin && pgAdmin.server_mode == 'True')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comment', label: gettext('Comments'), type: 'multiline', group: null,
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
},{
|
||||
id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'],disabled: 'isShared',
|
||||
control: Backform.InputControl.extend({
|
||||
onChange: function() {
|
||||
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||
if (!this.model || !this.model.changed) {
|
||||
this.model.inform_text = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.model.origSessAttrs.host != this.model.changed.host && !this.model.isNew() && this.model.get('connected'))
|
||||
{
|
||||
this.model.inform_text = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
this.model.inform_text = undefined;
|
||||
}
|
||||
},
|
||||
}),
|
||||
},{
|
||||
id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], min: 1, max: 65535, disabled: 'isShared',
|
||||
control: Backform.InputControl.extend({
|
||||
onChange: function() {
|
||||
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||
if (!this.model || !this.model.changed) {
|
||||
this.model.inform_text = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.model.origSessAttrs.port != this.model.changed.port && !this.model.isNew() && this.model.get('connected'))
|
||||
{
|
||||
this.model.inform_text = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
this.model.inform_text = undefined;
|
||||
}
|
||||
},
|
||||
}),
|
||||
},{
|
||||
id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',disabled: 'isShared',
|
||||
},{
|
||||
id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
control: Backform.InputControl.extend({
|
||||
onChange: function() {
|
||||
Backform.InputControl.prototype.onChange.apply(this, arguments);
|
||||
if (!this.model || !this.model.changed) {
|
||||
this.model.inform_text = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.model.origSessAttrs.username != this.model.changed.username && !this.model.isNew() && this.model.get('connected'))
|
||||
{
|
||||
this.model.inform_text = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
this.model.inform_text = undefined;
|
||||
}
|
||||
},
|
||||
}),
|
||||
},{
|
||||
id: 'kerberos_conn', label: gettext('Kerberos authentication?'), type: 'switch',
|
||||
group: gettext('Connection'), 'options': {
|
||||
'onText': gettext('True'), 'offText': gettext('False'), 'size': 'mini',
|
||||
}
|
||||
},{
|
||||
id: 'gss_authenticated', label: gettext('GSS authenticated?'), type: 'switch',
|
||||
group: gettext('Connection'), 'options': {
|
||||
'onText': gettext('True'), 'offText': gettext('False'), 'size': 'mini',
|
||||
}, mode: ['properties'], visible: 'isConnected'
|
||||
},{
|
||||
id: 'gss_encrypted', label: gettext('GSS encrypted?'), type: 'switch',
|
||||
group: gettext('Connection'), 'options': {
|
||||
'onText': gettext('True'), 'offText': gettext('False'), 'size': 'mini',
|
||||
}, mode: ['properties'], visible: 'isConnected',
|
||||
},{
|
||||
id: 'password', label: gettext('Password'), type: 'password', maxlength: null,
|
||||
group: gettext('Connection'), control: 'input', mode: ['create'],
|
||||
deps: ['connect_now', 'kerberos_conn'],
|
||||
visible: function(model) {
|
||||
return model.get('connect_now') && model.isNew();
|
||||
},
|
||||
disabled: function(model) {
|
||||
if (model.get('kerberos_conn'))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},{
|
||||
id: 'save_password', controlLabel: gettext('Save password?'),
|
||||
type: 'checkbox', group: gettext('Connection'), mode: ['create'],
|
||||
deps: ['connect_now', 'kerberos_conn'], visible: function(model) {
|
||||
return model.get('connect_now') && model.isNew();
|
||||
},
|
||||
disabled: function(model) {
|
||||
if (!current_user.allow_save_password || model.get('kerberos_conn'))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},{
|
||||
id: 'role', label: gettext('Role'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
},{
|
||||
id: 'service', label: gettext('Service'), type: 'text',
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
group: gettext('Connection'),
|
||||
},{
|
||||
id: 'sslmode', label: gettext('SSL mode'), control: 'select2', group: gettext('SSL'),
|
||||
select2: {
|
||||
allowClear: false,
|
||||
minimumResultsForSearch: Infinity,
|
||||
},
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected',
|
||||
'options': [
|
||||
{label: gettext('Allow'), value: 'allow'},
|
||||
{label: gettext('Prefer'), value: 'prefer'},
|
||||
{label: gettext('Require'), value: 'require'},
|
||||
{label: gettext('Disable'), value: 'disable'},
|
||||
{label: gettext('Verify-CA'), value: 'verify-ca'},
|
||||
{label: gettext('Verify-Full'), value: 'verify-full'},
|
||||
],
|
||||
},{
|
||||
id: 'sslcert', label: gettext('Client certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: 'isSSL', readonly: 'isConnected', control: Backform.FileControl,
|
||||
dialog_type: 'select_file', supp_types: ['*'],
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslkey', label: gettext('Client certificate key'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: 'isSSL', readonly: 'isConnected', control: Backform.FileControl,
|
||||
dialog_type: 'select_file', supp_types: ['*'],
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslrootcert', label: gettext('Root certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: 'isSSL', readonly: 'isConnected', control: Backform.FileControl,
|
||||
dialog_type: 'select_file', supp_types: ['*'],
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: 'isSSL', readonly: 'isConnected', control: Backform.FileControl,
|
||||
dialog_type: 'select_file', supp_types: ['*'],
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch',
|
||||
mode: ['edit', 'create'], group: gettext('SSL'),
|
||||
'options': {'size': 'mini'},
|
||||
deps: ['sslmode'], disabled: 'isSSL', readonly: 'isConnected',
|
||||
},{
|
||||
id: 'sslcert', label: gettext('Client certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(model) {
|
||||
var sslcert = model.get('sslcert');
|
||||
return !_.isUndefined(sslcert) && !_.isNull(sslcert);
|
||||
},
|
||||
},{
|
||||
id: 'sslkey', label: gettext('Client certificate key'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(model) {
|
||||
var sslkey = model.get('sslkey');
|
||||
return !_.isUndefined(sslkey) && !_.isNull(sslkey);
|
||||
},
|
||||
},{
|
||||
id: 'sslrootcert', label: gettext('Root certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(model) {
|
||||
var sslrootcert = model.get('sslrootcert');
|
||||
return !_.isUndefined(sslrootcert) && !_.isNull(sslrootcert);
|
||||
},
|
||||
},{
|
||||
id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(model) {
|
||||
var sslcrl = model.get('sslcrl');
|
||||
return !_.isUndefined(sslcrl) && !_.isNull(sslcrl);
|
||||
},
|
||||
},{
|
||||
id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch',
|
||||
mode: ['properties'], group: gettext('SSL'),
|
||||
'options': {'size': 'mini'},
|
||||
deps: ['sslmode'], visible: function(model) {
|
||||
var sslmode = model.get('sslmode');
|
||||
return _.indexOf(SSL_MODES, sslmode) != -1;
|
||||
},
|
||||
},{
|
||||
id: 'use_ssh_tunnel', label: gettext('Use SSH tunneling'), type: 'switch',
|
||||
mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),
|
||||
'options': {'size': 'mini'},
|
||||
disabled: function(model) {
|
||||
if (!pgAdmin.Browser.utils.support_ssh_tunnel) {
|
||||
setTimeout(function() {
|
||||
model.set('use_ssh_tunnel', 0);
|
||||
}, 10);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
},{
|
||||
id: 'tunnel_host', label: gettext('Tunnel host'), type: 'text', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
|
||||
disabled: function(model) {
|
||||
return !model.get('use_ssh_tunnel');
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
},{
|
||||
id: 'tunnel_port', label: gettext('Tunnel port'), type: 'int', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'], max: 65535,
|
||||
disabled: function(model) {
|
||||
return !model.get('use_ssh_tunnel');
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
},{
|
||||
id: 'tunnel_username', label: gettext('Username'), type: 'text', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
|
||||
disabled: function(model) {
|
||||
return !model.get('use_ssh_tunnel');
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
},{
|
||||
id: 'tunnel_authentication', label: gettext('Authentication'), type: 'switch',
|
||||
mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),
|
||||
'options': {'onText': gettext('Identity file'),
|
||||
'offText': gettext('Password'), 'size': 'mini', width: '90'},
|
||||
deps: ['use_ssh_tunnel'],
|
||||
disabled: function(model) {
|
||||
return !model.get('use_ssh_tunnel');
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
}, {
|
||||
id: 'tunnel_identity_file', label: gettext('Identity file'), type: 'text',
|
||||
group: gettext('SSH Tunnel'), mode: ['properties', 'edit', 'create'],
|
||||
control: Backform.FileControl, dialog_type: 'select_file', supp_types: ['*'],
|
||||
deps: ['tunnel_authentication', 'use_ssh_tunnel'],
|
||||
disabled: function(model) {
|
||||
let file = model.get('tunnel_identity_file');
|
||||
if (!model.get('tunnel_authentication') && file) {
|
||||
setTimeout(function() {
|
||||
model.set('tunnel_identity_file', null);
|
||||
}, 10);
|
||||
}
|
||||
return !model.get('tunnel_authentication') || !model.get('use_ssh_tunnel');
|
||||
},
|
||||
},{
|
||||
id: 'tunnel_password', label: gettext('Password'), type: 'password',
|
||||
group: gettext('SSH Tunnel'), control: 'input', mode: ['create'],
|
||||
deps: ['use_ssh_tunnel'],
|
||||
disabled: function(model) {
|
||||
return !model.get('use_ssh_tunnel');
|
||||
},
|
||||
readonly: 'isConnected',
|
||||
}, {
|
||||
id: 'save_tunnel_password', controlLabel: gettext('Save password?'),
|
||||
type: 'checkbox', group: gettext('SSH Tunnel'), mode: ['create'],
|
||||
deps: ['connect_now', 'use_ssh_tunnel'], visible: function(model) {
|
||||
return model.get('connect_now') && model.isNew();
|
||||
},
|
||||
disabled: function(model) {
|
||||
if (!current_user.allow_save_tunnel_password ||
|
||||
!model.get('use_ssh_tunnel'))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
}, {
|
||||
id: 'hostaddr', label: gettext('Host address'), type: 'text', group: gettext('Advanced'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
},{
|
||||
id: 'db_res', label: gettext('DB restriction'), type: 'select2', group: gettext('Advanced'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected', select2: {multiple: true, allowClear: false,
|
||||
tags: true, tokenSeparators: [','], first_empty: false, selectOnClose: true, emptyOptions: true},
|
||||
},{
|
||||
id: 'passfile', label: gettext('Password file'), type: 'text',
|
||||
group: gettext('Advanced'), mode: ['edit', 'create'],
|
||||
disabled: 'isValidLib', readonly: 'isConnected', control: Backform.FileControl,
|
||||
dialog_type: 'select_file', supp_types: ['*'],
|
||||
},{
|
||||
id: 'passfile', label: gettext('Password file'), type: 'text',
|
||||
group: gettext('Advanced'), mode: ['properties'],
|
||||
visible: function(model) {
|
||||
var passfile = model.get('passfile');
|
||||
return !_.isUndefined(passfile) && !_.isNull(passfile);
|
||||
},
|
||||
},{
|
||||
id: 'connect_timeout', label: gettext('Connection timeout (seconds)'),
|
||||
type: 'int', group: gettext('Advanced'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: 'isConnected',
|
||||
min: 0,
|
||||
}],
|
||||
isVisible: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
},
|
||||
isShared: function(model){
|
||||
var serverOwner = model.attributes.user_id;
|
||||
if (!model.isNew() && serverOwner != current_user.id && model.attributes.shared){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
validate: function() {
|
||||
const validateModel = new modelValidation.ModelValidation(this);
|
||||
return validateModel.validate();
|
||||
},
|
||||
isConnected: function(model) {
|
||||
return model.get('connected');
|
||||
},
|
||||
isfgColorSet: function(model) {
|
||||
var bgcolor = model.get('bgcolor'),
|
||||
fgcolor = model.get('fgcolor');
|
||||
|
||||
if(model.get('connected')) {
|
||||
return true;
|
||||
}
|
||||
// If fgcolor is set and bgcolor is not set then force bgcolor
|
||||
// to set as white
|
||||
if(_.isUndefined(bgcolor) || _.isNull(bgcolor) || !bgcolor) {
|
||||
if(fgcolor) {
|
||||
model.set('bgcolor', '#ffffff');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
isSSL: function(model) {
|
||||
var ssl_mode = model.get('sslmode');
|
||||
return _.indexOf(SSL_MODES, ssl_mode) == -1;
|
||||
},
|
||||
isValidLib: function() {
|
||||
// older version of libpq do not support 'passfile' parameter in
|
||||
// connect method, valid libpq must have version >= 100000
|
||||
return pgBrowser.utils.pg_libpq_version < 100000;
|
||||
},
|
||||
}),
|
||||
);
|
||||
return schema;
|
||||
},
|
||||
connection_lost: function(i, resp) {
|
||||
if (pgBrowser.tree) {
|
||||
var t = pgBrowser.tree,
|
||||
|
||||
538
web/pgadmin/browser/server_groups/servers/static/js/server.ui.js
Normal file
538
web/pgadmin/browser/server_groups/servers/static/js/server.ui.js
Normal file
@@ -0,0 +1,538 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import _ from 'lodash';
|
||||
import {Address4, Address6} from 'ip-address';
|
||||
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import {default as supportedServers} from 'pgadmin.server.supported_servers';
|
||||
|
||||
import current_user from 'pgadmin.user_management.current_user';
|
||||
import { isEmptyString } from 'sources/validators';
|
||||
|
||||
export default class ServerSchema extends BaseUISchema {
|
||||
constructor(serverGroupOptions=[], initValues) {
|
||||
super({
|
||||
gid: undefined,
|
||||
id: undefined,
|
||||
name: '',
|
||||
bgcolor: '',
|
||||
fgcolor: '',
|
||||
sslmode: 'prefer',
|
||||
host: '',
|
||||
hostaddr: '',
|
||||
port: 5432,
|
||||
db: 'postgres',
|
||||
username: current_user.name,
|
||||
role: null,
|
||||
connect_now: true,
|
||||
password: undefined,
|
||||
save_password: false,
|
||||
db_res: '',
|
||||
passfile: undefined,
|
||||
sslcompression: false,
|
||||
sslcert: undefined,
|
||||
sslkey: undefined,
|
||||
sslrootcert: undefined,
|
||||
sslcrl: undefined,
|
||||
service: undefined,
|
||||
use_ssh_tunnel: 0,
|
||||
tunnel_host: undefined,
|
||||
tunnel_port: 22,
|
||||
tunnel_username: undefined,
|
||||
tunnel_identity_file: undefined,
|
||||
tunnel_password: undefined,
|
||||
tunnel_authentication: false,
|
||||
save_tunnel_password: false,
|
||||
connect_timeout: 10,
|
||||
...initValues,
|
||||
});
|
||||
|
||||
this.serverGroupOptions = serverGroupOptions;
|
||||
_.bindAll(this, 'isShared', 'isSSL');
|
||||
}
|
||||
|
||||
get SSL_MODES() { return ['prefer', 'require', 'verify-ca', 'verify-full']; }
|
||||
|
||||
isShared(state) {
|
||||
if(!this.isNew(state) && state.user_id != current_user.id && state.shared) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isConnected(state) {
|
||||
return Boolean(state.connected);
|
||||
}
|
||||
|
||||
isSSL(state) {
|
||||
return this.SSL_MODES.indexOf(state.sslmode) == -1;
|
||||
}
|
||||
|
||||
isValidLib() {
|
||||
// older version of libpq do not support 'passfile' parameter in
|
||||
// connect method, valid libpq must have version >= 100000
|
||||
return pgAdmin.Browser.utils.pg_libpq_version < 100000;
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
{
|
||||
id: 'id', label: gettext('ID'), type: 'int', group: null,
|
||||
mode: ['properties'],
|
||||
},{
|
||||
id: 'name', label: gettext('Name'), type: 'text', group: null,
|
||||
mode: ['properties', 'edit', 'create'], noEmpty: true,
|
||||
disabled: obj.isShared,
|
||||
},{
|
||||
id: 'gid', label: gettext('Server group'), type: 'select',
|
||||
options: obj.serverGroupOptions,
|
||||
mode: ['create', 'edit'],
|
||||
controlProps: { allowClear: false },
|
||||
disabled: obj.isShared,
|
||||
},
|
||||
{
|
||||
id: 'server_owner', label: gettext('Shared Server Owner'), type: 'text', mode: ['properties'],
|
||||
visible: function(state) {
|
||||
var serverOwner = state.user_id;
|
||||
if (state.shared && serverOwner != current_user.id && pgAdmin.server_mode == 'True'){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'server_type', label: gettext('Server type'), type: 'select',
|
||||
mode: ['properties'], visible: obj.isConnected,
|
||||
options: supportedServers,
|
||||
}, {
|
||||
id: 'connected', label: gettext('Connected?'), type: 'switch',
|
||||
mode: ['properties'], group: gettext('Connection'),
|
||||
}, {
|
||||
id: 'version', label: gettext('Version'), type: 'text', group: null,
|
||||
mode: ['properties'], visible: obj.isConnected,
|
||||
},
|
||||
{
|
||||
id: 'bgcolor', label: gettext('Background'), type: 'color',
|
||||
group: null, mode: ['edit', 'create'],
|
||||
disabled: obj.isConnected, deps: ['fgcolor'], depChange: (state)=>{
|
||||
if(!state.bgcolor && state.fgcolor) {
|
||||
return {'bgcolor': '#ffffff'};
|
||||
}
|
||||
}
|
||||
},{
|
||||
id: 'fgcolor', label: gettext('Foreground'), type: 'color',
|
||||
group: null, mode: ['edit', 'create'], disabled: obj.isConnected,
|
||||
},
|
||||
{
|
||||
id: 'connect_now', label: gettext('Connect now?'), type: 'switch',
|
||||
group: null, mode: ['create'],
|
||||
},
|
||||
{
|
||||
id: 'shared', label: gettext('Shared?'), type: 'switch',
|
||||
mode: ['properties', 'create', 'edit'],
|
||||
readonly: function(state){
|
||||
var serverOwner = state.user_id;
|
||||
if (obj.isNew(state) && serverOwner != current_user.id) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, visible: function(){
|
||||
if (current_user.is_admin && pgAdmin.server_mode == 'True')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'comment', label: gettext('Comments'), type: 'multiline', group: null,
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
},
|
||||
{
|
||||
id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], disabled: obj.isShared,
|
||||
depChange: (state)=>{
|
||||
if(obj.origData.host != state.host && !obj.isNew(state) && state.connected){
|
||||
obj.informText = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
obj.informText = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], min: 1, max: 65535, disabled: obj.isShared,
|
||||
depChange: (state)=>{
|
||||
if(obj.origData.port != state.port && !obj.isNew(state) && state.connected){
|
||||
obj.informText = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
obj.informText = undefined;
|
||||
}
|
||||
}
|
||||
},{
|
||||
id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected, disabled: obj.isShared,
|
||||
noEmpty: true,
|
||||
},{
|
||||
id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
depChange: (state)=>{
|
||||
if(obj.origData.username != state.username && !obj.isNew(state) && state.connected){
|
||||
obj.informText = gettext(
|
||||
'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'
|
||||
);
|
||||
} else {
|
||||
obj.informText = undefined;
|
||||
}
|
||||
}
|
||||
},{
|
||||
id: 'kerberos_conn', label: gettext('Kerberos authentication?'), type: 'switch',
|
||||
group: gettext('Connection'),
|
||||
},{
|
||||
id: 'gss_authenticated', label: gettext('GSS authenticated?'), type: 'switch',
|
||||
group: gettext('Connection'), mode: ['properties'], visible: obj.isConnected,
|
||||
},{
|
||||
id: 'gss_encrypted', label: gettext('GSS encrypted?'), type: 'switch',
|
||||
group: gettext('Connection'), mode: ['properties'], visible: obj.isConnected,
|
||||
},{
|
||||
id: 'password', label: gettext('Password'), type: 'password', maxlength: null,
|
||||
group: gettext('Connection'),
|
||||
mode: ['create'],
|
||||
deps: ['connect_now', 'kerberos_conn'],
|
||||
visible: function(state) {
|
||||
return state.connect_now && obj.isNew(state);
|
||||
},
|
||||
disabled: function(state) {return state.kerberos_conn;},
|
||||
},{
|
||||
id: 'save_password', label: gettext('Save password?'),
|
||||
type: 'switch', group: gettext('Connection'), mode: ['create'],
|
||||
deps: ['connect_now', 'kerberos_conn'],
|
||||
visible: function(state) {
|
||||
return state.connect_now && obj.isNew(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
if (!current_user.allow_save_password || state.kerberos_conn)
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
},{
|
||||
id: 'role', label: gettext('Role'), type: 'text', group: gettext('Connection'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,
|
||||
},{
|
||||
id: 'service', label: gettext('Service'), type: 'text',
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,
|
||||
group: gettext('Connection'),
|
||||
},
|
||||
{
|
||||
id: 'sslmode', label: gettext('SSL mode'), type: 'select', group: gettext('SSL'),
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
},
|
||||
mode: ['properties', 'edit', 'create'], disabled: obj.isConnected,
|
||||
options: [
|
||||
{label: gettext('Allow'), value: 'allow'},
|
||||
{label: gettext('Prefer'), value: 'prefer'},
|
||||
{label: gettext('Require'), value: 'require'},
|
||||
{label: gettext('Disable'), value: 'disable'},
|
||||
{label: gettext('Verify-CA'), value: 'verify-ca'},
|
||||
{label: gettext('Verify-Full'), value: 'verify-full'},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'sslcert', label: gettext('Client certificate'), type: 'file',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: obj.isSSL, readonly: obj.isConnected,
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
deps: ['sslmode'],
|
||||
},
|
||||
{
|
||||
id: 'sslkey', label: gettext('Client certificate key'), type: 'file',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: obj.isSSL, readonly: obj.isConnected,
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslrootcert', label: gettext('Root certificate'), type: 'file',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: obj.isSSL, readonly: obj.isConnected,
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
deps: ['sslmode'],
|
||||
},{
|
||||
id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'file',
|
||||
group: gettext('SSL'), mode: ['edit', 'create'],
|
||||
disabled: obj.isSSL, readonly: obj.isConnected,
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
deps: ['sslmode'],
|
||||
},
|
||||
{
|
||||
id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch',
|
||||
mode: ['edit', 'create'], group: gettext('SSL'),
|
||||
disabled: obj.isSSL, readonly: obj.isConnected,
|
||||
deps: ['sslmode'],
|
||||
},
|
||||
{
|
||||
id: 'sslcert', label: gettext('Client certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(state) {
|
||||
var sslcert = state.sslcert;
|
||||
return !_.isUndefined(sslcert) && !_.isNull(sslcert);
|
||||
},
|
||||
},{
|
||||
id: 'sslkey', label: gettext('Client certificate key'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(state) {
|
||||
var sslkey = state.sslkey;
|
||||
return !_.isUndefined(sslkey) && !_.isNull(sslkey);
|
||||
},
|
||||
},{
|
||||
id: 'sslrootcert', label: gettext('Root certificate'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(state) {
|
||||
var sslrootcert = state.sslrootcert;
|
||||
return !_.isUndefined(sslrootcert) && !_.isNull(sslrootcert);
|
||||
},
|
||||
},{
|
||||
id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'text',
|
||||
group: gettext('SSL'), mode: ['properties'],
|
||||
deps: ['sslmode'],
|
||||
visible: function(state) {
|
||||
var sslcrl = state.sslcrl;
|
||||
return !_.isUndefined(sslcrl) && !_.isNull(sslcrl);
|
||||
},
|
||||
},{
|
||||
id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch',
|
||||
mode: ['properties'], group: gettext('SSL'),
|
||||
deps: ['sslmode'],
|
||||
visible: function(state) {
|
||||
return _.indexOf(obj.SSL_MODES, state.sslmode) != -1;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'use_ssh_tunnel', label: gettext('Use SSH tunneling'), type: 'switch',
|
||||
mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),
|
||||
disabled: function() {
|
||||
return !pgAdmin.Browser.utils.support_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
},{
|
||||
id: 'tunnel_host', label: gettext('Tunnel host'), type: 'text', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
|
||||
disabled: function(state) {
|
||||
return !state.use_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
},{
|
||||
id: 'tunnel_port', label: gettext('Tunnel port'), type: 'int', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'], max: 65535,
|
||||
disabled: function(state) {
|
||||
return !state.use_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
},{
|
||||
id: 'tunnel_username', label: gettext('Username'), type: 'text', group: gettext('SSH Tunnel'),
|
||||
mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],
|
||||
disabled: function(state) {
|
||||
return !state.use_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
},{
|
||||
id: 'tunnel_authentication', label: gettext('Authentication'), type: 'toggle',
|
||||
mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),
|
||||
options: [
|
||||
{'label': gettext('Password'), value: false},
|
||||
{'label': gettext('Identity file'), value: true},
|
||||
],
|
||||
disabled: function(state) {
|
||||
return !state.use_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
},
|
||||
{
|
||||
id: 'tunnel_identity_file', label: gettext('Identity file'), type: 'file',
|
||||
group: gettext('SSH Tunnel'), mode: ['properties', 'edit', 'create'],
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
deps: ['tunnel_authentication', 'use_ssh_tunnel'],
|
||||
depChange: (state)=>{
|
||||
if (!state.tunnel_authentication && state.tunnel_identity_file) {
|
||||
return {tunnel_identity_file: null};
|
||||
}
|
||||
},
|
||||
disabled: function(state) {
|
||||
return !state.tunnel_authentication || !state.use_ssh_tunnel;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'tunnel_password', label: gettext('Password'), type: 'password',
|
||||
group: gettext('SSH Tunnel'), mode: ['create'],
|
||||
deps: ['use_ssh_tunnel'],
|
||||
disabled: function(state) {
|
||||
return !state.use_ssh_tunnel;
|
||||
},
|
||||
readonly: obj.isConnected,
|
||||
}, {
|
||||
id: 'save_tunnel_password', label: gettext('Save password?'),
|
||||
type: 'switch', group: gettext('SSH Tunnel'), mode: ['create'],
|
||||
deps: ['connect_now', 'use_ssh_tunnel'],
|
||||
visible: function(state) {
|
||||
return state.connect_now && obj.isNew(state);
|
||||
},
|
||||
disabled: function(state) {
|
||||
return (!current_user.allow_save_tunnel_password || !state.use_ssh_tunnel);
|
||||
},
|
||||
}, {
|
||||
id: 'hostaddr', label: gettext('Host address'), type: 'text', group: gettext('Advanced'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,
|
||||
},
|
||||
{
|
||||
id: 'db_res', label: gettext('DB restriction'), type: 'select', group: gettext('Advanced'),
|
||||
options: [],
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected, controlProps: {
|
||||
multiple: true, allowClear: false, creatable: true},
|
||||
},
|
||||
{
|
||||
id: 'passfile', label: gettext('Password file'), type: 'file',
|
||||
group: gettext('Advanced'), mode: ['edit', 'create'],
|
||||
disabled: obj.isValidLib, readonly: obj.isConnected,
|
||||
controlProps: {
|
||||
dialogType: 'select_file', supportedTypes: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'passfile', label: gettext('Password file'), type: 'text',
|
||||
group: gettext('Advanced'), mode: ['properties'],
|
||||
visible: function(state) {
|
||||
var passfile = state.passfile;
|
||||
return !_.isUndefined(passfile) && !_.isNull(passfile);
|
||||
},
|
||||
},{
|
||||
id: 'connect_timeout', label: gettext('Connection timeout (seconds)'),
|
||||
type: 'int', group: gettext('Advanced'),
|
||||
mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,
|
||||
min: 0,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
let errmsg = null;
|
||||
|
||||
if (isEmptyString(state.service)) {
|
||||
errmsg = gettext('Either Host name, Address or Service must be specified.');
|
||||
if(isEmptyString(state.host) && isEmptyString(state.hostaddr)) {
|
||||
setError('host', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('host', errmsg);
|
||||
setError('hostaddr', errmsg);
|
||||
}
|
||||
|
||||
/* IP address validate */
|
||||
if (state.hostaddr) {
|
||||
try {
|
||||
new Address4(state.hostaddr);
|
||||
} catch(e) {
|
||||
try {
|
||||
new Address6(state.hostaddr);
|
||||
} catch(ex) {
|
||||
errmsg = gettext('Host address must be valid IPv4 or IPv6 address.');
|
||||
setError('hostaddr', errmsg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setError('hostaddr', null);
|
||||
}
|
||||
|
||||
if(isEmptyString(state.username)) {
|
||||
errmsg = gettext('Username must be specified.');
|
||||
setError('username', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('username', errmsg);
|
||||
}
|
||||
|
||||
if(isEmptyString(state.port)) {
|
||||
errmsg = gettext('Port must be specified.');
|
||||
setError('port', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('port', errmsg);
|
||||
}
|
||||
} else {
|
||||
errmsg = null;
|
||||
_.each(['host', 'hostaddr', 'db', 'username', 'port'], (item) => {
|
||||
setError(item, errmsg);
|
||||
});
|
||||
}
|
||||
|
||||
if (state.use_ssh_tunnel) {
|
||||
if(isEmptyString(state.tunnel_host)) {
|
||||
errmsg = gettext('SSH Tunnel host must be specified.');
|
||||
setError('tunnel_host', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('tunnel_host', errmsg);
|
||||
}
|
||||
|
||||
if(isEmptyString(state.tunnel_port)) {
|
||||
errmsg = gettext('SSH Tunnel port must be specified.');
|
||||
setError('tunnel_port', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('tunnel_port', errmsg);
|
||||
}
|
||||
|
||||
if(isEmptyString(state.tunnel_username)) {
|
||||
errmsg = gettext('SSH Tunnel username must be specified.');
|
||||
setError('tunnel_username', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('tunnel_username', errmsg);
|
||||
}
|
||||
|
||||
if (state.tunnel_authentication) {
|
||||
if(isEmptyString(state.tunnel_identity_file)) {
|
||||
errmsg = gettext('SSH Tunnel identity file must be specified.');
|
||||
setError('tunnel_identity_file', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
errmsg = null;
|
||||
setError('tunnel_identity_file', errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import _ from 'lodash';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import { getNodeAjaxOptions, getNodeListByName } from '../../../../static/js/node_ajax';
|
||||
|
||||
export function getNodeVariableSchema(nodeObj, treeNodeInfo, itemNodeData, hasDatabase, hasRole) {
|
||||
let keys = ['name', 'value'];
|
||||
if(hasDatabase) {
|
||||
keys.push('database');
|
||||
}
|
||||
if(hasRole) {
|
||||
keys.push('role');
|
||||
}
|
||||
return new VariableSchema(
|
||||
()=>getNodeAjaxOptions('vopts', nodeObj, treeNodeInfo, itemNodeData, null, (vars)=>{
|
||||
var res = [];
|
||||
_.each(vars, function(v) {
|
||||
res.push({
|
||||
'value': v.name,
|
||||
'image': undefined,
|
||||
'label': v.name,
|
||||
'vartype': v.vartype,
|
||||
'enumvals': v.enumvals,
|
||||
'max_val': v.max_val,
|
||||
'min_val': v.min_val,
|
||||
});
|
||||
});
|
||||
|
||||
return res;
|
||||
}),
|
||||
()=>getNodeListByName('database', treeNodeInfo, itemNodeData),
|
||||
()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
keys
|
||||
);
|
||||
}
|
||||
|
||||
export default class VariableSchema extends BaseUISchema {
|
||||
constructor(vnameOptions, databaseOptions, roleOptions, keys) {
|
||||
super({
|
||||
name: undefined,
|
||||
value: undefined,
|
||||
role: null,
|
||||
database: null,
|
||||
});
|
||||
this.vnameOptions = vnameOptions;
|
||||
this.databaseOptions = databaseOptions;
|
||||
this.roleOptions = roleOptions;
|
||||
this.varTypes = {};
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
setVarTypes(options) {
|
||||
options.forEach((option)=>{
|
||||
this.varTypes[option.value] = {
|
||||
...option,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getValueFieldProps(variable) {
|
||||
switch(variable?.vartype) {
|
||||
case 'bool':
|
||||
return 'switch';
|
||||
case 'enum':
|
||||
return {
|
||||
cell: 'select',
|
||||
options: (variable.enumvals || []).map((val)=>({
|
||||
label: val,
|
||||
value: val
|
||||
}))
|
||||
};
|
||||
case 'integer':
|
||||
return 'int';
|
||||
case 'real':
|
||||
return 'number';
|
||||
case 'string':
|
||||
return 'text';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
{
|
||||
id: 'id', label: gettext('ID'), type: 'int', group: null,
|
||||
mode: ['properties'],
|
||||
},
|
||||
{
|
||||
id: 'name', label: gettext('Name'), type:'text',
|
||||
readonly: function(state) {
|
||||
return !obj.isNew(state);
|
||||
},
|
||||
cell: ()=>({
|
||||
cell: 'select',
|
||||
options: this.vnameOptions,
|
||||
optionsLoaded: (options)=>{obj.setVarTypes(options);},
|
||||
controlProps: { allowClear: false },
|
||||
}),
|
||||
noEmpty: true,
|
||||
},
|
||||
{
|
||||
id: 'value', label: gettext('Value'), type: 'text',
|
||||
noEmpty: true, deps: ['name'],
|
||||
depChange: (state, changeSource)=>{
|
||||
if(changeSource == 'name') {
|
||||
return {...state
|
||||
, value: null
|
||||
};
|
||||
}
|
||||
},
|
||||
cell: (row)=>{
|
||||
let variable = this.varTypes[row.name];
|
||||
return this.getValueFieldProps(variable);
|
||||
}
|
||||
},
|
||||
{id: 'database', label: gettext('Database'), type: 'text',
|
||||
cell: ()=>({cell: 'select', options: this.databaseOptions }),
|
||||
},
|
||||
{id: 'role', label: gettext('Role'), type: 'text',
|
||||
cell: ()=>({cell: 'select', options: this.roleOptions,
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
}
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user