mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
Foreign Key fixes:
1. Auto FK related fixes. 2. Properties tab not showing columns. 3. Toggle button is editable even if set to read-only. 4. Dropdown placeholder should be blank for read-only/disabled. 5. Input control help text color on a dark theme. Fixes #6770
This commit is contained in:
parent
fc86faf51e
commit
a8c8ea69e3
@ -22,7 +22,7 @@ export default class CheckConstraintSchema extends BaseUISchema {
|
||||
if(_.isUndefined(this.nodeInfo)) {
|
||||
return true;
|
||||
}
|
||||
return !_.isUndefined(this.nodeInfo['table']);
|
||||
return _.isUndefined(this.nodeInfo['table']);
|
||||
}
|
||||
|
||||
isReadonly(state) {
|
||||
|
@ -214,7 +214,7 @@ export default class ExclusionConstraintSchema extends BaseUISchema {
|
||||
if(_.isUndefined(this.nodeInfo)) {
|
||||
return true;
|
||||
}
|
||||
return !_.isUndefined(this.nodeInfo['table']);
|
||||
return _.isUndefined(this.nodeInfo['table']);
|
||||
}
|
||||
|
||||
initialise(data) {
|
||||
|
@ -124,7 +124,7 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
columns: undefined,
|
||||
confupdtype: 'a',
|
||||
confdeltype: 'a',
|
||||
autoindex: true,
|
||||
autoindex: ForeignKeySchema.checkInTable(nodeInfo) ? false : true,
|
||||
coveringindex: undefined,
|
||||
hasindex:undefined,
|
||||
});
|
||||
@ -142,10 +142,14 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
}
|
||||
|
||||
get inTable() {
|
||||
if(_.isUndefined(this.nodeInfo)) {
|
||||
return ForeignKeySchema.checkInTable(this.nodeInfo);
|
||||
}
|
||||
|
||||
static checkInTable(nodeInfo) {
|
||||
if(_.isUndefined(nodeInfo)) {
|
||||
return true;
|
||||
}
|
||||
return !_.isUndefined(this.nodeInfo['table']);
|
||||
return _.isUndefined(nodeInfo['table']);
|
||||
}
|
||||
|
||||
changeColumnOptions(columns) {
|
||||
@ -231,23 +235,14 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
id: 'autoindex', label: gettext('Auto FK index?'),
|
||||
type: 'switch', group: gettext('Definition'),
|
||||
deps: ['name', 'hasindex'],
|
||||
disabled: (state)=>{
|
||||
readonly: (state)=>{
|
||||
if(!obj.isNew(state)) {
|
||||
return true;
|
||||
}
|
||||
// If we are in table edit mode then
|
||||
if(obj.inTable) {
|
||||
// user is trying to add new constraint which should allowed for Unique
|
||||
if(obj.isNew(state)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if(!obj.isNew(state) && state.autoindex && !isEmptyString(state.coveringindex)
|
||||
&& state.hasindex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(state.hasindex) {
|
||||
} else if(state.hasindex) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -256,10 +251,9 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
if(!obj.isNew(state)) {
|
||||
return {};
|
||||
}
|
||||
// If we are in table edit mode then
|
||||
// If we are in table edit mode
|
||||
if(obj.inTable) {
|
||||
// user is trying to add new constraint which should allowed for Unique
|
||||
if(obj.isNew(state)) {
|
||||
if(obj.isNew(state) && obj.top.isNew()) {
|
||||
return {autoindex: false, coveringindex: ''};
|
||||
}
|
||||
}
|
||||
@ -279,12 +273,7 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
mode: ['properties', 'create', 'edit'], group: gettext('Definition'),
|
||||
deps:['autoindex', 'hasindex'],
|
||||
disabled: (state)=>{
|
||||
if(!obj.isNew(state) && state.autoindex && !isEmptyString(state.coveringindex)) {
|
||||
return true;
|
||||
}
|
||||
if(state.hasindex) {
|
||||
return true;
|
||||
} else if(!state.autoindex) {
|
||||
if(!state.autoindex && !state.hasindex) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -304,7 +293,7 @@ export default class ForeignKeySchema extends BaseUISchema {
|
||||
},{
|
||||
id: 'columns', label: gettext('Columns'),
|
||||
group: gettext('Columns'), type: 'collection',
|
||||
mode: ['create', 'edit'],
|
||||
mode: ['create', 'edit', 'properties'],
|
||||
editable: false, schema: this.fkColumnSchema,
|
||||
headerSchema: this.fkHeaderSchema, headerVisible: (state)=>obj.isNew(state),
|
||||
CustomControl: DataGridViewWithHeaderForm,
|
||||
|
@ -81,7 +81,6 @@ const useStyles = makeStyles((theme)=>({
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
},
|
||||
tableCellHeader: {
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
|
@ -59,6 +59,7 @@ export default function(basicSettings) {
|
||||
},
|
||||
text: {
|
||||
primary: '#d4d4d4',
|
||||
muted: '#8A8A8A',
|
||||
},
|
||||
background: {
|
||||
paper: '#212121',
|
||||
|
@ -57,6 +57,7 @@ export default function(basicSettings) {
|
||||
},
|
||||
text: {
|
||||
primary: '#fff',
|
||||
muted: '#8b9cad',
|
||||
},
|
||||
background: {
|
||||
paper: '#010B15',
|
||||
|
@ -325,6 +325,11 @@ function getFinalTheme(baseTheme) {
|
||||
}
|
||||
}
|
||||
},
|
||||
MuiFormHelperText: {
|
||||
root: {
|
||||
color: baseTheme.palette.text.muted,
|
||||
},
|
||||
},
|
||||
}
|
||||
}, baseTheme);
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ export default function(basicSettings) {
|
||||
},
|
||||
text: {
|
||||
primary: '#222',
|
||||
muted: '#646B82',
|
||||
},
|
||||
background: {
|
||||
paper: '#fff',
|
||||
|
@ -511,7 +511,7 @@ export function InputToggle({cid, value, onChange, options, disabled, readonly,
|
||||
{
|
||||
(options||[]).map((option)=>{
|
||||
const isSelected = option.value === value;
|
||||
const isDisabled = disabled || (readonly && isSelected);
|
||||
const isDisabled = disabled || (readonly && !isSelected);
|
||||
return (
|
||||
<ToggleButton key={option.label} value={option.value} component={isSelected ? PrimaryButton : DefaultButton}
|
||||
disabled={isDisabled} aria-label={option.label}>
|
||||
@ -766,7 +766,7 @@ export function InputSelect({
|
||||
menuPortalTarget: document.body,
|
||||
styles: styles,
|
||||
inputId: cid,
|
||||
placeholder: controlProps.placeholder || gettext('Select...'),
|
||||
placeholder: (readonly || disabled) ? '' : controlProps.placeholder || gettext('Select...'),
|
||||
...otherProps,
|
||||
...props
|
||||
};
|
||||
|
@ -1,162 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {ModelValidation} from 'sources/browser/server_groups/servers/model_validation';
|
||||
|
||||
describe('Server#ModelValidation', () => {
|
||||
describe('When validating a server parameters', () => {
|
||||
let model;
|
||||
let modelValidation;
|
||||
beforeEach(() => {
|
||||
model = {
|
||||
errorModel: jasmine.createSpyObj('errorModel', ['set', 'unset']),
|
||||
allValues: {},
|
||||
get: function (key) {
|
||||
return this.allValues[key];
|
||||
},
|
||||
set: function (key, value) {
|
||||
this.key = value;
|
||||
},
|
||||
sessAttrs: {},
|
||||
};
|
||||
model.isNew = jasmine.createSpy('isNew');
|
||||
modelValidation = new ModelValidation(model);
|
||||
});
|
||||
|
||||
describe('When all parameters are valid', () => {
|
||||
beforeEach(() => {
|
||||
model.isNew.and.returnValue(true);
|
||||
model.allValues['name'] = 'some name';
|
||||
model.allValues['username'] = 'some username';
|
||||
model.allValues['port'] = 12345;
|
||||
});
|
||||
|
||||
describe('No service id', () => {
|
||||
it('does not set any error in the model', () => {
|
||||
model.allValues['host'] = 'some host';
|
||||
model.allValues['db'] = 'some db';
|
||||
model.allValues['hostaddr'] = '1.1.1.1';
|
||||
expect(modelValidation.validate()).toBeNull();
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Service id and Maintenance database present', () => {
|
||||
it('does not set any error in the model', () => {
|
||||
model.allValues['service'] = 'asdfg';
|
||||
model.allValues['db'] = 'postgres';
|
||||
expect(modelValidation.validate()).toBeNull();
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Service id present', () => {
|
||||
it('sets empty service name which should throw an error', () => {
|
||||
model.allValues['service'] = '';
|
||||
expect(modelValidation.validate()).toEqual('Either Host name, Address or Service must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
host: 'Either Host name, Address or Service must be specified.',
|
||||
hostaddr: 'Either Host name, Address or Service must be specified.',
|
||||
db: 'Maintenance database must be specified.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SSH Tunnel parameters', () => {
|
||||
beforeEach(() => {
|
||||
model.isNew.and.returnValue(true);
|
||||
model.allValues['name'] = 'some name';
|
||||
model.allValues['username'] = 'some username';
|
||||
model.allValues['port'] = 12345;
|
||||
model.allValues['host'] = 'some host';
|
||||
model.allValues['db'] = 'some db';
|
||||
model.allValues['hostaddr'] = '1.1.1.1';
|
||||
model.allValues['use_ssh_tunnel'] = 1;
|
||||
});
|
||||
it('sets the "SSH Tunnel host must be specified." error', () => {
|
||||
model.allValues['tunnel_port'] = 22;
|
||||
model.allValues['tunnel_username'] = 'user1';
|
||||
expect(modelValidation.validate()).toEqual('SSH Tunnel host must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
tunnel_host:'SSH Tunnel host must be specified.',
|
||||
});
|
||||
});
|
||||
it('sets the "SSH Tunnel port must be specified." error', () => {
|
||||
model.allValues['tunnel_host'] = 'host';
|
||||
model.allValues['tunnel_username'] = 'user1';
|
||||
expect(modelValidation.validate()).toEqual('SSH Tunnel port must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
tunnel_port:'SSH Tunnel port must be specified.',
|
||||
});
|
||||
});
|
||||
it('sets the "SSH Tunnel username be specified." error', () => {
|
||||
model.allValues['tunnel_host'] = 'host';
|
||||
model.allValues['tunnel_port'] = 22;
|
||||
expect(modelValidation.validate()).toEqual('SSH Tunnel username must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
tunnel_username:'SSH Tunnel username must be specified.',
|
||||
});
|
||||
});
|
||||
it('sets the "SSH Tunnel identity file be specified." error', () => {
|
||||
model.allValues['tunnel_host'] = 'host';
|
||||
model.allValues['tunnel_port'] = 22;
|
||||
model.allValues['tunnel_username'] = 'user1';
|
||||
model.allValues['tunnel_authentication'] = 1;
|
||||
expect(modelValidation.validate()).toEqual('SSH Tunnel identity file must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
tunnel_identity_file:'SSH Tunnel identity file must be specified.',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When no parameters are valid', () => {
|
||||
describe('Service id not present', () => {
|
||||
it('does not set any error in the model', () => {
|
||||
expect(modelValidation.validate()).toEqual('Name must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledTimes(1);
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
name: 'Name must be specified.',
|
||||
host: 'Either Host name, Address or Service must be specified.',
|
||||
hostaddr: 'Either Host name, Address or Service must be specified.',
|
||||
db: 'Maintenance database must be specified.',
|
||||
username: 'Username must be specified.',
|
||||
port: 'Port must be specified.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Host address is not valid', () => {
|
||||
it('sets the "Host address must be a valid IPv4 or IPv6 address" error', () => {
|
||||
model.allValues['hostaddr'] = 'something that is not an ip address';
|
||||
expect(modelValidation.validate()).toEqual('Host address must be valid IPv4 or IPv6 address.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledTimes(1);
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
name: 'Name must be specified.',
|
||||
hostaddr: 'Host address must be valid IPv4 or IPv6 address.',
|
||||
db: 'Maintenance database must be specified.',
|
||||
username: 'Username must be specified.',
|
||||
port: 'Port must be specified.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Service id present', () => {
|
||||
it('set the "Maintenance database must be specified." error', () => {
|
||||
model.allValues['name'] = 'some name';
|
||||
model.allValues['service'] = 'asdfg';
|
||||
expect(modelValidation.validate()).toEqual('Maintenance database must be specified.');
|
||||
expect(model.errorModel.set).toHaveBeenCalledWith({
|
||||
db: 'Maintenance database must be specified.',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -142,7 +142,6 @@ describe('CheckConstraintSchema', ()=>{
|
||||
});
|
||||
|
||||
/* If partitioned table */
|
||||
schemaObj.nodeInfo = {table: {}};
|
||||
schemaObj.top = {
|
||||
sessData: {
|
||||
is_partitioned: true,
|
||||
|
@ -196,7 +196,6 @@ describe('ExclusionConstraintSchema', ()=>{
|
||||
it('depChange', ()=>{
|
||||
let state = {columns: [{local_column: 'id'}]};
|
||||
|
||||
schemaObj.nodeInfo = {table: {}};
|
||||
expect(getFieldDepChange(schemaObj, 'columns')(state, ['columns', 0], null, {
|
||||
type: SCHEMA_STATE_ACTIONS.DELETE_ROW,
|
||||
oldState: {
|
||||
|
@ -171,6 +171,7 @@ describe('ForeignKeySchema', ()=>{
|
||||
let state = {columns: [{local_column: 'id'}]};
|
||||
let actionObj = {oldState:{name: 'fkname'}};
|
||||
|
||||
schemaObj.nodeInfo = {table: {}};
|
||||
state.autoindex = true;
|
||||
state.name = 'fkname';
|
||||
expect(getFieldDepChange(schemaObj, 'autoindex')(state, null, null, actionObj)).toEqual({
|
||||
@ -196,7 +197,8 @@ describe('ForeignKeySchema', ()=>{
|
||||
expect(getFieldDepChange(schemaObj, 'autoindex')(state, null, null, actionObj)).toEqual({});
|
||||
|
||||
state.oid = null;
|
||||
schemaObj.nodeInfo = {table: {}};
|
||||
schemaObj.nodeInfo = {};
|
||||
schemaObj.top = schemaObj;
|
||||
expect(getFieldDepChange(schemaObj, 'autoindex')(state, null, null, actionObj)).toEqual({
|
||||
autoindex: false,
|
||||
coveringindex: '',
|
||||
|
Loading…
Reference in New Issue
Block a user