Partition related fixes:

1. When attaching a partition, tables were not loading in the dropdown.
2. When adding a sub partition in a partition, collations were not loading in dropdown.
3. Fix some grid column widths in table node.

Fixes #6783
This commit is contained in:
Aditya Toshniwal 2021-09-24 16:28:55 +05:30 committed by Akshay Joshi
parent c32a325c11
commit 0228d16990
10 changed files with 86 additions and 671 deletions

View File

@ -98,13 +98,13 @@ class ForeignKeyColumnSchema extends BaseUISchema {
get baseFields() {
return [{
id: 'local_column', label: gettext('Local'), type:'text', editable: false,
cell:'', minWidth: 145,
cell:'',
},{
id: 'referenced', label: gettext('Referenced'), type: 'text', editable: false,
cell:'', minWidth: 145,
cell:'',
},{
id: 'references_table_name', label: gettext('Referenced Table'), type: 'text', editable: false,
cell:'', minWidth: 145,
cell:'',
}];
}
}
@ -326,7 +326,6 @@ export default class ForeignKeySchema extends BaseUISchema {
},
}
},
minWidth: 245,
}),
deps: ()=>{
let ret = [];

View File

@ -14,7 +14,7 @@ define([
'sources/pgadmin', 'pgadmin.browser',
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.backgrid',
'pgadmin.node.schema.dir/schema_child_tree_node', 'sources/utils',
'pgadmin.browser.collection', 'pgadmin.browser.table.partition.utils',
'pgadmin.browser.collection',
],
function(
gettext, url_for, $, _, pgAdmin, pgBrowser, Alertify, Backform, Backgrid,

View File

@ -6,16 +6,16 @@ import { ConstraintsSchema } from '../../../static/js/table.ui';
import { PartitionKeysSchema, PartitionsSchema } from '../../../static/js/partition.utils.ui';
import { getNodePrivilegeRoleSchema } from '../../../../../../static/js/privilege.ui';
import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../../../static/js/node_ajax';
import { getNodeVacuumSettingsSchema } from '../../../../../../static/js/vacuum.ui';
import { getNodeForeignKeySchema } from '../../../constraints/foreign_key/static/js/foreign_key.ui';
import { getNodeExclusionConstraintSchema } from '../../../constraints/exclusion_constraint/static/js/exclusion_constraint.ui';
import * as pgadminUtils from 'sources/utils';
export function getNodePartitionTableSchema(treeNodeInfo, itemNodeData, pgBrowser) {
const spcname = ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{
return (m.label != 'pg_global');
});
let tableNode = pgBrowser.Nodes['table'];
let partNode = pgBrowser.Nodes['partition'];
return new PartitionTableSchema(
{
@ -32,13 +32,12 @@ export function getNodePartitionTableSchema(treeNodeInfo, itemNodeData, pgBrowse
return true;
}),
spcname: spcname,
coll_inherits: ()=>getNodeAjaxOptions('get_inherits', tableNode, treeNodeInfo, itemNodeData),
typname: ()=>getNodeAjaxOptions('get_oftype', tableNode, treeNodeInfo, itemNodeData),
like_relation: ()=>getNodeAjaxOptions('get_relations', tableNode, treeNodeInfo, itemNodeData),
coll_inherits: ()=>getNodeAjaxOptions('get_inherits', partNode, treeNodeInfo, itemNodeData),
typname: ()=>getNodeAjaxOptions('get_oftype', partNode, treeNodeInfo, itemNodeData),
like_relation: ()=>getNodeAjaxOptions('get_relations', partNode, treeNodeInfo, itemNodeData),
},
treeNodeInfo,
{
vacuum_settings: ()=>getNodeVacuumSettingsSchema(tableNode, treeNodeInfo, itemNodeData),
constraints: ()=>new ConstraintsSchema(
treeNodeInfo,
()=>getNodeForeignKeySchema(treeNodeInfo, itemNodeData, pgBrowser, true),
@ -46,9 +45,24 @@ export function getNodePartitionTableSchema(treeNodeInfo, itemNodeData, pgBrowse
{spcname: spcname},
),
},
(privileges)=>getNodePrivilegeRoleSchema(tableNode, treeNodeInfo, itemNodeData, privileges),
(privileges)=>getNodePrivilegeRoleSchema(partNode, treeNodeInfo, itemNodeData, privileges),
(params)=>{
return getNodeAjaxOptions('get_columns', tableNode, treeNodeInfo, itemNodeData, {urlParams: params, useCache:false});
return getNodeAjaxOptions('get_columns', partNode, treeNodeInfo, itemNodeData, {urlParams: params, useCache:false});
},
()=>getNodeAjaxOptions('get_collations', pgBrowser.Nodes['collation'], treeNodeInfo, itemNodeData),
()=>getNodeAjaxOptions('get_op_class', pgBrowser.Nodes['table'], treeNodeInfo, itemNodeData),
()=>{
return getNodeAjaxOptions('get_attach_tables', partNode, treeNodeInfo, itemNodeData, {
useCache:false,
customGenerateUrl: (treeNodeInfo, actionType)=>{
return pgadminUtils.sprintf('table/%s/%s/%s/%s/%s/%s',
encodeURIComponent(actionType), encodeURIComponent(treeNodeInfo['server_group']._id),
encodeURIComponent(treeNodeInfo['server']._id),
encodeURIComponent(treeNodeInfo['database']._id),
encodeURIComponent(treeNodeInfo['partition'].schema_id),
encodeURIComponent(treeNodeInfo['partition']._id)
);
}});
},
{
relowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
@ -58,7 +72,8 @@ export function getNodePartitionTableSchema(treeNodeInfo, itemNodeData, pgBrowse
}
export default class PartitionTableSchema extends BaseUISchema {
constructor(fieldOptions={}, nodeInfo, schemas, getPrivilegeRoleSchema, getColumns, initValues) {
constructor(fieldOptions={}, nodeInfo, schemas, getPrivilegeRoleSchema, getColumns,
getCollations, getOperatorClass, getAttachTables, initValues) {
super({
name: undefined,
oid: undefined,
@ -98,11 +113,11 @@ export default class PartitionTableSchema extends BaseUISchema {
this.getPrivilegeRoleSchema = getPrivilegeRoleSchema;
this.nodeInfo = nodeInfo;
this.getColumns = getColumns;
this.getAttachTables = getAttachTables;
this.partitionKeysObj = new PartitionKeysSchema();
this.partitionsObj = new PartitionsSchema(this.nodeInfo);
this.partitionKeysObj = new PartitionKeysSchema([], getCollations, getOperatorClass);
this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables);
this.constraintsObj = this.schemas.constraints();
this.vacuumSettingsSchema = this.schemas.vacuum_settings();
}
get idAttribute() {
@ -395,13 +410,6 @@ export default class PartitionTableSchema extends BaseUISchema {
].join(''),
min_version: 100000,
},
{
// Here - we will create tab control for storage parameters
// (auto vacuum).
type: 'nested-tab', group: gettext('Parameters'),
mode: ['edit', 'create'], deps: ['is_partitioned'],
schema: this.vacuumSettingsSchema,
},
{
id: 'relacl_str', label: gettext('Privileges'), disabled: this.inCatalog,
type: 'text', mode: ['properties'], group: gettext('Security'),

View File

@ -1,595 +0,0 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
define('pgadmin.node.table_partition_utils', [
'sources/gettext', 'jquery', 'underscore', 'backbone', 'pgadmin.browser',
'pgadmin.backform','pgadmin.backgrid', 'pgadmin.browser.collection',
], function(gettext, $, _, Backbone, pgBrowser, Backform, Backgrid) {
Backgrid.PartitionRow = Backgrid.Row.extend({
modelDuplicateClass: 'bg-model-duplicate',
initialize: function () {
Backgrid.Row.prototype.initialize.apply(this, arguments);
var self = this;
self.model.on('change:is_attach', function() {
setTimeout(function() {
self.columns.each(function(col) {
if (col.get('name') == 'partition_name') {
var idx = self.columns.indexOf(col),
cf = col.get('cellFunction'),
cell = new (cf.apply(col, [self.model]))({
column: col,
model: self.model,
}),
oldCell = self.cells[idx];
oldCell.remove();
self.cells[idx] = cell;
self.render();
}
});
}, 10);
});
self.listenTo(self.model, 'pgadmin-session:model:duplicate', self.modelDuplicate);
self.listenTo(self.model, 'pgadmin-session:model:unique', self.modelUnique);
},
modelDuplicate: function() {
$(this.el).removeClass('new');
$(this.el).addClass(this.modelDuplicateClass);
},
modelUnique: function() {
$(this.el).removeClass(this.modelDuplicateClass);
},
});
var getPartitionCell = function(model) {
var is_attach = model.get('is_attach');
if (is_attach) {
var options = [];
model.set({'partition_name': undefined}, {silent:true});
_.each(model.top.table_options, function(t) {
options.push([t.label, t.value]);
});
return Backgrid.Extension.Select2Cell.extend({optionValues: options});
} else {
return Backgrid.StringCell;
}
};
Backform.PartitionKeyModel = pgBrowser.Node.Model.extend({
defaults: {
key_type: 'column',
pt_column: undefined,
expression: undefined,
},
keys:['pt_column'],
schema: [{
id: 'key_type', label: gettext('Key type'), type:'select2', editable: true,
cell:'select2', cellHeaderClasses: 'width_percent_25',
select2: {allowClear: false},
options:[{
label: gettext('Column'), value: 'column',
},{
label: gettext('Expression'), value: 'expression',
}],
},{
id: 'pt_column', label: gettext('Column'), type:'text',
cell: Backgrid.Extension.Select2DepCell.extend({
keyPathAccessor: function(obj, path) {
var res = obj;
if(_.isArray(res)) {
return _.map(res, function(o) { return o['pt_column'];
});
}
path = path.split('.');
for (var i = 0; i < path.length; i++) {
if (_.isNull(res)) return null;
if (_.isEmpty(path[i])) continue;
if (!_.isUndefined(res[path[i]])) res = res[path[i]];
}
return _.isObject(res) && !_.isArray(res) ? null : res;
},
initialize: function() {
// Here we will decide if we need to call URL
// Or fetch the data from parent columns collection
var self = this;
if(this.model.handler) {
Backgrid.Extension.Select2DepCell.prototype.initialize.apply(this, arguments);
// Do not listen for any event(s) for existing constraint.
if (_.isUndefined(self.model.get('oid'))) {
var tableCols = self.model.top.get('columns');
self.listenTo(tableCols, 'remove' , self.resetColOptions);
self.listenTo(tableCols, 'change:name', self.resetColOptions);
}
self.custom_options();
}
},
resetColOptions: function() {
var self = this;
setTimeout(function () {
self.custom_options();
self.render.apply(self);
}, 50);
},
custom_options: function() {
// We will add all the columns entered by user in table model
var columns = this.model.top.get('columns'),
typename = this.model.top.get('typname'),
of_types_tables = this.model.top.of_types_tables,
added_columns_from_tables = [];
if (columns.length > 0) {
_.each(columns.models, function(m) {
var col = m.get('name');
if(!_.isUndefined(col) && !_.isNull(col)) {
added_columns_from_tables.push(
{label: col, value: col, image:'icon-column'}
);
}
});
} else if (!_.isUndefined(typename) && !_.isNull(typename)
&& !_.isUndefined(of_types_tables) && of_types_tables.length > 0) {
// Iterate through all the of_type tables
_.each(of_types_tables, function(type) {
if (type.label == typename) {
// Iterate all the columns of selected "OF TYPE".
_.each(type.oftype_columns, function(col) {
added_columns_from_tables.push(
{label: col.name, value: col.name, image:'icon-column'}
);
});
}
});
}
// Set the values in to options so that user can select
this.column.set('options', added_columns_from_tables);
},
remove: function() {
if(this.model.handler) {
var self = this,
tableCols = self.model.top.get('columns');
self.stopListening(tableCols, 'remove' , self.resetColOptions);
self.stopListening(tableCols, 'change:name' , self.resetColOptions);
Backgrid.Extension.Select2DepCell.prototype.remove.apply(this, arguments);
}
},
}),
deps: ['key_type'],
cellHeaderClasses: 'width_percent_30',
transform : function(data){
var res = [];
if (data && _.isArray(data)) {
_.each(data, function(d) {
res.push({label: d.label, value: d.label, image:'icon-column'});
});
}
return res;
},
select2:{allowClear:false},
editable: function(m) {
if (m.get('key_type') == 'expression') {
setTimeout( function() {
m.set('pt_column', undefined);
}, 10);
return false;
}
return true;
},
},{
id: 'expression', label: gettext('Expression'), type:'text',
cell:Backgrid.Extension.StringDepCell,
cellHeaderClasses: 'width_percent_45',
deps: ['key_type'],
editable: function(m) {
if (m.get('key_type') == 'column') {
setTimeout( function() {
m.set('expression', undefined);
}, 10);
return false;
}
return true;
},
},
],
validate: function() {
var col_type = this.get('key_type'),
pt_column = this.get('pt_column'),
expression = this.get('expression'),
msg;
// Have to clear existing validation before initiating current state
// validation only
this.errorModel.clear();
if (_.isUndefined(col_type) || _.isNull(col_type) ||
String(col_type).replace(/^\s+|\s+$/g, '') == '') {
msg = gettext('Partition key type cannot be empty.');
this.errorModel.set('key_type', msg);
return msg;
}
else if (col_type == 'column' &&
_.isUndefined(pt_column) || _.isNull(pt_column) ||
String(pt_column).replace(/^\s+|\s+$/g, '') == '') {
msg = gettext('Partition key column cannot be empty.');
this.errorModel.set('pt_column', msg);
return msg;
}
else if (col_type == 'expression' &&
_.isUndefined(expression) || _.isNull(expression) ||
String(expression).replace(/^\s+|\s+$/g, '') == '') {
msg = gettext('Partition key expression cannot be empty.');
this.errorModel.set('expression', msg);
return msg;
}
return null;
},
});
Backform.PartitionsModel = pgBrowser.Node.Model.extend({
idAttribute: 'oid',
defaults: {
oid: undefined,
is_attach: false,
partition_name: undefined,
is_default: undefined,
values_from: undefined,
values_to: undefined,
values_in: undefined,
values_modulus: undefined,
values_remainder: undefined,
is_sub_partitioned: false,
sub_partition_type: 'range',
},
keys:['partition_name'],
schema: [{
id: 'oid', label: gettext('OID'), type: 'text',
mode: ['properties'],
},{
id: 'is_attach', label:gettext('Operation'), cell: 'switch', type: 'switch',
options: {'onText': gettext('Attach'), 'offText': gettext('Create'), 'width': 65},
cellHeaderClasses: 'width_percent_5',
editable: function(m) {
if (m instanceof Backbone.Model && m.isNew() && !m.top.isNew())
return true;
return false;
},
disabled: function(m) {
if (m instanceof Backbone.Model && m.isNew() && !m.top.isNew())
return false;
return true;
},
},{
id: 'partition_name', label: gettext('Name'), type: 'text', cell:'string',
cellHeaderClasses: 'width_percent_15',
editable: function(m) {
if (m instanceof Backbone.Model && m.isNew())
return true;
return false;
}, cellFunction: getPartitionCell,
disabled: function(m) {
if (m instanceof Backbone.Model && m.isNew())
return false;
return true;
},
},{
id: 'is_default', label: gettext('Default'), type: 'switch', cell:'switch',
cellHeaderClasses: 'width_percent_5', min_version: 110000,
options: {'onText': gettext('Yes'), 'offText': gettext('No')},
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
(m.handler.top.attributes.partition_type === 'range' ||
m.handler.top.attributes.partition_type === 'list') &&
m instanceof Backbone.Model && m.isNew() &&
m.handler.top.node_info.server.version >= 110000)
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
(m.handler.top.attributes.partition_type === 'range' ||
m.handler.top.attributes.partition_type === 'list') &&
m instanceof Backbone.Model && m.isNew() &&
m.handler.top.node_info.server.version >= 110000)
return false;
return true;
},
},{
id: 'values_from', label: gettext('From'), type:'text',
cell:Backgrid.Extension.StringDepCell, deps: ['is_default'],
cellHeaderClasses: 'width_percent_15',
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'range' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'range' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return false;
return true;
},
},{
id: 'values_to', label: gettext('To'), type:'text',
cell:Backgrid.Extension.StringDepCell, deps: ['is_default'],
cellHeaderClasses: 'width_percent_15',
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'range' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'range' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return false;
return true;
},
},{
id: 'values_in', label: gettext('In'), type:'text',
cell:Backgrid.Extension.StringDepCell, deps: ['is_default'],
cellHeaderClasses: 'width_percent_15',
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'list' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'list' &&
m instanceof Backbone.Model && m.isNew() && m.get('is_default') !== true)
return false;
return true;
},
},{
id: 'values_modulus', label: gettext('Modulus'), type:'int',
cell:Backgrid.Extension.StringDepCell,
cellHeaderClasses: 'width_percent_15',
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'hash' &&
m instanceof Backbone.Model && m.isNew())
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'hash' &&
m instanceof Backbone.Model && m.isNew())
return false;
return true;
},
},{
id: 'values_remainder', label: gettext('Remainder'), type:'int',
cell:Backgrid.Extension.StringDepCell,
cellHeaderClasses: 'width_percent_15 width_percent_20',
editable: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'hash' &&
m instanceof Backbone.Model && m.isNew())
return true;
return false;
},
disabled: function(m) {
if(m.handler && m.handler.top &&
m.handler.top.attributes &&
m.handler.top.attributes.partition_type === 'hash' &&
m instanceof Backbone.Model && m.isNew())
return false;
return true;
},
},{
id: 'is_sub_partitioned', label:gettext('Partitioned table?'), cell: 'switch',
group: 'Partition', type: 'switch', mode: ['properties', 'create', 'edit'],
deps: ['is_attach'],
disabled: function(m) {
if(!m.isNew())
return true;
if (m.get('is_attach')) {
setTimeout( function() {
m.set('is_sub_partitioned', false);
}, 10);
return true;
}
return false;
},
},{
id: 'sub_partition_type', label:gettext('Partition Type'),
editable: false, type: 'select2', select2: {allowClear: false},
group: 'Partition', deps: ['is_sub_partitioned'],
options: function() {
var options = [{
label: gettext('Range'), value: 'range',
},{
label: gettext('List'), value: 'list',
}];
if(!_.isUndefined(this.node_info) && !_.isUndefined(this.node_info.server)
&& !_.isUndefined(this.node_info.server.version) &&
this.node_info.server.version >= 110000) {
options.push({
label: gettext('Hash'), value: 'hash',
});
}
return options;
},
visible: function(m) {
if (m.isNew())
return true;
return false;
},
disabled: function(m) {
if (!m.isNew() || !m.get('is_sub_partitioned'))
return true;
return false;
},
},{
id: 'sub_partition_keys', label:gettext('Partition Keys'),
model: Backform.PartitionKeyModel,
subnode: Backform.PartitionKeyModel,
editable: true, type: 'collection',
group: 'Partition', mode: ['properties', 'create', 'edit'],
deps: ['is_sub_partitioned', 'sub_partition_type'],
canEdit: false, canDelete: true,
control: 'sub-node-collection',
canAdd: function(m) {
if (m.isNew() && m.get('is_sub_partitioned'))
return true;
return false;
},
canAddRow: function(m) {
var columns = m.top.get('columns'),
typename = m.top.get('typname'),
columns_exist= false;
var max_row_count = 1000;
if (m.get('sub_partition_type') && m.get('sub_partition_type') == 'list')
max_row_count = 1;
/* If columns are not specified by the user then it may be
* possible that he/she selected 'OF TYPE', so we should check
* for that as well.
*/
if (columns.length <= 0 && !_.isUndefined(typename)
&& !_.isNull(typename) && m.of_types_tables.length > 0){
_.each(m.of_types_tables, function(data) {
if (data.label == typename && data.oftype_columns.length > 0){
columns_exist = true;
}
});
} else if (columns.length > 0) {
columns_exist = _.some(columns.pluck('name'));
}
return (m.get('sub_partition_keys') &&
m.get('sub_partition_keys').length < max_row_count && columns_exist
);
},
disabled: function(m) {
if (m.get('sub_partition_keys') && m.get('sub_partition_keys').models.length > 0) {
setTimeout(function () {
var coll = m.get('sub_partition_keys');
coll.remove(coll.filter(function() { return true; }));
}, 10);
}
},
visible: function(m) {
if (m.isNew())
return true;
return false;
},
},{
id: 'sub_partition_scheme', label: gettext('Partition Scheme'),
type: 'note', group: 'Partition', mode: ['edit'],
visible: function(m) {
if (!m.isNew() && !_.isUndefined(m.get('sub_partition_scheme')) &&
m.get('sub_partition_scheme') != '')
return true;
return false;
},
disabled: function(m) {
if (!m.isNew()) {
this.text = m.get('sub_partition_scheme');
}
},
}],
validate: function() {
var partition_name = this.get('partition_name'),
is_default = this.get('is_default'),
values_from = this.get('values_from'),
values_to = this.get('values_to'),
values_in = this.get('values_in'),
values_modulus = this.get('values_modulus'),
values_remainder = this.get('values_remainder'),
is_sub_partitioned = this.get('is_sub_partitioned'),
sub_partition_keys = this.get('sub_partition_keys'),
msg;
// Have to clear existing validation before initiating current state
// validation only
this.errorModel.clear();
this.top.errorModel.clear();
if (_.isUndefined(partition_name) || _.isNull(partition_name) ||
String(partition_name).replace(/^\s+|\s+$/g, '') === '') {
msg = gettext('Partition name cannot be empty.');
this.errorModel.set('partition_name', msg);
return msg;
}
if (is_sub_partitioned && this.isNew() &&
!_.isNull(sub_partition_keys) && sub_partition_keys.length <= 0) {
msg = gettext('Please specify at least one key for partitioned table.');
this.top.errorModel.set('sub_partition_keys', msg);
return msg;
}
if (this.top.get('partition_type') === 'range') {
if (is_default !== true && (_.isUndefined(values_from) ||
_.isNull(values_from) || String(values_from).replace(/^\s+|\s+$/g, '') === '')) {
msg = gettext('For range partition From field cannot be empty.');
this.errorModel.set('values_from', msg);
return msg;
} else if (is_default !== true && (_.isUndefined(values_to) || _.isNull(values_to) ||
String(values_to).replace(/^\s+|\s+$/g, '') === '')) {
msg = gettext('For range partition To field cannot be empty.');
this.errorModel.set('values_to', msg);
return msg;
}
} else if (this.top.get('partition_type') === 'list') {
if (is_default !== true && (_.isUndefined(values_in) || _.isNull(values_in) ||
String(values_in).replace(/^\s+|\s+$/g, '') === '')) {
msg = gettext('For list partition In field cannot be empty.');
this.errorModel.set('values_in', msg);
return msg;
}
} else if (this.top.get('partition_type') === 'hash') {
if (_.isUndefined(values_modulus) || _.isNull(values_modulus) ||
String(values_modulus).replace(/^\s+|\s+$/g, '') === '') {
msg = gettext('For hash partition Modulus field cannot be empty.');
this.errorModel.set('values_modulus', msg);
return msg;
} else if (_.isUndefined(values_remainder) || _.isNull(values_remainder) ||
String(values_remainder).replace(/^\s+|\s+$/g, '') === '') {
msg = gettext('For hash partition Remainder field cannot be empty.');
this.errorModel.set('values_remainder', msg);
return msg;
}
}
return null;
},
});
});

