mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Make PgTreeView react component more customisable
This commit is contained in:
parent
d39fe78239
commit
c45fb47b08
@ -13,7 +13,7 @@ import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
||||
|
||||
|
||||
|
||||
const Root = styled('div')(({theme}) => ({
|
||||
const Root = styled('div')(({ theme }) => ({
|
||||
height: '100%',
|
||||
'& .PgTree-tree': {
|
||||
background: theme.palette.background.default,
|
||||
@ -38,9 +38,11 @@ const Root = styled('div')(({theme}) => ({
|
||||
|
||||
export const PgTreeSelectionContext = React.createContext();
|
||||
|
||||
export default function PgTreeView({ data = [], hasCheckbox = false, selectionChange = null}) {
|
||||
export default function PgTreeView({ data = [], hasCheckbox = false,
|
||||
selectionChange = null, NodeComponent = null, ...props }) {
|
||||
|
||||
let treeData = data;
|
||||
const Node = NodeComponent ?? DefaultNode;
|
||||
const treeObj = useRef();
|
||||
const treeContainerRef = useRef();
|
||||
const [selectedCheckBoxNodes, setSelectedCheckBoxNodes] = React.useState([]);
|
||||
@ -51,9 +53,9 @@ export default function PgTreeView({ data = [], hasCheckbox = false, selectionCh
|
||||
let selectedChildNodes = [];
|
||||
|
||||
treeObj.current.selectedNodes.forEach((node) => {
|
||||
if(node.isInternal && !node.isOpen) {
|
||||
node.children.forEach((ch)=>{
|
||||
if(ch.data.isSelected && ch.isLeaf && !selectedChildNodes.includes(ch.id)) {
|
||||
if (node.isInternal && !node.isOpen) {
|
||||
node.children.forEach((ch) => {
|
||||
if (ch.data.isSelected && ch.isLeaf && !selectedChildNodes.includes(ch.id)) {
|
||||
selectedChildNodes.push(ch.id);
|
||||
selectedChNodes.push(ch);
|
||||
}
|
||||
@ -68,7 +70,7 @@ export default function PgTreeView({ data = [], hasCheckbox = false, selectionCh
|
||||
};
|
||||
|
||||
return (<Root>
|
||||
{ treeData.length > 0 ?
|
||||
{treeData.length > 0 ?
|
||||
<PgTreeSelectionContext.Provider value={selectedCheckBoxNodes}>
|
||||
<div ref={(containerRef) => treeContainerRef.current = containerRef} className={'PgTree-tree'}>
|
||||
<AutoSizer>
|
||||
@ -83,9 +85,10 @@ export default function PgTreeView({ data = [], hasCheckbox = false, selectionCh
|
||||
disableDrag={true}
|
||||
disableDrop={true}
|
||||
dndRootElement={treeContainerRef.current}
|
||||
{...props}
|
||||
>
|
||||
{
|
||||
(props) => <Node onNodeSelectionChange={onSelectionChange} hasCheckbox={hasCheckbox} {...props}></Node>
|
||||
(props) => <Node onNodeSelectionChange={onSelectionChange} hasCheckbox={hasCheckbox} {...props} />
|
||||
}
|
||||
</Tree>
|
||||
)}
|
||||
@ -93,7 +96,7 @@ export default function PgTreeView({ data = [], hasCheckbox = false, selectionCh
|
||||
</div>
|
||||
</PgTreeSelectionContext.Provider>
|
||||
:
|
||||
<EmptyPanelMessage text={gettext('No objects are found to display')}/>
|
||||
<EmptyPanelMessage text={gettext('No objects are found to display')} />
|
||||
}
|
||||
</Root>
|
||||
);
|
||||
@ -103,22 +106,23 @@ PgTreeView.propTypes = {
|
||||
data: PropTypes.array,
|
||||
selectionChange: PropTypes.func,
|
||||
hasCheckbox: PropTypes.bool,
|
||||
NodeComponent: PropTypes.func
|
||||
};
|
||||
|
||||
function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
function DefaultNode({ node, style, tree, hasCheckbox, onNodeSelectionChange }) {
|
||||
|
||||
const pgTreeSelCtx = React.useContext(PgTreeSelectionContext);
|
||||
const [isSelected, setIsSelected] = React.useState(pgTreeSelCtx.includes(node.id) || node.data?.isSelected);
|
||||
const [isIndeterminate, setIsIndeterminate] = React.useState(node?.parent.level==0);
|
||||
const [isIndeterminate, setIsIndeterminate] = React.useState(node?.parent.level == 0);
|
||||
|
||||
useEffect(()=>{
|
||||
useEffect(() => {
|
||||
setIsIndeterminate(node.data.isIndeterminate);
|
||||
}, [node?.data?.isIndeterminate]);
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
if(isSelected){
|
||||
if(!pgTreeSelCtx.includes(node.id)){
|
||||
useEffect(() => {
|
||||
if (isSelected) {
|
||||
if (!pgTreeSelCtx.includes(node.id)) {
|
||||
tree.selectMulti(node.id);
|
||||
onNodeSelectionChange();
|
||||
}
|
||||
@ -139,7 +143,7 @@ function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
checkAndSelectParent(node);
|
||||
}
|
||||
|
||||
if(node?.level == 0) {
|
||||
if (node?.level == 0) {
|
||||
node.data.isIndeterminate = false;
|
||||
}
|
||||
node.focus();
|
||||
@ -149,7 +153,7 @@ function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
deselectAllChild(node);
|
||||
}
|
||||
|
||||
if(node?.parent){
|
||||
if (node?.parent) {
|
||||
node.parent.data.isIndeterminate = false;
|
||||
delectPrentNode(node.parent);
|
||||
}
|
||||
@ -165,7 +169,7 @@ function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
};
|
||||
|
||||
const onKeyDown = (e) => {
|
||||
if(e.code == 'Enter') {
|
||||
if (e.code == 'Enter') {
|
||||
onSelect(e);
|
||||
}
|
||||
};
|
||||
@ -174,10 +178,10 @@ function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
<div style={style} className={node.isFocused ? 'PgTree-focusedNode' : ''} onClick={onSelect} onKeyDown={onKeyDown}>
|
||||
<CollectionArrow node={node} tree={tree} selectedNodeIds={pgTreeSelCtx} />
|
||||
{
|
||||
hasCheckbox ? <Checkbox style={{ padding: 0 }} color="primary" className={!node.isInternal ? 'PgTree-leafNode': null}
|
||||
hasCheckbox ? <Checkbox style={{ padding: 0 }} color="primary" className={!node.isInternal ? 'PgTree-leafNode' : null}
|
||||
checked={isSelected}
|
||||
checkedIcon={isIndeterminate ? <IndeterminateCheckBoxIcon style={{height: '1.4rem'}} />: <CheckBoxIcon style={{height: '1.4rem'}} />}
|
||||
onChange={onCheckboxSelection}/> :
|
||||
checkedIcon={isIndeterminate ? <IndeterminateCheckBoxIcon style={{ height: '1.4rem' }} /> : <CheckBoxIcon style={{ height: '1.4rem' }} />}
|
||||
onChange={onCheckboxSelection} /> :
|
||||
<span className={node.data.icon}></span>
|
||||
}
|
||||
<div className={node.data.icon + ' PgTree-node'}>{node.data.name}</div>
|
||||
@ -185,7 +189,7 @@ function Node({ node, style, tree, hasCheckbox, onNodeSelectionChange}) {
|
||||
);
|
||||
}
|
||||
|
||||
Node.propTypes = {
|
||||
DefaultNode.propTypes = {
|
||||
node: PropTypes.object,
|
||||
style: PropTypes.any,
|
||||
tree: PropTypes.object,
|
||||
@ -202,7 +206,7 @@ function CollectionArrow({ node, tree, selectedNodeIds }) {
|
||||
}
|
||||
};
|
||||
return (
|
||||
<span onClick={toggleNode} onKeyDown={()=>{/* handled by parent */}}>
|
||||
<span onClick={toggleNode} onKeyDown={() => {/* handled by parent */ }}>
|
||||
{node.isInternal && node?.children.length > 0 ? <ToggleArrowIcon node={node} /> : null}
|
||||
</span>
|
||||
);
|
||||
@ -215,7 +219,7 @@ CollectionArrow.propTypes = {
|
||||
};
|
||||
|
||||
|
||||
function ToggleArrowIcon({node}){
|
||||
function ToggleArrowIcon({ node }) {
|
||||
return (<>{node.isOpen ? <ExpandMoreIcon /> : <ChevronRightIcon />}</>);
|
||||
}
|
||||
|
||||
@ -223,7 +227,7 @@ ToggleArrowIcon.propTypes = {
|
||||
node: PropTypes.object,
|
||||
};
|
||||
|
||||
function checkAndSelectParent(chNode){
|
||||
function checkAndSelectParent(chNode) {
|
||||
let isAllChildSelected = true;
|
||||
chNode?.parent?.children?.forEach((child) => {
|
||||
if (!child.isSelected) {
|
||||
@ -251,15 +255,15 @@ checkAndSelectParent.propTypes = {
|
||||
chNode: PropTypes.object
|
||||
};
|
||||
|
||||
function delectPrentNode(chNode){
|
||||
function delectPrentNode(chNode) {
|
||||
if (chNode) {
|
||||
let isAnyChildSelected = false;
|
||||
chNode.children.forEach((childNode)=>{
|
||||
if(childNode.isSelected && !isAnyChildSelected){
|
||||
chNode.children.forEach((childNode) => {
|
||||
if (childNode.isSelected && !isAnyChildSelected) {
|
||||
isAnyChildSelected = true;
|
||||
}
|
||||
});
|
||||
if(isAnyChildSelected){
|
||||
if (isAnyChildSelected) {
|
||||
chNode.data.isSelected = true;
|
||||
chNode.data.isIndeterminate = true;
|
||||
} else {
|
||||
@ -273,14 +277,14 @@ function delectPrentNode(chNode){
|
||||
}
|
||||
}
|
||||
|
||||
function selectAllChild(chNode, tree, source, selectedNodeIds){
|
||||
function selectAllChild(chNode, tree, source, selectedNodeIds) {
|
||||
let selectedChild = 0;
|
||||
chNode?.children?.forEach(child => {
|
||||
|
||||
if(!child.isLeaf) {
|
||||
if (!child.isLeaf) {
|
||||
child.data.isIndeterminate = false;
|
||||
}
|
||||
if((source == 'expand' && selectedNodeIds.includes(child.id)) || source == 'checkbox') {
|
||||
if ((source == 'expand' && selectedNodeIds.includes(child.id)) || source == 'checkbox') {
|
||||
child.data.isSelected = true;
|
||||
selectedChild += 1;
|
||||
}
|
||||
@ -291,7 +295,7 @@ function selectAllChild(chNode, tree, source, selectedNodeIds){
|
||||
}
|
||||
});
|
||||
|
||||
if(selectedChild < chNode?.children.length ){
|
||||
if (selectedChild < chNode?.children.length) {
|
||||
chNode.data.isIndeterminate = true;
|
||||
} else {
|
||||
chNode.data.isIndeterminate = false;
|
||||
@ -302,7 +306,7 @@ function selectAllChild(chNode, tree, source, selectedNodeIds){
|
||||
}
|
||||
}
|
||||
|
||||
function deselectAllChild(chNode){
|
||||
function deselectAllChild(chNode) {
|
||||
chNode?.children.forEach(child => {
|
||||
child.deselect(child);
|
||||
child.data.isSelected = false;
|
||||
|
Loading…
Reference in New Issue
Block a user