Port Collation node to react. Fixes #6584.

This commit is contained in:
Yogesh Mahajan 2021-07-15 14:32:57 +05:30 committed by Akshay Joshi
parent a06f78b2d5
commit 6fe83d1f06
3 changed files with 331 additions and 131 deletions

View File

@ -7,6 +7,9 @@
//
//////////////////////////////////////////////////////////////
import CollationSchema from './collation.ui';
import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../../static/js/node_ajax';
define('pgadmin.node.collation', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/pgadmin', 'pgadmin.browser',
@ -68,14 +71,6 @@ define('pgadmin.node.collation', [
},
model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: {
name: undefined,
oid: undefined,
owner: undefined,
lc_type: undefined,
lc_collate: undefined,
description: undefined,
},
// Default values!
initialize: function(attrs, args) {
@ -103,136 +98,29 @@ define('pgadmin.node.collation', [
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', control: 'node-list-by-name',
node: 'role',
},{
id: 'schema', label: gettext('Schema'), cell: 'string',
type: 'text', mode: ['create', 'edit'], node: 'schema',
disabled: 'inSchema', filter: function(d) {
// If schema name start with pg_* then we need to exclude them
if(d && d.label.match(/^pg_/))
{
return false;
}
return true;
}, control: 'node-list-by-name',
cache_node: 'database', cached_level: 'database',
},{
id: 'copy_collation', label: gettext('Copy collation'), cell: 'string',
control: 'node-ajax-options',
type: 'text', mode: ['create', 'edit'], group: gettext('Definition'),
url: 'get_collations', disabled: 'inSchemaWithModelCheck',
readonly: function(m) {return !m.isNew;},
deps: ['locale', 'lc_collate', 'lc_type'],
},{
id: 'locale', label: gettext('Locale'), cell: 'string',
type: 'text', mode: ['create', 'edit'], group: gettext('Definition'),
disabled: 'inSchemaWithModelCheck', readonly: function(m) {return !m.isNew;},
deps: ['lc_collate', 'lc_type', 'copy_collation'],
},{
id: 'lc_collate', label: gettext('LC_COLLATE'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'], group: gettext('Definition'),
deps: ['locale', 'copy_collation'], disabled: 'inSchemaWithModelCheck',
readonly: function(m) {return !m.isNew;},
},{
id: 'lc_type', label: gettext('LC_TYPE'), cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'], group: gettext('Definition'),
disabled: 'inSchemaWithModelCheck', readonly: function(m) {return !m.isNew;},
deps: ['locale', 'copy_collation'],
},{
id: 'is_sys_obj', label: gettext('System collation?'),
cell:'boolean', type: 'switch', mode: ['properties'],
},{
id: 'description', label: gettext('Comment'), cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema',
},
}
],
validate: function() {
var err = {},
msg = undefined,
changedAttrs = this.changed,
locale_flag = false,
lc_type_flag = false,
lc_coll_flag = false,
copy_coll_flag = false,
data = this.toJSON();
this.errorModel.clear();
if (_.has(changedAttrs,data.name) && _.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = gettext('Name cannot be empty.');
this.errorModel.set('name', msg);
}
if (_.has(changedAttrs,data.locale) && (_.isUndefined(this.get('locale'))
|| String(this.get('locale')).replace(/^\s+|\s+$/g, '') == '')) {
locale_flag = true;
}
if (_.has(changedAttrs,data.lc_collate) && (_.isUndefined(this.get('lc_collate'))
|| String(this.get('lc_collate')).replace(/^\s+|\s+$/g, '') == '')) {
lc_coll_flag = true;
}
if (_.has(changedAttrs,data.lc_type) && (_.isUndefined(this.get('lc_type'))
|| String(this.get('lc_type')).replace(/^\s+|\s+$/g, '') == '')) {
lc_type_flag = true;
}
if (_.has(changedAttrs,data.copy_collation) && (_.isUndefined(this.get('copy_collation'))
|| String(this.get('copy_collation')).replace(/^\s+|\s+$/g, '') == '')) {
copy_coll_flag = true;
}
if (locale_flag && (lc_coll_flag || lc_type_flag) && copy_coll_flag) {
msg = gettext('Definition incomplete. Please provide Locale OR Copy Collation OR LC_TYPE/LC_COLLATE.');
err['locale'] = msg;
}
return null;
},
// We will disable everything if we are under catalog node
inSchema: function() {
if(this.node_info && 'catalog' in this.node_info)
{
return true;
}
return false;
},
// We will check if we are under schema node & in 'create' mode
inSchemaWithModelCheck: function(m) {
if(this.node_info && 'schema' in this.node_info)
{
// Enable copy_collation only if locale & lc_* is not provided
if (m.isNew() && this.name == 'copy_collation')
{
if(m.get('locale'))
return true;
if(m.get('lc_collate') || m.get('lc_type'))
return true;
return false;
}
// Enable lc_* only if copy_collation & locale is not provided
if (m.isNew() && (this.name == 'lc_collate' || this.name == 'lc_type'))
{
if(m.get('locale'))
return true;
if(m.get('copy_collation'))
return true;
return false;
}
// Enable localy only if lc_* & copy_collation is not provided
if (m.isNew() && this.name == 'locale')
{
if(m.get('lc_collate') || m.get('lc_type'))
return true;
if(m.get('copy_collation'))
return true;
return false;
}
}
return true;
},
}),
getSchema: (treeNodeInfo, itemNodeData)=>{
let nodeObj = pgAdmin.Browser.Nodes['collation'];
let schema = new CollationSchema(
{
rolesList: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData, {cacheLevel: 'server'}),
schemaList: ()=>getNodeListByName('schema', treeNodeInfo, itemNodeData, {cacheLevel: 'database'}),
collationsList: ()=>getNodeAjaxOptions('get_collations', nodeObj, treeNodeInfo, itemNodeData, {cacheLevel: 'server'})
},
{
owner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
schema: ('schema' in treeNodeInfo)? treeNodeInfo.schema.label : ''
}
);
return schema;
}
});
}
return pgBrowser.Nodes['collation'];
});

