mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-30 20:43:50 -06:00
Fixed an issue introduced due to reloading of the tree due to changes in particular preferences (#7942)
* Fix an issue - when the object browser tree is being recreated due to reloading for changes in some of the preferences. Tree object returns object from the previous instance as 'selected', but - it does not have the 'treeNodeInfo' available. In this special case - we would consider that there is no node selected at that particular moment, and pass information accordingly. * Fixed 'New Connection' dialog issue after connecting a disconnected server. * Disable the 'Add' button in the GridHeader with form, when 'canAdd' flag is set to false. * Convert the access path to string array for correct comparision. * Check the access path type before comparison. When language is 'c', set the 'code' block read-only. * Enabled 'Strict' control for EPAS >= 95
This commit is contained in:
parent
100f59f78b
commit
b0cd028ff8
@ -16,15 +16,15 @@ class TokenHeaderSchema extends BaseUISchema {
|
|||||||
constructor(tokenOptions) {
|
constructor(tokenOptions) {
|
||||||
super({
|
super({
|
||||||
token: undefined,
|
token: undefined,
|
||||||
isNew: false,
|
isNew: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tokenOptions = tokenOptions;
|
this.tokenOptions = tokenOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
set isNewFTSConf(flag) {
|
set isNewFTSConf(flag) {
|
||||||
if (!this.state) return;
|
if (this.state)
|
||||||
this.state.data = {...this.state.data, isNew: flag};
|
this.state.data = {...this.state.data, isNew: flag};
|
||||||
}
|
}
|
||||||
|
|
||||||
getNewData(data) {
|
getNewData(data) {
|
||||||
@ -35,16 +35,17 @@ class TokenHeaderSchema extends BaseUISchema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get baseFields() {
|
get baseFields() {
|
||||||
let obj = this;
|
|
||||||
return [{
|
return [{
|
||||||
id: 'token', label: gettext('Tokens'), deps: ['isNew'],
|
id: 'token', label: gettext('Tokens'), deps: ['isNew'],
|
||||||
type: () => ({
|
type: () => ({
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: this.tokenOptions,
|
options: this.tokenOptions,
|
||||||
}),
|
}),
|
||||||
disabled: function() { return obj.isNewFTSConf; }
|
disabled: function() {
|
||||||
}, {
|
return this.state ? this.state.data.isNew : true;
|
||||||
id: 'isNew', visible: false, type: 'text',
|
}
|
||||||
|
},{
|
||||||
|
id: 'isNew', visible: false, type: 'text', exclude: true,
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,12 +161,13 @@ export default class FTSConfigurationSchema extends BaseUISchema {
|
|||||||
}, {
|
}, {
|
||||||
id: 'tokens', label: '', type: 'collection',
|
id: 'tokens', label: '', type: 'collection',
|
||||||
group: gettext('Tokens'), mode: ['create','edit'],
|
group: gettext('Tokens'), mode: ['create','edit'],
|
||||||
editable: false, schema: this.tokColumnSchema,
|
schema: this.tokColumnSchema,
|
||||||
headerSchema: this.tokHeaderSchema,
|
headerSchema: this.tokHeaderSchema,
|
||||||
headerFormVisible: true,
|
headerFormVisible: true,
|
||||||
GridHeader: DataGridFormHeader,
|
GridHeader: DataGridFormHeader,
|
||||||
uniqueCol : ['token'],
|
uniqueCol : ['token'],
|
||||||
canAdd: true, canEdit: false, canDelete: true,
|
canAdd: (state, helpderProps) => (helpderProps.mode !== 'create'),
|
||||||
|
canDelete: true,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -159,33 +159,21 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isGreaterThan95(state){
|
isLessThan95ORNonSPL(state) {
|
||||||
if (
|
return (
|
||||||
|
this.inCatalog() ||
|
||||||
this.node_info['node_info'].server.version < 90500 ||
|
this.node_info['node_info'].server.version < 90500 ||
|
||||||
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
||||||
state.lanname != 'edbspl'
|
state.lanname != 'edbspl'
|
||||||
) {
|
);
|
||||||
state.provolatile = null;
|
|
||||||
state.proisstrict = false;
|
|
||||||
state.procost = null;
|
|
||||||
state.proleakproof = false;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isGreaterThan96(state){
|
isLessThan96ORNonSPL(state){
|
||||||
if (
|
return (
|
||||||
this.node_info['node_info'].server.version < 90600 ||
|
this.node_info['node_info'].server.version < 90600 ||
|
||||||
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
this.node_info['node_info']['server'].server_type != 'ppas' ||
|
||||||
state.lanname != 'edbspl'
|
state.lanname != 'edbspl'
|
||||||
) {
|
);
|
||||||
state.proparallel = null;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -210,7 +198,7 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
if (this.type !== 'procedure') {
|
if (this.type !== 'procedure') {
|
||||||
obj.inCatalog(state);
|
obj.inCatalog(state);
|
||||||
} else {
|
} else {
|
||||||
obj.isGreaterThan95(state);
|
obj.isLessThan95ORNonSPL(state);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
noEmpty: true,
|
noEmpty: true,
|
||||||
@ -328,7 +316,7 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
{'label': 'VOLATILE', 'value': 'v'},
|
{'label': 'VOLATILE', 'value': 'v'},
|
||||||
{'label': 'STABLE', 'value': 's'},
|
{'label': 'STABLE', 'value': 's'},
|
||||||
{'label': 'IMMUTABLE', 'value': 'i'},
|
{'label': 'IMMUTABLE', 'value': 'i'},
|
||||||
], disabled: (this.type !== 'procedure') ? obj.inCatalog() : obj.isGreaterThan95,
|
], disabled: (this.type !== 'procedure') ? obj.inCatalog() : obj.isLessThan95ORNonSPL,
|
||||||
controlProps: {allowClear: false},
|
controlProps: {allowClear: false},
|
||||||
},{
|
},{
|
||||||
id: 'proretset', label: gettext('Returns a set?'), type: 'switch',
|
id: 'proretset', label: gettext('Returns a set?'), type: 'switch',
|
||||||
@ -336,8 +324,22 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
visible: obj.isVisible, readonly: obj.isReadonly,
|
visible: obj.isVisible, readonly: obj.isReadonly,
|
||||||
},{
|
},{
|
||||||
id: 'proisstrict', label: gettext('Strict?'), type: 'switch',
|
id: 'proisstrict', label: gettext('Strict?'), type: 'switch',
|
||||||
group: gettext('Options'), disabled: obj.inCatalog(),
|
group: gettext('Options'),
|
||||||
|
disabled: obj.inCatalog() ? true : obj.isLessThan95ORNonSPL,
|
||||||
deps: ['lanname'],
|
deps: ['lanname'],
|
||||||
|
depChange: (state, source) => (
|
||||||
|
(source[source.length - 1] !== 'lanname') ? undefined : (
|
||||||
|
obj.isLessThan95ORNonSPL(state)
|
||||||
|
) ? {
|
||||||
|
provolatile: null,
|
||||||
|
proisstrict: false,
|
||||||
|
procost: null,
|
||||||
|
proleakproof: false,
|
||||||
|
proparallel: null,
|
||||||
|
} : (
|
||||||
|
obj.isLessThan95ORNonSPL(state) ? { proparallel: null } : undefined
|
||||||
|
)
|
||||||
|
),
|
||||||
},{
|
},{
|
||||||
id: 'prosecdef', label: gettext('Security of definer?'),
|
id: 'prosecdef', label: gettext('Security of definer?'),
|
||||||
group: gettext('Options'), type: 'switch',
|
group: gettext('Options'), type: 'switch',
|
||||||
@ -357,13 +359,13 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
{'label': 'RESTRICTED', 'value': 'r'},
|
{'label': 'RESTRICTED', 'value': 'r'},
|
||||||
{'label': 'SAFE', 'value': 's'},
|
{'label': 'SAFE', 'value': 's'},
|
||||||
],
|
],
|
||||||
disabled: (this.type !== 'procedure') ? obj.inCatalog(): obj.isGreaterThan96,
|
disabled: (this.type !== 'procedure') ? obj.inCatalog(): obj.isLessThan96ORNonSPL,
|
||||||
min_version: 90600,
|
min_version: 90600,
|
||||||
controlProps: {allowClear: false},
|
controlProps: {allowClear: false},
|
||||||
},{
|
},{
|
||||||
id: 'procost', label: gettext('Estimated cost'), group: gettext('Options'),
|
id: 'procost', label: gettext('Estimated cost'), group: gettext('Options'),
|
||||||
cell:'string', type: 'text', deps: ['lanname'],
|
cell:'string', type: 'text', deps: ['lanname'],
|
||||||
disabled: (this.type !== 'procedure') ? obj.isDisabled: obj.isGreaterThan95,
|
disabled: (this.type !== 'procedure') ? obj.isDisabled : obj.isLessThan95ORNonSPL,
|
||||||
},{
|
},{
|
||||||
id: 'prorows', label: gettext('Estimated rows'), type: 'text',
|
id: 'prorows', label: gettext('Estimated rows'), type: 'text',
|
||||||
deps: ['proretset'], visible: obj.isVisible,
|
deps: ['proretset'], visible: obj.isVisible,
|
||||||
@ -378,7 +380,7 @@ export default class FunctionSchema extends BaseUISchema {
|
|||||||
},{
|
},{
|
||||||
id: 'proleakproof', label: gettext('Leak proof?'),
|
id: 'proleakproof', label: gettext('Leak proof?'),
|
||||||
group: gettext('Options'), cell:'boolean', type: 'switch', min_version: 90200,
|
group: gettext('Options'), cell:'boolean', type: 'switch', min_version: 90200,
|
||||||
disabled: (this.type !== 'procedure') ? obj.inCatalog(): obj.isGreaterThan95,
|
disabled: (this.type !== 'procedure') ? obj.inCatalog() : obj.isLessThan95ORNonSPL,
|
||||||
deps: ['lanname'],
|
deps: ['lanname'],
|
||||||
},{
|
},{
|
||||||
id: 'prosupportfunc', label: gettext('Support function'),
|
id: 'prosupportfunc', label: gettext('Support function'),
|
||||||
|
@ -161,10 +161,7 @@ export default class TriggerFunctionSchema extends BaseUISchema {
|
|||||||
type: 'sql', isFullTab: true,
|
type: 'sql', isFullTab: true,
|
||||||
mode: ['properties', 'create', 'edit'],
|
mode: ['properties', 'create', 'edit'],
|
||||||
group: gettext('Code'), deps: ['lanname'],
|
group: gettext('Code'), deps: ['lanname'],
|
||||||
visible: (state) => {
|
readonly: (state) => (obj.isDisabled() || state.lanname === 'c'),
|
||||||
return state.lanname !== 'c';
|
|
||||||
},
|
|
||||||
disabled: obj.isDisabled, readonly: obj.isReadonly,
|
|
||||||
},{
|
},{
|
||||||
id: 'probin', label: gettext('Object file'), cell: 'string',
|
id: 'probin', label: gettext('Object file'), cell: 'string',
|
||||||
type: 'text', group: gettext('Definition'), deps: ['lanname'],
|
type: 'text', group: gettext('Definition'), deps: ['lanname'],
|
||||||
@ -260,8 +257,8 @@ export default class TriggerFunctionSchema extends BaseUISchema {
|
|||||||
|
|
||||||
if (isEmptyString(state.service)) {
|
if (isEmptyString(state.service)) {
|
||||||
|
|
||||||
/* code validation*/
|
/* code validation */
|
||||||
if (isEmptyString(state.prosrc)) {
|
if (isEmptyString(state.prosrc) && state.lanname !== 'c') {
|
||||||
errmsg = gettext('Code cannot be empty.');
|
errmsg = gettext('Code cannot be empty.');
|
||||||
setError('prosrc', errmsg);
|
setError('prosrc', errmsg);
|
||||||
return true;
|
return true;
|
||||||
|
@ -77,7 +77,7 @@ export function DataGridFormHeader({tableEleRef}) {
|
|||||||
viewHelperProps,
|
viewHelperProps,
|
||||||
} = useContext(DataGridContext);
|
} = useContext(DataGridContext);
|
||||||
const {
|
const {
|
||||||
addOnTop, canAddRow, canEdit, expandEditOnAdd, headerFormVisible
|
canAdd, addOnTop, canAddRow, canEdit, expandEditOnAdd, headerFormVisible
|
||||||
} = options;
|
} = options;
|
||||||
const rows = table.getRowModel().rows;
|
const rows = table.getRowModel().rows;
|
||||||
|
|
||||||
@ -85,8 +85,12 @@ export function DataGridFormHeader({tableEleRef}) {
|
|||||||
const newRowIndex = useRef(-1);
|
const newRowIndex = useRef(-1);
|
||||||
const schemaState = useContext(SchemaStateContext);
|
const schemaState = useContext(SchemaStateContext);
|
||||||
const headerFormData = useRef({});
|
const headerFormData = useRef({});
|
||||||
const [addDisabled, setAddDisabled] = useState(canAddRow);
|
const [addDisabled, setAddDisabled] = useState(!canAdd || !canAddRow);
|
||||||
const {headerSchema} = field;
|
const {headerSchema} = field;
|
||||||
|
const disableAddButton = (flag) => {
|
||||||
|
if (!canAdd || !canAddRow) return;
|
||||||
|
setAddDisabled(flag);
|
||||||
|
};
|
||||||
|
|
||||||
const onAddClick = useCallback(() => {
|
const onAddClick = useCallback(() => {
|
||||||
|
|
||||||
@ -154,8 +158,8 @@ export function DataGridFormHeader({tableEleRef}) {
|
|||||||
showFooter={false}
|
showFooter={false}
|
||||||
onDataChange={(isDataChanged, dataChanged)=>{
|
onDataChange={(isDataChanged, dataChanged)=>{
|
||||||
headerFormData.current = dataChanged;
|
headerFormData.current = dataChanged;
|
||||||
setAddDisabled(
|
disableAddButton(
|
||||||
canAddRow && headerSchema.addDisabled(headerFormData.current)
|
headerSchema.addDisabled(headerFormData.current)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
hasSQL={false}
|
hasSQL={false}
|
||||||
|
@ -114,7 +114,7 @@ export const sessDataReducer = (state, action) => {
|
|||||||
return data;
|
return data;
|
||||||
|
|
||||||
case SCHEMA_STATE_ACTIONS.DEFERRED_DEPCHANGE:
|
case SCHEMA_STATE_ACTIONS.DEFERRED_DEPCHANGE:
|
||||||
data = getDepChange(action.path, data, state, action);
|
data = getDepChange(action.path, _.cloneDeep(data), state, action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,14 @@
|
|||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
const convertKeysToString = (arr) => (arr||[]).map((key) => String(key));
|
||||||
const isPathEqual = (path1, path2) => (
|
const isPathEqual = (path1, path2) => (
|
||||||
JSON.stringify(path1) === JSON.stringify(path2)
|
Array.isArray(path1) &&
|
||||||
|
Array.isArray(path2) &&
|
||||||
|
JSON.stringify(convertKeysToString(path1)) ===
|
||||||
|
JSON.stringify(convertKeysToString(path2))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
export const useFieldError = (path, schemaState, subscriberManager) => {
|
export const useFieldError = (path, schemaState, subscriberManager) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -38,7 +41,9 @@ export const useFieldError = (path, schemaState, subscriberManager) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const errors = schemaState?.errors || {};
|
const errors = schemaState?.errors || {};
|
||||||
const error = isPathEqual(errors.name, path) ? errors.message : null;
|
const error = (
|
||||||
|
Array.isArray(errors.name) && isPathEqual(errors.name, path)
|
||||||
|
) ? errors.message : null;
|
||||||
|
|
||||||
return {hasError: !_.isNull(error), error};
|
return {hasError: !_.isNull(error), error};
|
||||||
};
|
};
|
||||||
|
@ -67,13 +67,23 @@ export default function withStandardTabInfo(Component, tabId) {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
////////
|
||||||
|
// Special case:
|
||||||
|
//
|
||||||
|
// When the tree is being recreated during reloading on changes of some
|
||||||
|
// preferences, it is possible that the tree returns 'selected' node, but -
|
||||||
|
// it does not have the 'treeNodeInfo' as it was actually part of the
|
||||||
|
// previous instance of the tree.
|
||||||
|
//
|
||||||
|
// In that case - we consider that there is no node selected in the tree.
|
||||||
|
///////
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Component
|
<Component
|
||||||
{...props}
|
{...props}
|
||||||
nodeItem={nodeItem}
|
nodeItem={treeNodeInfo ? nodeItem : undefined}
|
||||||
nodeData={nodeData}
|
nodeData={treeNodeInfo ? nodeData : undefined}
|
||||||
node={node}
|
node={treeNodeInfo ? node : undefined}
|
||||||
treeNodeInfo={treeNodeInfo}
|
treeNodeInfo={treeNodeInfo}
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
isStale={isStale}
|
isStale={isStale}
|
||||||
|
@ -52,7 +52,7 @@ class NewConnectionSchema extends BaseUISchema {
|
|||||||
if(this.groupedServers?.length != 0) {
|
if(this.groupedServers?.length != 0) {
|
||||||
return Promise.resolve(this.groupedServers);
|
return Promise.resolve(this.groupedServers);
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject)=>{
|
return new Promise((resolve, reject) => {
|
||||||
this.api.get(url_for('sqleditor.get_new_connection_servers'))
|
this.api.get(url_for('sqleditor.get_new_connection_servers'))
|
||||||
.then(({data: respData})=>{
|
.then(({data: respData})=>{
|
||||||
let groupedOptions = [];
|
let groupedOptions = [];
|
||||||
@ -61,7 +61,7 @@ class NewConnectionSchema extends BaseUISchema {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* initial selection */
|
/* initial selection */
|
||||||
let foundServer = _.find(v, (o)=>o.value==obj.params.sid);
|
let foundServer = _.find(v, (o) => o.value == obj.params.sid);
|
||||||
foundServer && (foundServer.selected = true);
|
foundServer && (foundServer.selected = true);
|
||||||
groupedOptions.push({
|
groupedOptions.push({
|
||||||
label: k,
|
label: k,
|
||||||
@ -69,7 +69,7 @@ class NewConnectionSchema extends BaseUISchema {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
/* Will be re-used for changing icon when connected */
|
/* Will be re-used for changing icon when connected */
|
||||||
this.groupedServers = groupedOptions.map((group)=>{
|
this.groupedServers = groupedOptions.map((group) => {
|
||||||
return {
|
return {
|
||||||
label: group.label,
|
label: group.label,
|
||||||
options: group.options.map((o)=>({...o, selected: false})),
|
options: group.options.map((o)=>({...o, selected: false})),
|
||||||
@ -118,18 +118,19 @@ class NewConnectionSchema extends BaseUISchema {
|
|||||||
optionsLoaded: (res) => self.flatServers = flattenSelectOptions(res),
|
optionsLoaded: (res) => self.flatServers = flattenSelectOptions(res),
|
||||||
optionsReloadBasis: self.flatServers.map((s) => s.connected).join(''),
|
optionsReloadBasis: self.flatServers.map((s) => s.connected).join(''),
|
||||||
}),
|
}),
|
||||||
depChange: (state)=>{
|
depChange: (state) => {
|
||||||
/* Once the option is selected get the name */
|
/* Once the option is selected get the name */
|
||||||
/* Force sid to null, and set only if connected */
|
/* Force sid to null, and set only if connected */
|
||||||
let selectedServer = _.find(
|
let selectedServer = _.find(
|
||||||
self.flatServers, (s) => s.value == state.sid
|
self.flatServers, (s) => s.value == state.sid
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
server_name: selectedServer?.label,
|
server_name: selectedServer?.label,
|
||||||
did: null,
|
did: null,
|
||||||
user: null,
|
user: null,
|
||||||
role: null,
|
role: null,
|
||||||
sid: null,
|
sid: state.sid,
|
||||||
fgcolor: selectedServer?.fgcolor,
|
fgcolor: selectedServer?.fgcolor,
|
||||||
bgcolor: selectedServer?.bgcolor,
|
bgcolor: selectedServer?.bgcolor,
|
||||||
connected: selectedServer?.connected,
|
connected: selectedServer?.connected,
|
||||||
@ -138,6 +139,7 @@ class NewConnectionSchema extends BaseUISchema {
|
|||||||
deferredDepChange: (state, source, topState, actionObj) => {
|
deferredDepChange: (state, source, topState, actionObj) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let sid = actionObj.value;
|
let sid = actionObj.value;
|
||||||
|
|
||||||
if(!_.find(self.flatServers, (s) => s.value == sid)?.connected) {
|
if(!_.find(self.flatServers, (s) => s.value == sid)?.connected) {
|
||||||
this.connectServer(sid, state.user, null, (data) => {
|
this.connectServer(sid, state.user, null, (data) => {
|
||||||
self.setServerConnected(sid, data.icon);
|
self.setServerConnected(sid, data.icon);
|
||||||
|
Loading…
Reference in New Issue
Block a user