mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
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:
parent
c32a325c11
commit
0228d16990
@ -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 = [];
|
||||
|
@ -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,
|
||||
|
@ -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'),
|
||||
|
@ -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;
|
||||
},
|
||||
});
|
||||
|
||||
});
|
@ -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;
|
||||
|
@ -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);
|
||||
},
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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'),
|
||||
|
Loading…
Reference in New Issue
Block a user