View File

@ -0,0 +1,171 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import gettext from 'sources/gettext';
import { isEmptyString } from 'sources/validators';
export default class CollationSchema extends BaseUISchema {
constructor(fieldOptions = {},initValues) {
super({
name: undefined,
oid: undefined,
owner: undefined,
copy_collation: null,
locale: undefined,
lc_type: undefined,
lc_collate: undefined,
description: undefined,
schema: null,
...initValues
});
this.schemaList = fieldOptions.schemaList;
this.ownerList = fieldOptions.rolesList;
this.collationsList = fieldOptions.collationsList;
}
get idAttribute() {
return 'oid';
}
get baseFields() {
let obj = this;
return [
{
id: 'name', label: gettext('Name'),
type: 'text', mode: ['properties', 'create', 'edit'],
},
{
id: 'oid', label: gettext('OID'),
type: 'text', mode: ['properties'],
},
{
id: 'owner', label: gettext('Owner'),
type: 'select', mode: ['properties', 'create', 'edit'],
options: obj.ownerList
},
{
id: 'schema', label: gettext('Schema'),
mode: ['create', 'edit'], node: 'schema',
type: () => {
return {
type: 'select',
options: obj.schemaList,
controlProps: {
filter: (options) => {
let res = [];
options.forEach((d) => {
if (!(d && d.label.match(/^pg_/)))
res.push(d);
});
return res;
}
}
};
}
},
{
id: 'copy_collation', label: gettext('Copy collation'),
type: 'select', mode: ['create', 'edit'], group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
options: obj.collationsList,
disabled: function (state) {
// Enable copy_collation only if locale & lc_* is not provided
if (state.locale)
return true;
if (state.lc_collate || state.lc_type)
return true;
return false;
},
deps: ['locale', 'lc_collate', 'lc_type'],
},
{
id: 'locale', label: gettext('Locale'),
type: 'text', mode: ['create', 'edit'], group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
deps: ['lc_collate', 'lc_type', 'copy_collation'],
disabled: function (state) {
// Enable localy only if lc_* & copy_collation is not provided
if (state.lc_collate || state.lc_type)
return true;
if (state.copy_collation)
return true;
return false;
}
},
{
id: 'lc_collate', label: gettext('LC_COLLATE'),
type: 'text', mode: ['properties', 'create', 'edit'], group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
disabled: obj.disableFields,
deps: ['locale', 'copy_collation'],
},
{
id: 'lc_type', label: gettext('LC_TYPE'),
type: 'text', mode: ['properties', 'create', 'edit'], group: gettext('Definition'),
readonly: function (state) { return !obj.isNew(state); },
disabled: obj.disableFields,
deps: ['locale', 'copy_collation'],
},
{
id: 'is_sys_obj', label: gettext('System collation?'),
cell: 'boolean', type: 'switch', mode: ['properties'],
},
{
id: 'description', label: gettext('Comment'),
type: 'multiline', mode: ['properties', 'create', 'edit'],
}
];
}
disableFields(state) {
// Enable lc_* only if copy_collation & locale is not provided
if (state.locale || state.copy_collation) {
if (state.locale)
return true;
if (state.copy_collation)
return true;
}
return false;
}
validate(state, setError) {
let errmsg = null,
locale_flag = false,
lc_type_flag = false,
lc_coll_flag = false,
copy_coll_flag = false;
if (isEmptyString(state.name)) {
errmsg = gettext('Name cannot be empty.');
setError('name', errmsg);
return true;
}
if (isEmptyString(state.locale)) {
locale_flag = true;
}
if (isEmptyString(state.copy_collation)) {
copy_coll_flag = true;
}
if (isEmptyString(state.lc_collate)) {
lc_coll_flag = true;
}
if (isEmptyString(state.lc_type)) {
lc_type_flag = true;
}
if (locale_flag && (lc_coll_flag || lc_type_flag) && copy_coll_flag) {
errmsg = gettext('Definition incomplete. Please provide Locale OR Copy Collation OR LC_TYPE/LC_COLLATE.');
setError('copy_collation', errmsg);
return true;
}
return null;
}
}

