mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
Port FTS Configurations node to react. Fixes #6638
This commit is contained in:
parent
42eac6f846
commit
4bfffa3806
@ -7,6 +7,9 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getNodeAjaxOptions, getNodeListByName, getNodeListById} from '../../../../../../../static/js/node_ajax';
|
||||
import FTSConfigurationSchema from './fts_configuration.ui';
|
||||
|
||||
define('pgadmin.node.fts_configuration', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
@ -17,398 +20,6 @@ define('pgadmin.node.fts_configuration', [
|
||||
schemaChild, schemaChildTreeNode
|
||||
) {
|
||||
|
||||
// Model for tokens control
|
||||
var TokenModel = pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'token',
|
||||
defaults: {
|
||||
token: undefined,
|
||||
dictname: undefined,
|
||||
},
|
||||
keys: ['token'],
|
||||
// Define the schema for the token/dictionary list
|
||||
schema: [{
|
||||
id: 'token', label: gettext('Token'), type:'text', group: null,
|
||||
cellHeaderClasses:'width_percent_50',
|
||||
editable: false, cell: 'string', url: 'tokens',
|
||||
},{
|
||||
id: 'dictname', label: gettext('Dictionaries'), type: 'text', group:null,
|
||||
cellHeaderClasses:'width_percent_50', editable: true,
|
||||
cell:Backgrid.Extension.MultiSelectAjaxCell, url: 'dictionaries',
|
||||
cache_level:'fts_configuration', cache_node:'fts_configuration',
|
||||
}],
|
||||
// Validation for token and dictionary list
|
||||
validate: function() {
|
||||
// Clear any existing errors.
|
||||
var msg;
|
||||
this.errorModel.clear();
|
||||
var token = this.get('token');
|
||||
var dictionary = this.get('dictname');
|
||||
|
||||
if (_.isNull(token) ||
|
||||
_.isUndefined(token) ||
|
||||
String(token).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Token cannot be empty.');
|
||||
this.errorModel.set('token',msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (_.isNull(dictionary) ||
|
||||
_.isUndefined(dictionary) ||
|
||||
String(dictionary).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Dictionary name cannot be empty.');
|
||||
this.errorModel.set('dictname',msg);
|
||||
return msg;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
// Customized control for token control
|
||||
var TokenControl = Backform.TokenControl =
|
||||
Backform.UniqueColCollectionControl.extend({
|
||||
|
||||
initialize: function() {
|
||||
Backform.UniqueColCollectionControl.prototype.initialize.apply(
|
||||
this, arguments
|
||||
);
|
||||
|
||||
var self = this,
|
||||
headerSchema = [{
|
||||
id: 'token', label:'', type:'text', url: 'tokens',
|
||||
node:'fts_configuration', canAdd: true, 'url_with_id': true,
|
||||
|
||||
// Defining control for tokens dropdown control in header
|
||||
control: Backform.NodeAjaxOptionsControl.extend({
|
||||
formatter: Backform.NodeAjaxOptionsControl.prototype.formatter,
|
||||
initialize: function() {
|
||||
Backform.NodeAjaxOptionsControl.prototype.initialize.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
var _self = this,
|
||||
url = _self.field.get('url') || _self.defaults.url,
|
||||
m = _self.model.top || _self.model;
|
||||
|
||||
/* Fetch the tokens/dict list from '_self' node.
|
||||
* Here '_self' refers to unique collection control where
|
||||
* '_self' refers to nodeAjaxOptions control for dictionary
|
||||
*/
|
||||
if (url) {
|
||||
var node = this.field.get('schema_node'),
|
||||
node_info = this.field.get('node_info'),
|
||||
full_url = node.generate_url.apply(
|
||||
node, [
|
||||
null, url, this.field.get('node_data'),
|
||||
this.field.get('url_with_id') || false,
|
||||
node_info,
|
||||
]),
|
||||
cache_level = this.field.get('cache_level') || node.type,
|
||||
cache_node = this.field.get('cache_node');
|
||||
|
||||
cache_node = (cache_node &&
|
||||
pgAdmin.Browser.Nodes[cache_node])
|
||||
|| node;
|
||||
|
||||
// Clear the cache to get the latest dictionaries and parsers.
|
||||
cache_node.clear_cache(this);
|
||||
|
||||
/*
|
||||
* We needs to check, if we have already cached data
|
||||
* for this url. If yes - use it, and do not bother about
|
||||
* fetching it again.
|
||||
*/
|
||||
var data = cache_node.cache(url, node_info, cache_level);
|
||||
|
||||
// Fetch token/dictionary list
|
||||
if (this.field.get('version_compatible') &&
|
||||
(_.isUndefined(data) || _.isNull(data))) {
|
||||
m.trigger('pgadmin:view:fetching', m, _self.field);
|
||||
$.ajax({
|
||||
async: false,
|
||||
url: full_url,
|
||||
})
|
||||
.done(function(res) {
|
||||
/*
|
||||
* We will cache this data for short period of time for
|
||||
* avoiding same calls.
|
||||
*/
|
||||
data = cache_node.cache(url,
|
||||
node_info,
|
||||
cache_level,
|
||||
res.data
|
||||
);
|
||||
})
|
||||
.fail(function() {
|
||||
m.trigger('pgadmin:view:fetch:error', m, _self.field);
|
||||
});
|
||||
m.trigger('pgadmin:view:fetched', m, _self.field);
|
||||
}
|
||||
|
||||
// It is feasible that the data may not have been fetched.
|
||||
data = (data && data.data) || [];
|
||||
|
||||
/*
|
||||
* Transform the data
|
||||
*/
|
||||
var transform = (this.field.get('transform')
|
||||
|| _self.defaults.transform);
|
||||
if (transform && _.isFunction(transform)) {
|
||||
_self.field.set('options', transform.bind(_self, data));
|
||||
} else {
|
||||
_self.field.set('options', data);
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
// Select2 control for adding new tokens
|
||||
select2: {
|
||||
allowClear: true, width: 'style',
|
||||
placeholder: gettext('Select token'),
|
||||
},
|
||||
first_empty: true,
|
||||
disabled: function() {
|
||||
return _.isUndefined(self.model.get('oid'));
|
||||
},
|
||||
}],
|
||||
headerDefaults = {token: null},
|
||||
// Grid columns backgrid
|
||||
gridCols = ['token', 'dictname'];
|
||||
|
||||
// Creating model for header control which is used to add new tokens
|
||||
self.headerData = new (Backbone.Model.extend({
|
||||
defaults: headerDefaults,
|
||||
schema: headerSchema,
|
||||
}))({});
|
||||
|
||||
// Creating view from header schema in tokens control
|
||||
var headerGroups = Backform.generateViewSchema(
|
||||
self.field.get('node_info'), self.headerData, 'create',
|
||||
self.field.get('schema_node'), self.field.get('node_data')
|
||||
),
|
||||
fields = [];
|
||||
|
||||
_.each(headerGroups, function(o) {
|
||||
fields = fields.concat(o.fields);
|
||||
});
|
||||
self.headerFields = new Backform.Fields(fields);
|
||||
|
||||
// creating grid using grid columns
|
||||
self.gridSchema = Backform.generateGridColumnsFromModel(
|
||||
self.field.get('node_info'), self.field.get('model'),
|
||||
'edit', gridCols, self.field.get('schema_node')
|
||||
);
|
||||
|
||||
// Providing behaviour control functions to header and grid control
|
||||
self.controls = [];
|
||||
self.listenTo(self.headerData, 'change', self.headerDataChanged);
|
||||
self.listenTo(self.headerData, 'select2', self.headerDataChanged);
|
||||
self.listenTo(self.collection, 'add', self.onAddorRemoveTokens);
|
||||
self.listenTo(self.collection, 'remove', self.onAddorRemoveTokens);
|
||||
},
|
||||
|
||||
// Template for creating header view
|
||||
generateHeader: function(data) {
|
||||
var header = [
|
||||
'<div class="subnode-header-form">',
|
||||
' <div class="container-fluid">',
|
||||
' <div class="row">',
|
||||
' <div class="col-3">',
|
||||
' <label class="control-label"><%-token_label%></label>',
|
||||
' </div>',
|
||||
' <div class="col-6" header="token"></div>',
|
||||
' <div class="col-2">',
|
||||
' <button class="btn btn-sm-sq btn-primary-icon add fa fa-plus" <%=canAdd ? "" : "disabled=\'disabled\'"%> ><span class="sr-only">' + gettext('Add Token') + '</span></button>',
|
||||
' </div>',
|
||||
' </div>',
|
||||
' </div>',
|
||||
'</div>'].join('\n');
|
||||
|
||||
_.extend(data, {
|
||||
token_label: gettext('Tokens'),
|
||||
});
|
||||
|
||||
var self = this,
|
||||
headerTmpl = _.template(header),
|
||||
$header = $(headerTmpl(data)),
|
||||
controls = this.controls;
|
||||
|
||||
self.headerFields.each(function(field) {
|
||||
var control = new (field.get('control'))({
|
||||
field: field,
|
||||
model: self.headerData,
|
||||
});
|
||||
|
||||
$header.find('div[header="' + field.get('name') + '"]').append(
|
||||
control.render().$el
|
||||
);
|
||||
|
||||
control.$el.find('.control-label').remove();
|
||||
controls.push(control);
|
||||
});
|
||||
|
||||
// We should not show add button in properties mode
|
||||
if (data.mode == 'properties') {
|
||||
$header.find('button.add').remove();
|
||||
}
|
||||
|
||||
// Disable add button in token control in create mode
|
||||
if(data.mode == 'create') {
|
||||
$header.find('button.add').attr('disabled', true);
|
||||
}
|
||||
|
||||
self.$header = $header;
|
||||
return $header;
|
||||
},
|
||||
|
||||
// Providing event handler for add button in header
|
||||
events: _.extend(
|
||||
{}, Backform.UniqueColCollectionControl.prototype.events,
|
||||
{'click button.add': 'addTokens'}
|
||||
),
|
||||
|
||||
// Show token/dictionary grid
|
||||
showGridControl: function(data) {
|
||||
|
||||
var self = this,
|
||||
titleTmpl = _.template('<div class=\'subnode-header\'></div>'),
|
||||
$gridBody = $('<div></div>', {
|
||||
class:'pgadmin-control-group backgrid form-group col-12 object subnode',
|
||||
}).append(
|
||||
titleTmpl({label: data.label})
|
||||
);
|
||||
|
||||
$gridBody.append(self.generateHeader(data));
|
||||
|
||||
var gridColumns = _.clone(this.gridSchema.columns);
|
||||
|
||||
// Insert Delete Cell into Grid
|
||||
if (data.disabled == false && data.canDelete) {
|
||||
gridColumns.unshift({
|
||||
name: 'pg-backform-delete', label: '',
|
||||
cell: Backgrid.Extension.DeleteCell,
|
||||
editable: false, cell_priority: -1,
|
||||
});
|
||||
}
|
||||
|
||||
if (self.grid) {
|
||||
self.grid.remove();
|
||||
self.grid = null;
|
||||
}
|
||||
// Initialize a new Grid instance
|
||||
var grid = self.grid = new Backgrid.Grid({
|
||||
columns: gridColumns,
|
||||
collection: self.collection,
|
||||
className: 'backgrid table-bordered',
|
||||
});
|
||||
self.$grid = grid.render().$el;
|
||||
|
||||
$gridBody.append(self.$grid);
|
||||
|
||||
// Find selected dictionaries in grid and show it all together
|
||||
setTimeout(function() {
|
||||
self.headerData.set({
|
||||
'token': self.$header.find(
|
||||
'div[header="token"] select'
|
||||
).val(),
|
||||
}, {silent:true}
|
||||
);
|
||||
}, 10);
|
||||
|
||||
// Render node grid
|
||||
return $gridBody;
|
||||
},
|
||||
|
||||
// When user change the header control to add a new token
|
||||
headerDataChanged: function() {
|
||||
var self = this,
|
||||
data = this.headerData.toJSON(),
|
||||
inSelected = (_.isEmpty(data) || _.isUndefined(data));
|
||||
|
||||
if (!self.$header) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.$header.find('button.add').prop('disabled', inSelected);
|
||||
},
|
||||
|
||||
// Get called when user click on add button header
|
||||
addTokens: function(ev) {
|
||||
ev.preventDefault();
|
||||
var self = this,
|
||||
token = self.headerData.get('token');
|
||||
|
||||
if (token && token != '') {
|
||||
var coll = self.model.get(self.field.get('name')),
|
||||
m = new (self.field.get('model'))(
|
||||
self.headerData.toJSON(), {
|
||||
silent: true, top: self.model.top,
|
||||
collection: coll, handler: coll,
|
||||
}),
|
||||
checkVars = ['token'],
|
||||
idx = -1;
|
||||
|
||||
// Find if token exists in grid
|
||||
self.collection.each(function(local_model) {
|
||||
_.each(checkVars, function(v) {
|
||||
var val = local_model.get(v);
|
||||
if(val == token) {
|
||||
idx = coll.indexOf(local_model);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// remove 'm' if duplicate value found.
|
||||
if (idx == -1) {
|
||||
coll.add(m);
|
||||
idx = coll.indexOf(m);
|
||||
}
|
||||
self.$grid.find('.new').removeClass('new');
|
||||
var newRow = self.grid.body.rows[idx].$el;
|
||||
newRow.addClass('new');
|
||||
$(newRow).pgMakeVisible('backform-tab');
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// When user delete token/dictionary entry from grid
|
||||
onAddorRemoveTokens: function() {
|
||||
var self = this;
|
||||
|
||||
/*
|
||||
* Wait for collection to be updated before checking for the button to
|
||||
* be enabled, or not.
|
||||
*/
|
||||
setTimeout(function() {
|
||||
self.collection.trigger('pgadmin:tokens:updated', self.collection);
|
||||
self.headerDataChanged();
|
||||
}, 10);
|
||||
},
|
||||
|
||||
// When control is about to destroy
|
||||
remove: function() {
|
||||
/*
|
||||
* Stop listening the events registered by this control.
|
||||
*/
|
||||
this.stopListening(this.headerData, 'change', this.headerDataChanged);
|
||||
this.listenTo(this.headerData, 'select2', this.headerDataChanged);
|
||||
this.listenTo(this.collection, 'remove', this.onAddorRemoveTokens);
|
||||
|
||||
// Remove header controls.
|
||||
_.each(this.controls, function(control) {
|
||||
control.remove();
|
||||
});
|
||||
TokenControl.__super__.remove.apply(this, arguments);
|
||||
|
||||
// Remove the header model
|
||||
delete (this.headerData);
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// Extend the collection class for FTS Configuration
|
||||
if (!pgBrowser.Nodes['coll-fts_configuration']) {
|
||||
pgAdmin.Browser.Nodes['coll-fts_configuration'] =
|
||||
@ -463,19 +74,30 @@ define('pgadmin.node.fts_configuration', [
|
||||
}]);
|
||||
},
|
||||
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
return new FTSConfigurationSchema(
|
||||
{
|
||||
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
|
||||
schema: ()=>getNodeListById(pgBrowser.Nodes['schema'], treeNodeInfo, itemNodeData),
|
||||
parsers: ()=>getNodeAjaxOptions('parsers', this, treeNodeInfo, itemNodeData),
|
||||
copyConfig: ()=>getNodeAjaxOptions('copyConfig', this, treeNodeInfo, itemNodeData),
|
||||
tokens: ()=>getNodeAjaxOptions('tokens', this, treeNodeInfo, itemNodeData, {urlWithId: true}),
|
||||
dictionaries: ()=>getNodeAjaxOptions('dictionaries', this, treeNodeInfo, itemNodeData, {
|
||||
cacheLevel: 'fts_configuration',
|
||||
cacheNode: 'fts_configuration'
|
||||
}),
|
||||
},
|
||||
{
|
||||
owner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
|
||||
schema: itemNodeData._id,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
// Defining model for FTS Configuration node
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'oid',
|
||||
defaults: {
|
||||
name: undefined, // FTS Configuration name
|
||||
owner: undefined, // FTS Configuration owner
|
||||
is_sys_obj: undefined, // Is system object
|
||||
description: undefined, // Comment on FTS Configuration
|
||||
schema: undefined, // Schema name FTS Configuration belongs to
|
||||
prsname: undefined, // FTS parser list for FTS Configuration node
|
||||
copy_config: undefined, // FTS configuration list to copy from
|
||||
tokens: undefined, // token/dictionary pair list for node
|
||||
},
|
||||
|
||||
initialize: function(attrs, opts) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
@ -492,106 +114,10 @@ define('pgadmin.node.fts_configuration', [
|
||||
schema: [{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text', cellHeaderClasses: 'width_percent_50',
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string',
|
||||
editable: false, type: 'text', mode:['properties'],
|
||||
},{
|
||||
id: 'owner', label: gettext('Owner'), cell: 'string',
|
||||
type: 'text', mode: ['properties', 'edit','create'], node: 'role',
|
||||
control: Backform.NodeListByNameControl, select2: { allowClear: false },
|
||||
},{
|
||||
id: 'schema', label: gettext('Schema'), cell: 'string',
|
||||
type: 'text', mode: ['create','edit'], node: 'schema',
|
||||
control: 'node-list-by-id', cache_node: 'database',
|
||||
cache_level: 'database',
|
||||
},{
|
||||
id: 'is_sys_obj', label: gettext('System FTS configuration?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
},{
|
||||
}, {
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline', cellHeaderClasses: 'width_percent_50',
|
||||
},{
|
||||
id: 'prsname', label: gettext('Parser'),type: 'text',
|
||||
url: 'parsers', first_empty: true,
|
||||
group: gettext('Definition'), control: 'node-ajax-options',
|
||||
deps: ['copy_config'],
|
||||
//disable parser when user select copy_config manually and vica-versa
|
||||
disabled: function(m) {
|
||||
var copy_config = m.get('copy_config');
|
||||
return (_.isNull(copy_config) ||
|
||||
_.isUndefined(copy_config) ||
|
||||
copy_config === '') ? false : true;
|
||||
},
|
||||
readonly: function(m) {return !m.isNew();},
|
||||
},{
|
||||
id: 'copy_config', label: gettext('Copy config'),type: 'text',
|
||||
mode: ['create'], group: gettext('Definition'),
|
||||
control: 'node-ajax-options', url: 'copyConfig', deps: ['prsname'],
|
||||
|
||||
//disable copy_config when user select parser manually and vica-versa
|
||||
disabled: function(m) {
|
||||
var parser = m.get('prsname');
|
||||
return (_.isNull(parser) ||
|
||||
_.isUndefined(parser) ||
|
||||
parser === '') ? false : true;
|
||||
},
|
||||
readonly: function(m) {return !m.isNew();},
|
||||
},{
|
||||
id: 'tokens', label: gettext('Tokens'), type: 'collection',
|
||||
group: gettext('Tokens'), control: TokenControl,
|
||||
model: TokenModel, columns: ['token', 'dictionary'],
|
||||
uniqueCol : ['token'], mode: ['create','edit'],
|
||||
canAdd: true, canEdit: false, canDelete: true,
|
||||
}],
|
||||
|
||||
/*
|
||||
* Triggers control specific error messages for name,
|
||||
* copy_config/parser and schema, if any one of them is not specified
|
||||
* while creating new fts configuration
|
||||
*/
|
||||
validate: function() {
|
||||
var msg;
|
||||
var name = this.get('name');
|
||||
var parser = this.get('prsname');
|
||||
var copy_config_or_parser = !(parser === '' ||
|
||||
_.isUndefined(parser) ||
|
||||
_.isNull(parser)) ?
|
||||
this.get('prsname') : this.get('copy_config');
|
||||
var schema = this.get('schema');
|
||||
|
||||
// Clear the existing error model
|
||||
this.errorModel.clear();
|
||||
this.trigger('on-status-clear');
|
||||
|
||||
// Validate the name
|
||||
if (_.isUndefined(name) ||
|
||||
_.isNull(name) ||
|
||||
String(name).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Name must be specified.');
|
||||
this.errorModel.set('name', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Validate parser or copy_config
|
||||
else if (_.isUndefined(copy_config_or_parser) ||
|
||||
_.isNull(copy_config_or_parser) ||
|
||||
String(copy_config_or_parser).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Select parser or configuration to copy.');
|
||||
this.errorModel.set('parser', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Validate schema
|
||||
else if (_.isUndefined(schema) ||
|
||||
_.isNull(schema) ||
|
||||
String(schema).replace(/^\s+|\s+$/g, '') == '') {
|
||||
msg = gettext('Schema must be selected.');
|
||||
this.errorModel.set('schema', msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,182 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 DataGridViewWithHeaderForm from 'sources/helpers/DataGridViewWithHeaderForm';
|
||||
import { isEmptyString } from '../../../../../../../../static/js/validators';
|
||||
|
||||
class TokenHeaderSchema extends BaseUISchema {
|
||||
constructor(tokenOptions) {
|
||||
super({
|
||||
token: undefined,
|
||||
});
|
||||
|
||||
this.tokenOptions = tokenOptions;
|
||||
this.isNewFTSConf = true;
|
||||
}
|
||||
|
||||
addDisabled() {
|
||||
return this.isNewFTSConf;
|
||||
}
|
||||
|
||||
getNewData(data) {
|
||||
return {
|
||||
token: data.token,
|
||||
dictname: [],
|
||||
};
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [{
|
||||
id: 'token', label: gettext('Tokens'), type:'select', editable: false,
|
||||
options: this.tokenOptions, disabled: function() { return obj.isNewFTSConf; }
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
class TokenSchema extends BaseUISchema {
|
||||
constructor(dictOptions) {
|
||||
super({
|
||||
token: undefined,
|
||||
dictname: undefined,
|
||||
});
|
||||
|
||||
this.dictOptions = dictOptions;
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return [
|
||||
{
|
||||
id: 'token', label: gettext('Token'), type:'text',
|
||||
editable: false, cell: '', minWidth: 150, noEmpty: true,
|
||||
}, {
|
||||
id: 'dictname', label: gettext('Dictionaries'),
|
||||
editable: true, controlProps: {multiple: true}, cell:'select',
|
||||
options: this.dictOptions, minWidth: 260, noEmpty: true,
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default class FTSConfigurationSchema extends BaseUISchema {
|
||||
constructor(fieldOptions={}, initValues) {
|
||||
super({
|
||||
name: undefined, // FTS Configuration name
|
||||
owner: undefined, // FTS Configuration owner
|
||||
is_sys_obj: undefined, // Is system object
|
||||
description: undefined, // Comment on FTS Configuration
|
||||
schema: undefined, // Schema name FTS Configuration belongs to
|
||||
prsname: undefined, // FTS parser list for FTS Configuration node
|
||||
copy_config: undefined, // FTS configuration list to copy from
|
||||
tokens: undefined, // token/dictionary pair list for node
|
||||
...initValues
|
||||
});
|
||||
this.fieldOptions = {
|
||||
role: [],
|
||||
schema: [],
|
||||
parsers: [],
|
||||
copyConfig: [],
|
||||
tokens: [],
|
||||
dictionaries: [],
|
||||
...fieldOptions,
|
||||
};
|
||||
|
||||
this.tokHeaderSchema = new TokenHeaderSchema(this.fieldOptions.tokens);
|
||||
this.tokColumnSchema = new TokenSchema(this.fieldOptions.dictionaries);
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
|
||||
initialise(data) {
|
||||
this.tokHeaderSchema.isNewFTSConf = this.isNew(data);
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let obj = this;
|
||||
return [
|
||||
{
|
||||
id: 'name', label: gettext('Name'), cell: 'text', type: 'text',
|
||||
noEmpty: true,
|
||||
}, {
|
||||
id: 'oid', label: gettext('OID'), cell: 'text',
|
||||
editable: false, type: 'text', mode:['properties'],
|
||||
}, {
|
||||
id: 'owner', label: gettext('Owner'), cell: 'text',
|
||||
editable: false, type: 'select', options: this.fieldOptions.role,
|
||||
mode: ['properties', 'edit','create'], noEmpty: true,
|
||||
}, {
|
||||
id: 'schema', label: gettext('Schema'),
|
||||
editable: false, type: 'select', options: this.fieldOptions.schema,
|
||||
mode: ['create', 'edit'], noEmpty: true,
|
||||
}, {
|
||||
id: 'is_sys_obj', label: gettext('System FTS configuration?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
}, {
|
||||
id: 'description', label: gettext('Comment'), cell: 'text',
|
||||
type: 'multiline',
|
||||
}, {
|
||||
id: 'prsname', label: gettext('Parser'),
|
||||
editable: false, type: 'select', group: gettext('Definition'),
|
||||
deps: ['copy_config'],
|
||||
options: this.fieldOptions.parsers,
|
||||
//disable parser when user select copy_config manually and vica-versa
|
||||
disabled: function(state) {
|
||||
var copy_config = state.copy_config;
|
||||
return (_.isNull(copy_config) ||
|
||||
_.isUndefined(copy_config) ||
|
||||
copy_config === '') ? false : true;
|
||||
},
|
||||
readonly: function(state) { return !obj.isNew(state); },
|
||||
}, {
|
||||
id: 'copy_config', label: gettext('Copy config'),
|
||||
editable: false, type: 'select', group: gettext('Definition'),
|
||||
mode: ['create'], deps: ['prsname'],
|
||||
options: this.fieldOptions.copyConfig,
|
||||
//disable copy_config when user select parser manually and vica-versa
|
||||
disabled: function(state) {
|
||||
var parser = state.prsname;
|
||||
return (_.isNull(parser) ||
|
||||
_.isUndefined(parser) ||
|
||||
parser === '') ? false : true;
|
||||
},
|
||||
readonly: function(state) { return !obj.isNew(state); },
|
||||
}, {
|
||||
id: 'tokens', label: '', type: 'collection',
|
||||
group: gettext('Tokens'), mode: ['create','edit'],
|
||||
editable: false, schema: this.tokColumnSchema,
|
||||
headerSchema: this.tokHeaderSchema,
|
||||
headerVisible: function() { return true;},
|
||||
CustomControl: DataGridViewWithHeaderForm,
|
||||
uniqueCol : ['token'],
|
||||
canAdd: true, canEdit: false, canDelete: true,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
let errmsg = null,
|
||||
parser = state.prsname,
|
||||
config = state.copy_config;
|
||||
|
||||
let copy_config_or_parser = !(parser === '' || _.isUndefined(parser)
|
||||
|| _.isNull(parser)) ? parser : config;
|
||||
|
||||
if(isEmptyString(copy_config_or_parser)) {
|
||||
errmsg = gettext('Select parser or configuration to copy.');
|
||||
setError('prsname', errmsg);
|
||||
return true;
|
||||
} else {
|
||||
setError('prsname', null);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ import {FormFooterMessage, MESSAGE_TYPE } from 'sources/components/FormComponent
|
||||
import Theme from 'sources/Theme';
|
||||
import { PrimaryButton, DefaultButton, PgIconButton } from 'sources/components/Buttons';
|
||||
import Loader from 'sources/components/Loader';
|
||||
import { minMaxValidator, numberValidator, integerValidator, emptyValidator, checkUniqueCol } from '../validators';
|
||||
import { minMaxValidator, numberValidator, integerValidator, emptyValidator, checkUniqueCol, isEmptyString} from '../validators';
|
||||
import { MappedFormControl } from './MappedControl';
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
@ -225,7 +225,7 @@ function validateSchema(schema, sessData, setError) {
|
||||
if(dupInd > 0) {
|
||||
let uniqueColNames = _.filter(field.schema.fields, (uf)=>field.uniqueCol.indexOf(uf.id) > -1)
|
||||
.map((uf)=>uf.label).join(', ');
|
||||
if (_.isUndefined(field.label) || _.isNull(field.label)) {
|
||||
if (isEmptyString(field.label)) {
|
||||
setError(field.uniqueCol[0], gettext('%s must be unique.', uniqueColNames));
|
||||
} else {
|
||||
setError(field.uniqueCol[0], gettext('%s in %s must be unique.', uniqueColNames, field.label));
|
||||
|
@ -53,7 +53,7 @@ export default function DataGridViewWithHeaderForm(props) {
|
||||
return (
|
||||
<Box className={containerClassName}>
|
||||
<Box className={classes.formBorder}>
|
||||
<DataGridHeader label={props.label} />
|
||||
{props.label && <DataGridHeader label={props.label} />}
|
||||
{headerVisible && <Box className={classes.form}>
|
||||
<SchemaView
|
||||
formType={'dialog'}
|
||||
|
@ -0,0 +1,121 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 FTSConfigurationSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/static/js/fts_configuration.ui';
|
||||
|
||||
describe('FTSConfigurationSchema', ()=>{
|
||||
let mount;
|
||||
let schemaObj = new FTSConfigurationSchema(
|
||||
{
|
||||
role: ()=>[],
|
||||
schema: ()=>[],
|
||||
parsers: ()=>[],
|
||||
copyConfig: ()=>[],
|
||||
tokens: ()=>[],
|
||||
dictionaries: ()=>[],
|
||||
},
|
||||
{
|
||||
owner: 'postgres',
|
||||
schema: '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}
|
||||
disableDialogHelp={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}
|
||||
disableDialogHelp={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.prsname = '';
|
||||
state.copy_config = '';
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prsname', 'Select parser or configuration to copy.');
|
||||
|
||||
state.prsname = 'default';
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('prsname', null);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user