View File

@ -113,7 +113,7 @@ export class PartitionKeysSchema extends BaseUISchema {
}
}
export class PartitionsSchema extends BaseUISchema {
constructor(nodeInfo, getCollations, getOperatorClass) {
constructor(nodeInfo, getCollations, getOperatorClass, getAttachTables=()=>[]) {
super({
oid: undefined,
is_attach: false,
@ -129,6 +129,7 @@ export class PartitionsSchema extends BaseUISchema {
});
this.subPartitionsObj = new PartitionKeysSchema([], getCollations, getOperatorClass);
this.getAttachTables = getAttachTables;
this.nodeInfo = nodeInfo;
}
@ -143,7 +144,7 @@ export class PartitionsSchema extends BaseUISchema {
mode: ['properties'],
},{
id: 'is_attach', label:gettext('Operation'), cell: 'select', type: 'select',
minWidth: 120, options: [
width: 120, disableResizing: true, options: [
{label: gettext('Attach'), value: true},
{label: gettext('Create'), value: false},
], controlProps: {allowClear: false},
@ -160,8 +161,34 @@ export class PartitionsSchema extends BaseUISchema {
return true;
},
},{
id: 'partition_name', label: gettext('Name'), type: 'text', cell:'text',
minWidth: 80, editable: function(state) {
id: 'partition_name', label: gettext('Name'),
type: (state)=>{
if(state.is_attach) {
return {
type: 'select',
options: this.getAttachTables,
controlProps: {allowClear: false},
};
} else {
return {
type: 'text',
};
}
},
cell: (state)=>{
if(state.is_attach) {
return {
cell: 'select',
options: this.getAttachTables,
controlProps: {allowClear: false},
};
} else {
return {
cell: 'text',
};
}
},
editable: function(state) {
if(obj.isNew(state)) {
return true;
}
@ -175,7 +202,7 @@ export class PartitionsSchema extends BaseUISchema {
}, noEmpty: true,
},{
id: 'is_default', label: gettext('Default'), type: 'switch', cell:'switch',
minWidth: 55, min_version: 110000,
width: 55, disableResizing: true, min_version: 110000,
editable: function(state) {
if(obj.top && (obj.top.sessData.partition_type == 'range' ||
obj.top.sessData.partition_type == 'list') && obj.isNew(state)
@ -194,7 +221,7 @@ export class PartitionsSchema extends BaseUISchema {
},
},{
id: 'values_from', label: gettext('From'), type:'text', cell: 'text',
minWidth: 80, deps: ['is_default'],
deps: ['is_default'],
editable: function(state) {
if(obj.top && obj.top.sessData.partition_type == 'range' && obj.isNew(state)
&& state.is_default !== true) {
@ -212,7 +239,7 @@ export class PartitionsSchema extends BaseUISchema {
},
{
id: 'values_to', label: gettext('To'), type:'text', cell: 'text',
minWidth: 80, deps: ['is_default'],
deps: ['is_default'],
editable: function(state) {
if(obj.top && obj.top.sessData.partition_type == 'range' && obj.isNew(state)
&& state.is_default !== true) {
@ -229,7 +256,7 @@ export class PartitionsSchema extends BaseUISchema {
},
},{
id: 'values_in', label: gettext('In'), type:'text', cell: 'text',
minWidth: 80, deps: ['is_default'],
deps: ['is_default'],
editable: function(state) {
if(obj.top && obj.top.sessData.partition_type == 'list' && obj.isNew(state)
&& state.is_default !== true) {
@ -246,7 +273,6 @@ export class PartitionsSchema extends BaseUISchema {
},
},{
id: 'values_modulus', label: gettext('Modulus'), type:'int', cell: 'int',
minWidth: 80,
editable: function(state) {
if(obj.top && obj.top.sessData.partition_type == 'hash' && obj.isNew(state)) {
return true;
@ -262,7 +288,6 @@ export class PartitionsSchema extends BaseUISchema {
},
},{
id: 'values_remainder', label: gettext('Remainder'), type:'int', cell: 'int',
minWidth: 80,
editable: function(state) {
if(obj.top && obj.top.sessData.partition_type == 'hash' && obj.isNew(state)) {
return true;

View File

@ -16,7 +16,7 @@ define('pgadmin.node.table', [
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.backgrid',
'pgadmin.node.schema.dir/child','pgadmin.node.schema.dir/schema_child_tree_node',
'pgadmin.browser.collection', 'pgadmin.node.column',
'pgadmin.node.constraints', 'pgadmin.browser.table.partition.utils',
'pgadmin.node.constraints',
], function(
tableFunctions,
gettext, url_for, $, _, pgAdmin, pgBrowser, Alertify, Backform, Backgrid,
@ -292,41 +292,6 @@ define('pgadmin.node.table', [
});
},
},
fetchColumnsInherits: function(arg) {
var self = this,
url = 'get_columns',
m = self.model.top || self.model,
data = undefined,
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 && pgBrowser.Nodes[cache_node]) || node;
m.trigger('pgadmin:view:fetching', m, self.field);
// Fetching Columns data for the selected table.
$.ajax({
async: false,
url: full_url,
data: arg,
})
.done(function(res) {
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);
data = (data && data.data) || [];
return data;
},
getSchema: function(treeNodeInfo, itemNodeData) {
return getNodeTableSchema(treeNodeInfo, itemNodeData, pgBrowser);
},

View File

@ -59,6 +59,9 @@ export function getNodeTableSchema(treeNodeInfo, itemNodeData, pgBrowser) {
},
()=>getNodeAjaxOptions('get_collations', pgBrowser.Nodes['collation'], treeNodeInfo, itemNodeData),
()=>getNodeAjaxOptions('get_op_class', pgBrowser.Nodes['table'], treeNodeInfo, itemNodeData),
()=>{
return getNodeAjaxOptions('get_attach_tables', tableNode, treeNodeInfo, itemNodeData, {useCache:false, urlWithId: true});
},
{
relowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name,
schema: treeNodeInfo.schema?._label,
@ -272,7 +275,8 @@ export class LikeSchema extends BaseUISchema {
}
export default class TableSchema extends BaseUISchema {
constructor(fieldOptions={}, nodeInfo, schemas, getPrivilegeRoleSchema, getColumns, getCollations, getOperatorClass, initValues) {
constructor(fieldOptions={}, nodeInfo, schemas, getPrivilegeRoleSchema, getColumns,
getCollations, getOperatorClass, getAttachTables, initValues) {
super({
name: undefined,
oid: undefined,
@ -316,7 +320,7 @@ export default class TableSchema extends BaseUISchema {
this.nodeInfo = nodeInfo;
this.getColumns = getColumns;
this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass);
this.partitionsObj = new PartitionsSchema(this.nodeInfo, getCollations, getOperatorClass, getAttachTables);
this.constraintsObj = this.schemas.constraints();
this.columnsSchema = this.schemas.columns();
this.vacuumSettingsSchema = this.schemas.vacuum_settings();

View File

@ -65,15 +65,22 @@ export function getNodeAjaxOptions(url, nodeObj, treeNodeInfo, itemNodeData, par
urlWithId: false,
jumpAfterNode: null,
useCache: true,
customGenerateUrl: null,
...params
};
return new Promise((resolve, reject)=>{
const api = getApiInstance();
let fullUrl = '';
if(url) {
fullUrl = generateNodeUrl.call(
nodeObj, treeNodeInfo, url, itemNodeData, otherParams.urlWithId, nodeObj.parent_type, otherParams.jumpAfterNode
);
if(otherParams.customGenerateUrl) {
fullUrl = otherParams.customGenerateUrl.call(
nodeObj, treeNodeInfo, url, itemNodeData, otherParams.urlWithId, otherParams.jumpAfterNode
);
} else {
fullUrl = generateNodeUrl.call(
nodeObj, treeNodeInfo, url, itemNodeData, otherParams.urlWithId, otherParams.jumpAfterNode
);
}
}
if (url) {

View File

@ -332,6 +332,9 @@ export default function DataGridView({
if(field.width) {
widthParms.width = field.width;
widthParms.minWidth = field.width;
} else {
widthParms.width = 75;
widthParms.minWidth = 75;
}
if(field.minWidth) {
widthParms.minWidth = field.minWidth;

View File

@ -213,7 +213,6 @@ var webpackShimConfig = {
'pgadmin.browser.toolbar': path.join(__dirname, './pgadmin/browser/static/js/toolbar'),
'pgadmin.browser.server.privilege': path.join(__dirname, './pgadmin/browser/server_groups/servers/static/js/privilege'),
'pgadmin.browser.server.variable': path.join(__dirname, './pgadmin/browser/server_groups/servers/static/js/variable'),
'pgadmin.browser.table.partition.utils': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils'),
'pgadmin.browser.utils': '/browser/js/utils',
'pgadmin.browser.wizard': path.join(__dirname, './pgadmin/browser/static/js/wizard'),
'pgadmin.dashboard': path.join(__dirname, './pgadmin/dashboard/static/js/dashboard'),