mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-21 16:27:39 -06:00
Fixes the Variable Schema UI issues and InlineView bug reported in #7884
* Show the icon for the 'Reset' button. (Reference #7884) * Reload the server list after connecting to a server in the 'New connection' dialog (QueryTool). (Reference: #7884) * Pass the grid path during the bulk update (click on a radio action) * Don't assign the cell value to the 'rowValue' variable. * Don't rely on the 'optionsLoaded' for setting the variable types as it is loaded asynchronously, and variable types data may not be available while rendering the 'value' cell. (Fixes #7884) * Fixed a type while checking for the 'inline-group'. fixes (#7884) * 'vnameOptions' can be a Promise function too, hence - taken care accrodingly. * Introduced a parameter 'reloadOnDepChanges' in the BaseSchemaUI field to force reload the control on value change for one of the dependencies. * Reload on the components in case of dependent value changes. * Introduced 'useSchemaStateSubscriber', which generates a state subscriber mananager instance. It helps multiple subscribers in a single control as we could have multiple subscribe within a control. (For example - value, options, errors, etc). * Fixed all the issues reported (#7884)
This commit is contained in:
parent
98d703645c
commit
5e96f0fd61
@ -96,7 +96,8 @@ class ForeignKeyHeaderSchema extends BaseUISchema {
|
||||
return state._disable_references;
|
||||
}
|
||||
},{
|
||||
id: 'referenced', label: gettext('Referencing'), editable: false, deps: ['references'],
|
||||
id: 'referenced', label: gettext('Referencing'), editable: false,
|
||||
deps: ['references'],
|
||||
type: (state)=>{
|
||||
return {
|
||||
type: 'select',
|
||||
|
@ -59,6 +59,8 @@ export default class VariableSchema extends BaseUISchema {
|
||||
this.varTypes = {};
|
||||
this.keys = keys;
|
||||
this.allReadOnly = false;
|
||||
|
||||
setTimeout(() => this.setVarTypes(vnameOptions), 0);
|
||||
}
|
||||
|
||||
setAllReadOnly(isReadOnly) {
|
||||
@ -66,11 +68,19 @@ export default class VariableSchema extends BaseUISchema {
|
||||
}
|
||||
|
||||
setVarTypes(options) {
|
||||
options.forEach((option)=>{
|
||||
let optPromise = options;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
optPromise = options();
|
||||
}
|
||||
|
||||
Promise.resolve(optPromise).then((res) => {
|
||||
res.forEach((option) => {
|
||||
this.varTypes[option.value] = {
|
||||
...option,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getPlaceHolderMsg(variable) {
|
||||
@ -145,13 +155,10 @@ export default class VariableSchema extends BaseUISchema {
|
||||
},
|
||||
{
|
||||
id: 'name', label: gettext('Name'), type:'text',
|
||||
editable: function(state) {
|
||||
return obj.isNew(state) || !obj.allReadOnly;
|
||||
},
|
||||
editable: (state) => (obj.isNew(state) || !obj.allReadOnly),
|
||||
cell: () => ({
|
||||
cell: 'select',
|
||||
options: this.vnameOptions,
|
||||
optionsLoaded: (options)=>{obj.setVarTypes(options);},
|
||||
options: obj.vnameOptions,
|
||||
controlProps: { allowClear: false },
|
||||
}),
|
||||
},
|
||||
@ -167,7 +174,7 @@ export default class VariableSchema extends BaseUISchema {
|
||||
deps: ['name'], editable: !obj.allReadOnly,
|
||||
depChange: (state, source) => {
|
||||
if(source[source.length-1] == 'name') {
|
||||
let variable = this.varTypes[state.name];
|
||||
let variable = obj.varTypes[state.name];
|
||||
if(variable.vartype === 'bool'){
|
||||
return {
|
||||
value: false,
|
||||
@ -179,18 +186,19 @@ export default class VariableSchema extends BaseUISchema {
|
||||
}
|
||||
},
|
||||
cell: (row) => {
|
||||
let variable = this.varTypes[row.name];
|
||||
return this.getValueFieldProps(variable);
|
||||
let variable = obj.varTypes[row.name];
|
||||
return obj.getValueFieldProps(variable);
|
||||
}
|
||||
},
|
||||
{id: 'database', label: gettext('Database'), type: 'text',
|
||||
cell: ()=>({cell: 'select', options: this.databaseOptions }),
|
||||
{
|
||||
id: 'database', label: gettext('Database'), type: 'text',
|
||||
cell: ()=>({cell: 'select', options: obj.databaseOptions }),
|
||||
},
|
||||
{id: 'role', label: gettext('Role'), type: 'text',
|
||||
cell: ()=>({cell: 'select', options: this.roleOptions,
|
||||
controlProps: {
|
||||
allowClear: false,
|
||||
}
|
||||
{
|
||||
id: 'role', label: gettext('Role'), type: 'text',
|
||||
cell: () => ({
|
||||
cell: 'select', options: obj.roleOptions,
|
||||
controlProps: { allowClear: false },
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
@ -65,10 +65,16 @@ class ChangePasswordSchema extends BaseUISchema {
|
||||
|
||||
export default function ChangePasswordContent({getInitData=() => { /*This is intentional (SonarQube)*/ },
|
||||
onSave, onClose, hasCsrfToken=false, showUser=true}) {
|
||||
const schema=React.useRef(null);
|
||||
if (!schema.current)
|
||||
schema.current = new ChangePasswordSchema(
|
||||
'', false, hasCsrfToken, showUser
|
||||
);
|
||||
|
||||
return <SchemaView
|
||||
formType={'dialog'}
|
||||
getInitData={getInitData}
|
||||
schema={new ChangePasswordSchema('', false, hasCsrfToken, showUser)}
|
||||
schema={schema.current}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
|
@ -33,7 +33,9 @@ import CustomPropTypes from 'sources/custom_prop_types';
|
||||
|
||||
import { StyleDataGridBox } from '../StyledComponents';
|
||||
import { SchemaStateContext } from '../SchemaState';
|
||||
import { useFieldOptions, useFieldValue } from '../hooks';
|
||||
import {
|
||||
useFieldOptions, useFieldValue, useSchemaStateSubscriber,
|
||||
} from '../hooks';
|
||||
import { registerView } from '../registry';
|
||||
import { listenDepChanges } from '../utils';
|
||||
|
||||
@ -49,20 +51,16 @@ export default function DataGridView({
|
||||
}) {
|
||||
const pgAdmin = usePgAdmin();
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
const subscriberManager = useSchemaStateSubscriber(setRefreshKey);
|
||||
const schemaState = useContext(SchemaStateContext);
|
||||
const options = useFieldOptions(
|
||||
accessPath, schemaState, refreshKey, setRefreshKey
|
||||
);
|
||||
const options = useFieldOptions(accessPath, schemaState, subscriberManager);
|
||||
const value = useFieldValue(accessPath, schemaState);
|
||||
const schema = field.schema;
|
||||
const features = useRef();
|
||||
|
||||
// Update refresh key on changing the number of rows.
|
||||
useFieldValue(
|
||||
[...accessPath, 'length'], schemaState, refreshKey,
|
||||
(newKey) => {
|
||||
setRefreshKey(newKey);
|
||||
}
|
||||
[...accessPath, 'length'], schemaState, subscriberManager
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -16,7 +16,9 @@ import { evalFunc } from 'sources/utils';
|
||||
import { MappedCellControl } from '../MappedControl';
|
||||
import { SCHEMA_STATE_ACTIONS, SchemaStateContext } from '../SchemaState';
|
||||
import { flatternObject } from '../common';
|
||||
import { useFieldOptions, useFieldValue } from '../hooks';
|
||||
import {
|
||||
useFieldOptions, useFieldValue, useSchemaStateSubscriber
|
||||
} from '../hooks';
|
||||
import { listenDepChanges } from '../utils';
|
||||
|
||||
import { DataGridContext, DataGridRowContext } from './context';
|
||||
@ -25,14 +27,17 @@ import { DataGridContext, DataGridRowContext } from './context';
|
||||
export function getMappedCell({field}) {
|
||||
const Cell = ({reRenderRow, getValue}) => {
|
||||
|
||||
const [key, setKey] = useState(0);
|
||||
const [, setKey] = useState(0);
|
||||
const subscriberManager = useSchemaStateSubscriber(setKey);
|
||||
const schemaState = useContext(SchemaStateContext);
|
||||
const { dataDispatch, accessPath } = useContext(DataGridContext);
|
||||
const { rowAccessPath, row } = useContext(DataGridRowContext);
|
||||
const colAccessPath = schemaState.accessPath(rowAccessPath, field.id);
|
||||
|
||||
let colOptions = useFieldOptions(colAccessPath, schemaState, key, setKey);
|
||||
let value = useFieldValue(colAccessPath, schemaState, key, setKey);
|
||||
let colOptions = useFieldOptions(
|
||||
colAccessPath, schemaState, subscriberManager
|
||||
);
|
||||
let value = useFieldValue(colAccessPath, schemaState, subscriberManager);
|
||||
let rowValue = useFieldValue(rowAccessPath, schemaState);
|
||||
|
||||
listenDepChanges(colAccessPath, field, true, schemaState);
|
||||
|
@ -15,7 +15,9 @@ import CustomPropTypes from 'sources/custom_prop_types';
|
||||
|
||||
import { FieldControl } from './FieldControl';
|
||||
import { SchemaStateContext } from './SchemaState';
|
||||
import { useFieldSchema, useFieldValue } from './hooks';
|
||||
import {
|
||||
useFieldSchema, useFieldValue, useSchemaStateSubscriber,
|
||||
} from './hooks';
|
||||
import { registerView } from './registry';
|
||||
import { createFieldControls, listenDepChanges } from './utils';
|
||||
|
||||
@ -23,13 +25,15 @@ import { createFieldControls, listenDepChanges } from './utils';
|
||||
export default function FieldSetView({
|
||||
field, accessPath, dataDispatch, viewHelperProps, controlClassName,
|
||||
}) {
|
||||
const [key, setRefreshKey] = useState(0);
|
||||
const [, setKey] = useState(0);
|
||||
const subscriberManager = useSchemaStateSubscriber(setKey);
|
||||
const schema = field.schema;
|
||||
const schemaState = useContext(SchemaStateContext);
|
||||
const value = useFieldValue(accessPath, schemaState);
|
||||
const options = useFieldSchema(
|
||||
field, accessPath, value, viewHelperProps, schemaState, key, setRefreshKey
|
||||
field, accessPath, value, viewHelperProps, schemaState, subscriberManager
|
||||
);
|
||||
|
||||
const label = field.label;
|
||||
|
||||
listenDepChanges(accessPath, field, options.visible, schemaState);
|
||||
|
@ -27,7 +27,9 @@ import { FieldControl } from './FieldControl';
|
||||
import { SQLTab } from './SQLTab';
|
||||
import { FormContentBox } from './StyledComponents';
|
||||
import { SchemaStateContext } from './SchemaState';
|
||||
import { useFieldSchema, useFieldValue } from './hooks';
|
||||
import {
|
||||
useFieldSchema, useFieldValue, useSchemaStateSubscriber,
|
||||
} from './hooks';
|
||||
import { registerView, View } from './registry';
|
||||
import { createFieldControls, listenDepChanges } from './utils';
|
||||
|
||||
@ -62,10 +64,11 @@ export default function FormView({
|
||||
showError=false, resetKey, focusOnFirstInput=false
|
||||
}) {
|
||||
const [key, setKey] = useState(0);
|
||||
const subscriberManager = useSchemaStateSubscriber(setKey);
|
||||
const schemaState = useContext(SchemaStateContext);
|
||||
const value = useFieldValue(accessPath, schemaState);
|
||||
const { visible } = useFieldSchema(
|
||||
field, accessPath, value, viewHelperProps, schemaState, key, setKey
|
||||
field, accessPath, value, viewHelperProps, schemaState, subscriberManager
|
||||
);
|
||||
|
||||
const [tabValue, setTabValue] = useState(0);
|
||||
@ -106,13 +109,12 @@ export default function FormView({
|
||||
|
||||
useEffect(() => {
|
||||
// Refresh on message changes.
|
||||
return schemaState.subscribe(
|
||||
['errors', 'message'],
|
||||
return subscriberManager.current?.add(
|
||||
schemaState, ['errors', 'message'], 'states',
|
||||
(newState, prevState) => {
|
||||
if (_.isUndefined(newState) || _.isUndefined(prevState));
|
||||
setKey(Date.now());
|
||||
},
|
||||
'states'
|
||||
if (_.isUndefined(newState) || _.isUndefined(prevState))
|
||||
subscriberManager.current?.signal();
|
||||
}
|
||||
);
|
||||
}, [key]);
|
||||
|
||||
|
@ -28,7 +28,7 @@ import { evalFunc } from 'sources/utils';
|
||||
import { SchemaStateContext } from './SchemaState';
|
||||
import { isValueEqual } from './common';
|
||||
import {
|
||||
useFieldOptions, useFieldValue, useFieldError
|
||||
useFieldOptions, useFieldValue, useFieldError, useSchemaStateSubscriber,
|
||||
} from './hooks';
|
||||
import { listenDepChanges } from './utils';
|
||||
|
||||
@ -339,22 +339,15 @@ export const MappedFormControl = ({
|
||||
}) => {
|
||||
const checkIsMounted = useIsMounted();
|
||||
const [key, setKey] = useState(0);
|
||||
const subscriberManager = useSchemaStateSubscriber(setKey);
|
||||
const schemaState = useContext(SchemaStateContext);
|
||||
const state = schemaState.data;
|
||||
const avoidRenderingWhenNotMounted = (newKey) => {
|
||||
if (checkIsMounted()) {
|
||||
setKey(newKey);
|
||||
}
|
||||
const value = useFieldValue(accessPath, schemaState, subscriberManager);
|
||||
const options = useFieldOptions(accessPath, schemaState, subscriberManager);
|
||||
const {hasError} = useFieldError(accessPath, schemaState, subscriberManager);
|
||||
const avoidRenderingWhenNotMounted = (...args) => {
|
||||
if (checkIsMounted()) subscriberManager.current?.signal(...args);
|
||||
};
|
||||
const value = useFieldValue(
|
||||
accessPath, schemaState, key, avoidRenderingWhenNotMounted
|
||||
);
|
||||
const options = useFieldOptions(
|
||||
accessPath, schemaState, key, avoidRenderingWhenNotMounted
|
||||
);
|
||||
const { hasError } = useFieldError(
|
||||
accessPath, schemaState, key, avoidRenderingWhenNotMounted
|
||||
);
|
||||
|
||||
const origOnChange = onChange;
|
||||
|
||||
@ -369,7 +362,10 @@ export const MappedFormControl = ({
|
||||
if (!isValueEqual(changedValue, currValue)) origOnChange(changedValue);
|
||||
};
|
||||
|
||||
listenDepChanges(accessPath, field, options.visible, schemaState);
|
||||
const depVals = listenDepChanges(
|
||||
accessPath, field, options.visible, schemaState, state,
|
||||
avoidRenderingWhenNotMounted
|
||||
);
|
||||
|
||||
let newProps = {
|
||||
...props,
|
||||
@ -394,14 +390,17 @@ export const MappedFormControl = ({
|
||||
newProps.onClick = ()=>{
|
||||
origOnClick?.();
|
||||
};
|
||||
|
||||
// FIXME:: Get this list from the option registry.
|
||||
const memDeps = ['disabled', 'visible', 'readonly'].map(
|
||||
option => options[option]
|
||||
);
|
||||
|
||||
memDeps.push(value);
|
||||
memDeps.push(hasError);
|
||||
memDeps.push(key);
|
||||
memDeps.push(JSON.stringify(accessPath));
|
||||
memDeps.push(depVals);
|
||||
|
||||
// Filter out garbage props if any using ALLOWED_PROPS_FIELD.
|
||||
return useMemo(
|
||||
|
@ -12,6 +12,7 @@ import { useFieldOptions } from './useFieldOptions';
|
||||
import { useFieldValue } from './useFieldValue';
|
||||
import { useSchemaState } from './useSchemaState';
|
||||
import { useFieldSchema } from './useFieldSchema';
|
||||
import { useSchemaStateSubscriber } from './useSchemaStateSubscriber';
|
||||
|
||||
|
||||
export {
|
||||
@ -20,4 +21,5 @@ export {
|
||||
useFieldValue,
|
||||
useFieldSchema,
|
||||
useSchemaState,
|
||||
useSchemaStateSubscriber,
|
||||
};
|
||||
|
@ -9,26 +9,36 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const isPathEqual = (path1, path2) => (
|
||||
JSON.stringify(path1) === JSON.stringify(path2)
|
||||
);
|
||||
|
||||
|
||||
export const useFieldError = (path, schemaState, subscriberManager) => {
|
||||
|
||||
export const useFieldError = (
|
||||
path, schemaState, key, setRefreshKey
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!schemaState || !setRefreshKey) return;
|
||||
if (!schemaState || !subscriberManager?.current) return;
|
||||
|
||||
const checkPathError = (newState, prevState) => {
|
||||
if (prevState.name !== path && newState.name !== path) return;
|
||||
// We don't need to redraw the control on message change.
|
||||
if (prevState.name === newState.name) return;
|
||||
if ((
|
||||
!isPathEqual(prevState.name, path) &&
|
||||
!isPathEqual(newState.name, path)
|
||||
) || (
|
||||
isPathEqual(prevState.name, newState.name) &&
|
||||
prevState.message == newState.message
|
||||
)) return;
|
||||
|
||||
setRefreshKey({id: Date.now()});
|
||||
subscriberManager.current?.signal();
|
||||
};
|
||||
|
||||
return schemaState.subscribe(['errors'], checkPathError, 'states');
|
||||
}, [key, schemaState?._id]);
|
||||
return subscriberManager.current?.add(
|
||||
schemaState, ['errors'], 'states', checkPathError
|
||||
);
|
||||
});
|
||||
|
||||
const errors = schemaState?.errors || {};
|
||||
const error = errors.name === path ? errors.message : null;
|
||||
const error = isPathEqual(errors.name, path) ? errors.message : null;
|
||||
|
||||
return {hasError: !_.isNull(error), error};
|
||||
};
|
||||
|
@ -10,16 +10,13 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
|
||||
export const useFieldOptions = (
|
||||
path, schemaState, key, setRefreshKey
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!schemaState) return;
|
||||
export const useFieldOptions = (path, schemaState, subscriberManager) => {
|
||||
|
||||
return schemaState.subscribe(
|
||||
path, () => setRefreshKey?.({id: Date.now()}), 'options'
|
||||
);
|
||||
}, [key, schemaState?._id]);
|
||||
useEffect(() => {
|
||||
if (!schemaState || !subscriberManager?.current) return;
|
||||
|
||||
return subscriberManager.current?.add(schemaState, path, 'options');
|
||||
});
|
||||
|
||||
return schemaState?.options(path) || {visible: true};
|
||||
};
|
||||
|
@ -14,32 +14,32 @@ import { booleanEvaluator } from '../options';
|
||||
|
||||
|
||||
export const useFieldSchema = (
|
||||
field, accessPath, value, viewHelperProps, schemaState, key, setRefreshKey
|
||||
field, accessPath, value, viewHelperProps, schemaState, subscriberManager
|
||||
) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!schemaState || !field) return;
|
||||
if (!schemaState || !field || !subscriberManager?.current) return;
|
||||
|
||||
// It already has 'id', 'options' is already evaluated.
|
||||
if (field.id)
|
||||
return schemaState.subscribe(
|
||||
accessPath, () => setRefreshKey?.({id: Date.now()}), 'options'
|
||||
);
|
||||
return subscriberManager.current?.add(schemaState, accessPath, 'options');
|
||||
|
||||
// There are no dependencies.
|
||||
if (!_.isArray(field?.deps)) return;
|
||||
|
||||
// Subscribe to all the dependents.
|
||||
const unsubscribers = field.deps.map((dep) => (
|
||||
schemaState.subscribe(
|
||||
accessPath.concat(dep), () => setRefreshKey?.({id: Date.now()}),
|
||||
'value'
|
||||
subscriberManager.current?.add(
|
||||
schemaState, accessPath.concat(dep), 'value'
|
||||
)
|
||||
));
|
||||
|
||||
return () => {
|
||||
unsubscribers.forEach(unsubscribe => unsubscribe());
|
||||
unsubscribers.forEach(
|
||||
unsubscribe => subscriberManager.current?.remove(unsubscribe)
|
||||
);
|
||||
};
|
||||
}, [key, schemaState?._id]);
|
||||
});
|
||||
|
||||
if (!field) return { visible: true };
|
||||
if (field.id) return schemaState?.options(accessPath);
|
||||
|
@ -10,16 +10,13 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
|
||||
export const useFieldValue = (
|
||||
path, schemaState, key, setRefreshKey
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!schemaState || !setRefreshKey) return;
|
||||
export const useFieldValue = (path, schemaState, subscriberManager) => {
|
||||
|
||||
return schemaState.subscribe(
|
||||
path, () => setRefreshKey({id: Date.now()}), 'value'
|
||||
);
|
||||
}, [key, schemaState?._id]);
|
||||
useEffect(() => {
|
||||
if (!schemaState || !subscriberManager?.current) return;
|
||||
|
||||
return subscriberManager.current?.add(schemaState, path, 'value');
|
||||
});
|
||||
|
||||
return schemaState?.value(path);
|
||||
};
|
||||
|
@ -0,0 +1,92 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import React from 'react';
|
||||
|
||||
/////////
|
||||
//
|
||||
// A class to handle the ScheamState subscription for a control to avoid
|
||||
// rendering multiple times.
|
||||
//
|
||||
class SubscriberManager {
|
||||
|
||||
constructor(refreshKeyCallback) {
|
||||
this.mounted = true;
|
||||
this.callback = refreshKeyCallback;
|
||||
this.unsubscribers = new Set();
|
||||
this._id = Date.now();
|
||||
}
|
||||
|
||||
add(schemaState, accessPath, kind, callback) {
|
||||
if (!schemaState) return;
|
||||
|
||||
callback = callback || (() => this.signal());
|
||||
|
||||
return this._add(schemaState.subscribe(accessPath, callback, kind));
|
||||
}
|
||||
|
||||
_add(unsubscriber) {
|
||||
if (!unsubscriber) return;
|
||||
// Avoid reinsertion of same unsubscriber.
|
||||
if (this.unsubscribers.has(unsubscriber)) return;
|
||||
this.unsubscribers.add(unsubscriber);
|
||||
|
||||
return () => this.remove(unsubscriber);
|
||||
}
|
||||
|
||||
remove(unsubscriber) {
|
||||
if (!unsubscriber) return;
|
||||
if (!this.unsubscribers.has(unsubscriber)) return;
|
||||
this.unsubscribers.delete(unsubscriber);
|
||||
unsubscriber();
|
||||
}
|
||||
|
||||
signal() {
|
||||
// Do nothing - if already work is in progress.
|
||||
if (!this.mounted) return;
|
||||
this.mounted = false;
|
||||
this.release();
|
||||
this.callback(Date.now());
|
||||
}
|
||||
|
||||
release () {
|
||||
const unsubscribers = this.unsubscribers;
|
||||
this.unsubscribers = new Set();
|
||||
this.mounted = true;
|
||||
|
||||
setTimeout(() => {
|
||||
Set.prototype.forEach.call(
|
||||
unsubscribers, (unsubscriber) => unsubscriber()
|
||||
);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
mount() {
|
||||
this.mounted = true;
|
||||
}
|
||||
}
|
||||
|
||||
export function useSchemaStateSubscriber(refreshKeyCallback) {
|
||||
const subscriberManager = React.useRef(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!subscriberManager.current) return;
|
||||
|
||||
return () => {
|
||||
subscriberManager.current?.release();
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!subscriberManager.current)
|
||||
subscriberManager.current = new SubscriberManager(refreshKeyCallback);
|
||||
else
|
||||
subscriberManager.current.mount();
|
||||
|
||||
return subscriberManager;
|
||||
}
|
@ -17,7 +17,7 @@ import { View, hasView } from '../registry';
|
||||
import { StaticMappedFormControl, MappedFormControl } from '../MappedControl';
|
||||
|
||||
|
||||
const DEFAULT_TAB = 'general';
|
||||
const DEFAULT_TAB = gettext('General');
|
||||
|
||||
export const createFieldControls = ({
|
||||
schema, schemaState, accessPath, viewHelperProps, dataDispatch
|
||||
@ -50,13 +50,13 @@ export const createFieldControls = ({
|
||||
};
|
||||
|
||||
// Create default group - 'General'.
|
||||
createGroup(DEFAULT_TAB, gettext('General'), true);
|
||||
createGroup(DEFAULT_TAB, DEFAULT_TAB, true);
|
||||
|
||||
schema?.fields?.forEach((field) => {
|
||||
if (!isModeSupportedByField(field, viewHelperProps)) return;
|
||||
|
||||
let inlineGroup = null;
|
||||
const inlineGroupId = field[inlineGroup];
|
||||
const inlineGroupId = field['inlineGroup'];
|
||||
|
||||
if(field.type === 'group') {
|
||||
|
||||
|
@ -13,7 +13,16 @@ import _ from 'lodash';
|
||||
import { evalFunc } from 'sources/utils';
|
||||
|
||||
|
||||
export const listenDepChanges = (accessPath, field, visible, schemaState) => {
|
||||
export const listenDepChanges = (
|
||||
accessPath, field, visible, schemaState, data, setRefreshKey
|
||||
) => {
|
||||
const deps = field?.deps ? (evalFunc(null, field.deps) || []) : null;
|
||||
const parentPath = accessPath ? [...accessPath] : [];
|
||||
|
||||
// Remove the last element.
|
||||
if (field?.id && field.id === parentPath[parentPath.length - 1]) {
|
||||
parentPath.pop();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible || !schemaState || !field) return;
|
||||
@ -26,15 +35,7 @@ export const listenDepChanges = (accessPath, field, visible, schemaState) => {
|
||||
}
|
||||
|
||||
if (field.deps) {
|
||||
const parentPath = [...accessPath];
|
||||
|
||||
// Remove the last element.
|
||||
if (field.id && field.id === parentPath[parentPath.length - 1]) {
|
||||
parentPath.pop();
|
||||
}
|
||||
|
||||
(evalFunc(null, field.deps) || []).forEach((dep) => {
|
||||
|
||||
deps.forEach((dep) => {
|
||||
// When dep is a string then prepend the complete accessPath,
|
||||
// but - when dep is an array, then the intention is to provide
|
||||
// the exact accesspath.
|
||||
@ -45,6 +46,11 @@ export const listenDepChanges = (accessPath, field, visible, schemaState) => {
|
||||
source, accessPath, field.depChange, field.deferredDepChange
|
||||
);
|
||||
}
|
||||
|
||||
if (setRefreshKey)
|
||||
schemaState.subscribe(
|
||||
source, () => setRefreshKey(Date.now()), 'value'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -54,4 +60,7 @@ export const listenDepChanges = (accessPath, field, visible, schemaState) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
return deps?.map((dep) => schemaState.value(
|
||||
_.isArray(dep) ? dep : parentPath.concat(dep)
|
||||
));
|
||||
};
|
||||
|
@ -955,7 +955,6 @@ export const InputSelect = forwardRef(({
|
||||
return () => umounted = true;
|
||||
}, [optionsReloadBasis]);
|
||||
|
||||
|
||||
/* Apply filter if any */
|
||||
const filteredOptions = (controlProps.filter?.(finalOptions)) || finalOptions;
|
||||
const flatFiltered = flattenSelectOptions(filteredOptions);
|
||||
|
@ -192,6 +192,11 @@ export default function MacrosDialog({onClose, onSave}) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const schema = React.useRef(null);
|
||||
|
||||
if (!schema.current)
|
||||
schema.current = new MacrosSchema(keyOptions);
|
||||
|
||||
return (
|
||||
<StyledBox>
|
||||
<SchemaView
|
||||
@ -202,7 +207,7 @@ export default function MacrosDialog({onClose, onSave}) {
|
||||
}
|
||||
return Promise.resolve({macro: userMacrosData.filter((m)=>Boolean(m.name))});
|
||||
}}
|
||||
schema={new MacrosSchema(keyOptions)}
|
||||
schema={schema.current}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
|
@ -172,9 +172,10 @@ class NewConnectionSchema extends BaseUISchema {
|
||||
}
|
||||
}, {
|
||||
id: 'user', label: gettext('User'), deps: ['sid', 'connected'],
|
||||
noEmpty: true, controlProps: { allowClear: false },
|
||||
noEmpty: true,
|
||||
type: (state) => ({
|
||||
type: 'select',
|
||||
controlProps: { allowClear: false },
|
||||
options: () => this.getOtherOptions(
|
||||
state.sid, 'get_new_connection_user'
|
||||
),
|
||||
@ -184,6 +185,7 @@ class NewConnectionSchema extends BaseUISchema {
|
||||
id: 'role', label: gettext('Role'), deps: ['sid', 'connected'],
|
||||
type: (state) => ({
|
||||
type: 'select',
|
||||
controlProps: { allowClear: false },
|
||||
options: () => this.getOtherOptions(
|
||||
state.sid, 'get_new_connection_role'
|
||||
),
|
||||
|
@ -399,6 +399,11 @@ function UserManagementDialog({onClose}) {
|
||||
window.open(url_for('help.static', { 'filename': 'user_management.html' }), 'pgadmin_help');
|
||||
};
|
||||
|
||||
const schema = React.useRef(null);
|
||||
|
||||
if (!schema.current)
|
||||
schema.current = new UserManagementSchema(authSourcesOptions, roleOptions);
|
||||
|
||||
return <StyledBox><SchemaView
|
||||
formType={'dialog'}
|
||||
getInitData={()=>{ return new Promise((resolve, reject)=>{
|
||||
@ -410,7 +415,7 @@ function UserManagementDialog({onClose}) {
|
||||
reject(err instanceof Error ? err : Error(gettext('Something went wrong')));
|
||||
});
|
||||
}); }}
|
||||
schema={new UserManagementSchema(authSourcesOptions, roleOptions)}
|
||||
schema={schema.current}
|
||||
viewHelperProps={{
|
||||
mode: 'edit',
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user