View File

@ -0,0 +1,141 @@
/////////////////////////////////////////////////////////////
//
// 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';
// web/pgadmin/browser/server_groups/servers/databases/schemas/collations/static/js/collation.ui.js
import CollationSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/collations/static/js/collation.ui';
describe('CollationsSchema', () => {
let mount;
let schemaObj = new CollationSchema(
{
rolesList: () => [],
schemaList: () => [],
collationsList: () => []
},
{
owner: 'postgres',
schema: ''
}
);
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: 'create',
}}
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;
state.locale = 'locale';
schemaObj.validate(state, setError);
expect(setError).toHaveBeenCalledWith('name', 'Name cannot be empty.');
state.name = 'test';
state.copy_collation = null;
state.lc_type = null;
state.lc_collate = null;
state.locale = null;
schemaObj.validate(state, setError);
expect(setError).toHaveBeenCalledWith('copy_collation', 'Definition incomplete. Please provide Locale OR Copy Collation OR LC_TYPE/LC_COLLATE.');
});
it('disableFields',() => {
let state = {};
state.name = 'test';
state.locale = 'locale';
expect(schemaObj.disableFields(state)).toBeTrue();
state.name = 'test';
state.copy_collation = 'copy_collation';
state.locale = null;
expect(schemaObj.disableFields(state)).toBeTrue();
state.name = 'test';
state.copy_collation = null;
state.locale = null;
expect(schemaObj.disableFields(state)).toBeFalse();
});
});