Port Synonyms node to react. Fixes #6599
parent
47855eae0b
commit
5c1ce23780
|
@ -7,6 +7,9 @@
|
|||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../../static/js/node_ajax';
|
||||
import SynonymSchema from './synonym.ui';
|
||||
|
||||
define('pgadmin.node.synonym', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.alertifyjs',
|
||||
|
@ -68,6 +71,35 @@ define('pgadmin.node.synonym', [
|
|||
]);
|
||||
|
||||
},
|
||||
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return new SynonymSchema(
|
||||
{
|
||||
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
schema: ()=>getNodeListByName('schema', treeNodeInfo, itemNodeData, {
|
||||
cacheLevel: 'database',
|
||||
cacheNode: 'database'
|
||||
}),
|
||||
synobjschema: ()=>getNodeListByName('schema', treeNodeInfo, itemNodeData, {}, (m)=>{
|
||||
// Exclude PPAS catalogs
|
||||
var exclude_catalogs = ['pg_catalog', 'sys', 'dbo', 'pgagent', 'information_schema', 'dbms_job_procedure'];
|
||||
return m && _.indexOf(exclude_catalogs, m.label) == -1;
|
||||
}),
|
||||
getTargetObjectOptions: (targettype, synobjschema) =>
|
||||
{
|
||||
return getNodeAjaxOptions('get_target_objects', this, treeNodeInfo,
|
||||
itemNodeData, {urlParams: {'trgTyp' : targettype, 'trgSchema' : synobjschema}, useCache: false});
|
||||
},
|
||||
},
|
||||
treeNodeInfo,
|
||||
{
|
||||
owner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
|
||||
schema: itemNodeData.label,
|
||||
synobjschema: itemNodeData.label,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
isNew: function() {
|
||||
return !this.fetchFromServer;
|
||||
|
@ -104,123 +136,8 @@ define('pgadmin.node.synonym', [
|
|||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
readonly: true , control: 'node-list-by-name',
|
||||
node: 'role', visible: false,
|
||||
},{
|
||||
id: 'schema', label: gettext('Schema'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
readonly: function(m) { return !m.isNew(); }, node: 'schema',
|
||||
control: 'node-list-by-name', cache_node: 'database',
|
||||
cache_level: 'database',
|
||||
},{
|
||||
id: 'targettype', label: gettext('Target type'), cell: 'string',
|
||||
disabled: 'inSchema', group: gettext('Definition'),
|
||||
select2: { width: '50%', allowClear: false },
|
||||
options: function() {
|
||||
return [
|
||||
{label: gettext('Function'), value: 'f'},
|
||||
{label: gettext('Package'), value: 'P'},
|
||||
{label: gettext('Procedure'), value: 'p'},
|
||||
{label: gettext('Public Synonym'), value: 's'},
|
||||
{label: gettext('Sequence'), value: 'S'},
|
||||
{label: gettext('Table'), value: 'r'},
|
||||
{label: gettext('View'), value: 'v'},
|
||||
];
|
||||
},
|
||||
control: 'select2',
|
||||
},{
|
||||
id: 'synobjschema', label: gettext('Target schema'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
group: gettext('Definition'), deps: ['targettype'],
|
||||
select2: { allowClear: false }, control: 'node-list-by-name',
|
||||
node: 'schema', filter: function(d) {
|
||||
// Exclude PPAS catalogs
|
||||
var exclude_catalogs = ['pg_catalog', 'sys', 'dbo',
|
||||
'pgagent', 'information_schema',
|
||||
'dbms_job_procedure'];
|
||||
return d && _.indexOf(exclude_catalogs, d.label) == -1;
|
||||
},
|
||||
disabled: function(m) {
|
||||
// If tagetType is synonym then disable it
|
||||
if(!m.inSchema.apply(this, [m])) {
|
||||
var is_synonym = (m.get('targettype') == 's');
|
||||
if(is_synonym) {
|
||||
m.set('synobjschema', 'public', {silent: true});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},{
|
||||
id: 'synobjname', label: gettext('Target object'), cell: 'string',
|
||||
type: 'text', group: gettext('Definition'),
|
||||
deps: ['targettype', 'synobjschema'],
|
||||
control: 'node-ajax-options',
|
||||
options: function(control) {
|
||||
var trgTyp = control.model.get('targettype');
|
||||
var trgSchema = control.model.get('synobjschema');
|
||||
var res = [];
|
||||
var node = control.field.get('schema_node'),
|
||||
_url = node.generate_url.apply(
|
||||
node, [
|
||||
null, 'get_target_objects', control.field.get('node_data'), false,
|
||||
control.field.get('node_info') ]);
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
timeout: 30000,
|
||||
url: _url,
|
||||
cache: false,
|
||||
async: false,
|
||||
data: {'trgTyp' : trgTyp, 'trgSchema' : trgSchema},
|
||||
})
|
||||
// On success return function list from server
|
||||
.done(function(result) {
|
||||
res = result.data;
|
||||
return res;
|
||||
})
|
||||
// On failure show error appropriate error message to user
|
||||
.fail(function(xhr, status, error) {
|
||||
alertify.pgRespErrorNotify(xhr, error);
|
||||
});
|
||||
return res;
|
||||
},
|
||||
disabled: function(m) {
|
||||
if (this.node_info && 'catalog' in this.node_info) {
|
||||
return true;
|
||||
}
|
||||
// Check the changed attributes if targettype or synobjschema
|
||||
// is changed then reset the target object
|
||||
if ('changed' in m && !('name' in m.changed) &&
|
||||
('targettype' in m.changed || 'synobjschema' in m.changed)) {
|
||||
m.set('synobjname', undefined);
|
||||
}
|
||||
}],
|
||||
|
||||
return false;
|
||||
},
|
||||
},{
|
||||
id: 'is_sys_obj', label: gettext('System synonym?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
},
|
||||
],
|
||||
validate: function() {
|
||||
var msg = undefined;
|
||||
this.errorModel.clear();
|
||||
|
||||
if (_.isUndefined(this.get('name'))
|
||||
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Name cannot be empty.');
|
||||
this.errorModel.set('name', msg);
|
||||
} else if (_.isUndefined(this.get('synobjschema'))
|
||||
|| String(this.get('synobjschema')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Target schema cannot be empty.');
|
||||
this.errorModel.set('synobjschema', msg);
|
||||
} else if (_.isUndefined(this.get('synobjname'))
|
||||
|| String(this.get('synobjname')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Target object cannot be empty.');
|
||||
this.errorModel.set('synobjname', msg);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// We will disable everything if we are under catalog node
|
||||
inSchema: function() {
|
||||
if(this.node_info && 'catalog' in this.node_info)
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 { emptyValidator } from 'sources/validators';
|
||||
|
||||
export default class SynonymSchema extends BaseUISchema {
|
||||
constructor(fieldOptions={}, nodeInfo, initValues) {
|
||||
super({
|
||||
targettype: 'r',
|
||||
...initValues,
|
||||
});
|
||||
this.fieldOptions = fieldOptions;
|
||||
this.nodeInfo = nodeInfo;
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
{
|
||||
id: 'name', label: gettext('Name'), cell: 'text',
|
||||
type: 'text', mode: ['properties', 'create', 'edit'],
|
||||
readonly: function(state) { return !obj.isNew(state); },
|
||||
}, {
|
||||
id: 'oid', label: gettext('OID'), cell: 'text',
|
||||
type: 'text', mode: ['properties'],
|
||||
}, {
|
||||
id: 'owner', label: gettext('Owner'),
|
||||
options: this.fieldOptions.role,
|
||||
controlProps: { allowClear: false, editable: false},
|
||||
type: 'select', mode: ['properties', 'create', 'edit'],
|
||||
readonly: true , visible: false,
|
||||
}, {
|
||||
id: 'schema', label: gettext('Schema'),
|
||||
type: 'select', mode: ['properties', 'create', 'edit'],
|
||||
options: this.fieldOptions.schema,
|
||||
controlProps: { allowClear: false, editable: false },
|
||||
readonly: function(state) { return !obj.isNew(state); },
|
||||
}, {
|
||||
id: 'targettype', label: gettext('Target type'),
|
||||
readonly: this.inSchema, group: gettext('Definition'),
|
||||
controlProps: { allowClear: false },
|
||||
type: 'select',
|
||||
options: [
|
||||
{label: gettext('Function'), value: 'f'},
|
||||
{label: gettext('Package'), value: 'P'},
|
||||
{label: gettext('Procedure'), value: 'p'},
|
||||
{label: gettext('Public Synonym'), value: 's'},
|
||||
{label: gettext('Sequence'), value: 'S'},
|
||||
{label: gettext('Table'), value: 'r'},
|
||||
{label: gettext('View'), value: 'v'}
|
||||
]
|
||||
}, {
|
||||
id: 'synobjschema', label: gettext('Target schema'),
|
||||
type: 'select', mode: ['properties', 'create', 'edit'],
|
||||
group: gettext('Definition'), deps: ['targettype'],
|
||||
controlProps: { allowClear: false},
|
||||
options: this.fieldOptions.synobjschema,
|
||||
readonly: function(state) {
|
||||
// If tagetType is synonym then disable it
|
||||
if(!obj.inSchema()) {
|
||||
if(state.targettype == 's') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
depChange: function(state) {
|
||||
if(!obj.inSchema() && state.targettype == 's') {
|
||||
return { synobjschema: 'public'};
|
||||
}
|
||||
}
|
||||
}, {
|
||||
id: 'synobjname', label: gettext('Target object'),
|
||||
group: gettext('Definition'),
|
||||
deps: ['targettype', 'synobjschema'],
|
||||
type: (state)=>{
|
||||
let fetchOptionsBasis = state.targettype + state.synobjschema;
|
||||
return {
|
||||
type: 'select',
|
||||
options: ()=>obj.fieldOptions.getTargetObjectOptions(state.targettype, state.synobjschema),
|
||||
optionsReloadBasis: fetchOptionsBasis,
|
||||
};
|
||||
},
|
||||
readonly: function() {
|
||||
if(!obj.inSchema()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
id: 'is_sys_obj', label: gettext('System synonym?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
let errmsg = null;
|
||||
|
||||
errmsg = emptyValidator('Name', state.name);
|
||||
if (errmsg) {
|
||||
setError('name', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
setError('name', errmsg);
|
||||
}
|
||||
|
||||
errmsg = emptyValidator('Target schema', state.synobjschema);
|
||||
if (errmsg) {
|
||||
setError('synobjschema', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
setError('synobjschema', errmsg);
|
||||
}
|
||||
|
||||
errmsg = emptyValidator('Target object', state.synobjname);
|
||||
if (errmsg) {
|
||||
setError('synobjname', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
setError('synobjname', errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
inSchema() {
|
||||
if(this.nodeInfo && 'catalog' in this.nodeInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -64,6 +64,7 @@ export function getNodeAjaxOptions(url, nodeObj, treeNodeInfo, itemNodeData, par
|
|||
let otherParams = {
|
||||
urlWithId: false,
|
||||
jumpAfterNode: null,
|
||||
useCache: true,
|
||||
...params
|
||||
};
|
||||
return new Promise((resolve, reject)=>{
|
||||
|
@ -91,7 +92,7 @@ export function getNodeAjaxOptions(url, nodeObj, treeNodeInfo, itemNodeData, par
|
|||
})
|
||||
.then((res)=>{
|
||||
data = res.data.data;
|
||||
cacheNode.cache(nodeObj.type + '#' + url, treeNodeInfo, cacheLevel, data);
|
||||
otherParams.useCache && cacheNode.cache(nodeObj.type + '#' + url, treeNodeInfo, cacheLevel, data);
|
||||
resolve(transform(data));
|
||||
})
|
||||
.catch((err)=>{
|
||||
|
|
|
@ -116,9 +116,7 @@ export default function FormView({
|
|||
|
||||
visible = _.isUndefined(visible) ? true : visible;
|
||||
let _visible = true;
|
||||
if(visible) {
|
||||
_visible = evalFunc(schema, visible, value);
|
||||
}
|
||||
_visible = evalFunc(schema, visible, value);
|
||||
_visible = _visible && verInLimit;
|
||||
|
||||
disabled = evalFunc(schema, disabled, value);
|
||||
|
|
|
@ -597,6 +597,7 @@ function SchemaPropertiesView({
|
|||
<MappedFormControl
|
||||
key={field.id}
|
||||
viewHelperProps={viewHelperProps}
|
||||
state={origData}
|
||||
name={field.id}
|
||||
value={origData[field.id]}
|
||||
readonly={readonly}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import jasmineEnzyme from 'jasmine-enzyme';
|
||||
import React from 'react';
|
||||
import '../helper/enzyme.helper';
|
||||
import { createMount } from '@material-ui/core/test-utils';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import {messages} from '../fake_messages';
|
||||
import SchemaView from '../../../pgadmin/static/js/SchemaView';
|
||||
import SynonymSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/synonyms/static/js/synonym.ui';
|
||||
|
||||
describe('SynonymSchema', ()=>{
|
||||
let mount;
|
||||
let schemaObj = new SynonymSchema(
|
||||
{
|
||||
role: ()=>[],
|
||||
schema: ()=>[],
|
||||
synobjschema: ()=>[],
|
||||
getTargetObjectOptions: ()=>[],
|
||||
},
|
||||
[],
|
||||
{
|
||||
owner: 'postgres',
|
||||
schema: 'public',
|
||||
synobjschema: 'public',
|
||||
}
|
||||
);
|
||||
let getInitData = ()=>Promise.resolve({});
|
||||
|
||||
/* Use createMount so that material ui components gets the required context */
|
||||
/* https://material-ui.com/guides/testing/#api */
|
||||
beforeAll(()=>{
|
||||
mount = createMount();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mount.cleanUp();
|
||||
});
|
||||
|
||||
beforeEach(()=>{
|
||||
jasmineEnzyme();
|
||||
/* messages used by validators */
|
||||
pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
|
||||
pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
|
||||
});
|
||||
|
||||
it('create', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('edit', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('properties', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='tab'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'properties',
|
||||
}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('validate', ()=>{
|
||||
let state = {};
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
state.name = null;
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('name', '\'Name\' cannot be empty.');
|
||||
|
||||
state.name = 'my_syn';
|
||||
state.synobjschema = null;
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('synobjschema', '\'Target schema\' cannot be empty.');
|
||||
|
||||
state.synobjschema = 'public';
|
||||
state.synobjname = null;
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('synobjname', '\'Target object\' cannot be empty.');
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue