2022-03-30 01:36:59 -05:00
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
2024-01-01 02:43:48 -06:00
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
2022-03-30 01:36:59 -05:00
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React from 'react' ;
2024-06-06 06:43:12 -05:00
import { styled } from '@mui/material/styles' ;
2022-03-30 01:36:59 -05:00
import getApiInstance from 'sources/api_instance' ;
2024-04-08 21:51:14 -05:00
import { Box } from '@mui/material' ;
2022-03-30 01:36:59 -05:00
import { generateCollectionURL } from '../../browser/static/js/node_ajax' ;
import gettext from 'sources/gettext' ;
import PgTable from 'sources/components/PgTable' ;
import PropTypes from 'prop-types' ;
2023-10-27 05:21:45 -05:00
import { PgButtonGroup , PgIconButton } from '../../static/js/components/Buttons' ;
2024-04-08 21:51:14 -05:00
import DeleteIcon from '@mui/icons-material/Delete' ;
import DeleteSweepIcon from '@mui/icons-material/DeleteSweep' ;
import DeleteForeverIcon from '@mui/icons-material/DeleteForever' ;
2022-04-05 01:40:51 -05:00
import EmptyPanelMessage from '../../static/js/components/EmptyPanelMessage' ;
2022-04-22 05:12:04 -05:00
import Loader from 'sources/components/Loader' ;
2023-06-19 04:34:40 -05:00
import { evalFunc } from '../../static/js/utils' ;
2023-10-23 07:13:17 -05:00
import { usePgAdmin } from '../../static/js/BrowserComponent' ;
2024-05-07 06:01:04 -05:00
import { getSwitchCell } from '../../static/js/components/PgReactTableStyled' ;
2022-03-30 01:36:59 -05:00
2024-06-06 06:43:12 -05:00
const StyledBox = styled ( Box ) ( ( { theme } ) => ( {
height : '100%' ,
'&.CollectionNodeProperties-emptyPanel' : {
2022-03-30 01:36:59 -05:00
minHeight : '100%' ,
minWidth : '100%' ,
2022-04-05 01:40:51 -05:00
background : theme . otherVars . emptySpaceBg ,
2022-03-30 01:36:59 -05:00
overflow : 'auto' ,
2022-04-05 01:40:51 -05:00
padding : '8px' ,
display : 'flex' ,
2024-06-06 06:43:12 -05:00
}
2022-03-30 01:36:59 -05:00
} ) ) ;
2023-10-23 07:13:17 -05:00
export default function CollectionNodeProperties ( {
2022-03-30 01:36:59 -05:00
node ,
treeNodeInfo ,
2023-10-23 07:13:17 -05:00
nodeData ,
nodeItem ,
isActive ,
isStale ,
setIsStale
2022-03-30 01:36:59 -05:00
} ) {
2023-10-23 07:13:17 -05:00
const pgAdmin = usePgAdmin ( ) ;
2022-03-30 01:36:59 -05:00
const [ data , setData ] = React . useState ( [ ] ) ;
const [ infoMsg , setInfoMsg ] = React . useState ( 'Please select an object in the tree view.' ) ;
2024-05-07 06:01:04 -05:00
const [ selectedObject , setSelectedObject ] = React . useState ( { } ) ;
2022-04-22 05:12:04 -05:00
const [ loaderText , setLoaderText ] = React . useState ( '' ) ;
2023-03-17 07:13:42 -05:00
const schemaRef = React . useRef ( ) ;
2022-03-30 01:36:59 -05:00
const [ pgTableColumns , setPgTableColumns ] = React . useState ( [
{
2024-05-07 06:01:04 -05:00
header : 'properties' ,
accessorKey : 'Properties' ,
enableSorting : true ,
enableResizing : true ,
enableFilters : true ,
2022-03-30 01:36:59 -05:00
} ,
{
2024-05-07 06:01:04 -05:00
header : 'value' ,
accessorKey : 'value' ,
enableSorting : true ,
enableResizing : true ,
enableFilters : true ,
2022-03-30 01:36:59 -05:00
} ,
] ) ;
const onDrop = ( type ) => {
2024-05-07 06:01:04 -05:00
let selRows = [ ] ,
2023-10-23 07:13:17 -05:00
selItem = pgAdmin . Browser . tree . selected ( ) ,
selectedItemData = selItem ? pgAdmin . Browser . tree . itemData ( selItem ) : null ,
selNode = selectedItemData && pgAdmin . Browser . Nodes [ selectedItemData . _type ] ,
2024-04-09 08:48:56 -05:00
url , msg , title ;
2022-03-30 01:36:59 -05:00
2024-05-07 06:01:04 -05:00
selRows = Object . keys ( selectedObject ) . map ( ( i ) => ( selNode ? . type == 'coll-constraints' ? {
id : data [ i ] . oid ,
_type : data [ i ] . _type ,
} : data [ i ] [ schemaRef . current . idAttribute ] ) ) ;
2022-03-30 01:36:59 -05:00
if ( selRows . length === 0 ) {
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . notifier . alert (
2023-06-19 04:34:40 -05:00
gettext ( 'Delete Multiple' ) ,
2022-03-30 01:36:59 -05:00
gettext ( 'Please select at least one object to delete.' )
) ;
return ;
}
if ( ! selNode ) return ;
if ( type === 'dropCascade' ) {
url = selNode . generate _url ( selItem , 'delete' ) ;
msg = gettext (
2023-06-19 04:34:40 -05:00
'Are you sure you want to delete all the selected objects and all the objects that depend on them?'
2022-03-30 01:36:59 -05:00
) ;
2023-06-19 04:34:40 -05:00
title = gettext ( 'Delete CASCADE multiple objects?' ) ;
} else if ( type === 'dropForce' ) {
url = selNode . generate _url ( selItem , 'delete' ) ;
msg = gettext (
'Delete databases with the force option will attempt to terminate all the existing connections to the selected databases. Are you sure you want to proceed?'
) ;
title = gettext ( 'Delete FORCE multiple objects?' ) ;
2022-03-30 01:36:59 -05:00
} else {
url = selNode . generate _url ( selItem , 'drop' ) ;
2023-06-19 04:34:40 -05:00
msg = gettext ( 'Are you sure you want to delete all the selected objects?' ) ;
title = gettext ( 'Delete multiple objects?' ) ;
2022-03-30 01:36:59 -05:00
}
const api = getApiInstance ( ) ;
let dropNodeProperties = function ( ) {
2023-06-19 04:34:40 -05:00
setLoaderText ( gettext ( 'Deleting Objects...' ) ) ;
2022-03-30 01:36:59 -05:00
api
. delete ( url , {
data : JSON . stringify ( { ids : selRows } ) ,
contentType : 'application/json; charset=utf-8' ,
} )
. then ( function ( res ) {
if ( res . success == 0 ) {
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . notifier . alert ( res . errormsg , res . info ) ;
2022-03-30 01:36:59 -05:00
}
2022-04-09 01:05:11 -05:00
pgAdmin . Browser . tree . refresh ( selItem ) ;
2023-11-17 04:59:01 -06:00
setIsStale ( true ) ;
2024-05-07 06:01:04 -05:00
setSelectedObject ( { } ) ;
2022-03-30 01:36:59 -05:00
} )
. catch ( function ( error ) {
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . notifier . alert (
2023-06-19 04:34:40 -05:00
gettext ( 'Error deleting %s' , selectedItemData . _label . toLowerCase ( ) ) ,
2022-04-09 01:05:11 -05:00
_ . isUndefined ( error . response ) ? error . message : error . response . data . errormsg
2022-03-30 01:36:59 -05:00
) ;
2023-11-17 04:59:01 -06:00
} )
. then ( ( ) => {
setLoaderText ( '' ) ;
2022-03-30 01:36:59 -05:00
} ) ;
} ;
if ( confirm ) {
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . notifier . confirm ( title , msg , dropNodeProperties , null ) ;
2022-03-30 01:36:59 -05:00
} else {
dropNodeProperties ( ) ;
}
} ;
React . useEffect ( ( ) => {
2024-02-20 04:53:05 -06:00
if ( node ) {
2022-03-30 01:36:59 -05:00
let nodeObj =
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . Nodes [ nodeData ? . _type . replace ( 'coll-' , '' ) ] ;
2022-03-30 01:36:59 -05:00
2023-10-23 07:13:17 -05:00
let url = generateCollectionURL . call ( nodeObj , nodeItem , 'properties' ) ;
2022-03-30 01:36:59 -05:00
const api = getApiInstance ( ) ;
let tableColumns = [ ] ;
2022-09-08 04:46:48 -05:00
let column = { } ;
2024-02-20 04:53:05 -06:00
if ( ! isStale || ! isActive ) {
return ;
}
2023-06-19 04:34:40 -05:00
setLoaderText ( gettext ( 'Loading...' ) ) ;
2024-03-18 01:23:59 -05:00
if ( ! _ . isUndefined ( nodeObj . getSchema ) ) {
2024-04-09 08:48:56 -05:00
schemaRef . current = nodeObj . getSchema ? . ( treeNodeInfo , nodeData ) ;
2023-03-17 07:13:42 -05:00
schemaRef . current ? . fields . forEach ( ( field ) => {
2022-03-30 01:36:59 -05:00
if ( node . columns . indexOf ( field . id ) > - 1 ) {
if ( field . label . indexOf ( '?' ) > - 1 ) {
column = {
2024-05-07 06:01:04 -05:00
header : field . label ,
accessorKey : field . id ,
enableSorting : true ,
enableResizing : true ,
enableFilters : true ,
cell : getSwitchCell ( )
2022-03-30 01:36:59 -05:00
} ;
} else {
column = {
2024-05-07 06:01:04 -05:00
header : field . label ,
accessorKey : field . id ,
enableSorting : true ,
enableResizing : true ,
enableFilters : true ,
2022-03-30 01:36:59 -05:00
} ;
}
tableColumns . push ( column ) ;
}
} ) ;
2022-04-04 07:12:42 -05:00
} else {
node . columns . forEach ( ( field ) => {
column = {
2024-05-07 06:01:04 -05:00
header : field ,
accessorKey : field ,
enableSorting : true ,
enableResizing : true ,
enableFilters : true ,
2022-04-04 07:12:42 -05:00
} ;
tableColumns . push ( column ) ;
} ) ;
2022-03-30 01:36:59 -05:00
}
2022-04-04 07:12:42 -05:00
api ( {
url : url ,
type : 'GET' ,
} )
. then ( ( res ) => {
res . data . forEach ( ( element ) => {
element [ 'icon' ] = '' ;
} ) ;
setPgTableColumns ( tableColumns ) ;
setData ( res . data ) ;
setInfoMsg ( 'No properties are available for the selected object.' ) ;
2022-04-22 05:12:04 -05:00
setLoaderText ( '' ) ;
2022-04-04 07:12:42 -05:00
} )
. catch ( ( err ) => {
2023-10-23 07:13:17 -05:00
pgAdmin . Browser . notifier . alert (
2022-04-04 07:12:42 -05:00
gettext ( 'Failed to retrieve data from the server.' ) ,
gettext ( err . message )
) ;
} ) ;
2023-10-23 07:13:17 -05:00
setIsStale ( false ) ;
2022-03-30 01:36:59 -05:00
}
2024-02-20 04:53:05 -06:00
} , [ nodeData , node , nodeItem , isStale , isActive ] ) ;
2022-03-30 01:36:59 -05:00
2022-08-11 00:19:45 -05:00
const CustomHeader = ( ) => {
2023-10-23 07:13:17 -05:00
const canDrop = evalFunc ( node , node . canDrop , nodeData , nodeItem , treeNodeInfo ) ;
const canDropCascade = evalFunc ( node , node . canDropCascade , nodeData , nodeItem , treeNodeInfo ) ;
const canDropForce = evalFunc ( node , node . canDropForce , nodeData , nodeItem , treeNodeInfo ) ;
2022-03-30 01:36:59 -05:00
return (
< Box >
2023-10-27 05:21:45 -05:00
< PgButtonGroup size = "small" >
2023-06-19 04:34:40 -05:00
< PgIconButton
2023-10-27 05:21:45 -05:00
icon = { < DeleteIcon style = { { height : '1.35rem' } } / > }
aria - label = "Delete"
title = { gettext ( 'Delete' ) }
2023-06-19 04:34:40 -05:00
onClick = { ( ) => {
2023-10-27 05:21:45 -05:00
onDrop ( 'drop' ) ;
2023-06-19 04:34:40 -05:00
} }
disabled = {
2024-05-07 06:01:04 -05:00
( Object . keys ( selectedObject ) . length > 0 )
2023-10-27 05:21:45 -05:00
? ! canDrop
2023-06-19 04:34:40 -05:00
: true
}
2023-10-27 05:21:45 -05:00
> < / PgIconButton >
{ node . type !== 'coll-database' ? < PgIconButton
icon = { < DeleteSweepIcon style = { { height : '1.5rem' } } / > }
aria - label = "Delete Cascade"
title = { gettext ( 'Delete (Cascade)' ) }
onClick = { ( ) => {
onDrop ( 'dropCascade' ) ;
} }
disabled = {
2024-05-07 06:01:04 -05:00
( Object . keys ( selectedObject ) . length > 0 )
2023-10-27 05:21:45 -05:00
? ! canDropCascade
: true
}
> < / PgIconButton > :
< PgIconButton
icon = { < DeleteForeverIcon style = { { height : '1.4rem' } } / > }
aria - label = "Delete Force"
title = { gettext ( 'Delete (Force)' ) }
onClick = { ( ) => {
onDrop ( 'dropForce' ) ;
} }
disabled = {
2024-05-07 06:01:04 -05:00
( Object . keys ( selectedObject ) . length > 0 )
2023-10-27 05:21:45 -05:00
? ! canDropForce
: true
}
> < / PgIconButton > }
< / PgButtonGroup >
2022-03-30 01:36:59 -05:00
< / Box > ) ;
} ;
return (
2024-06-06 06:43:12 -05:00
< >
2023-06-19 04:34:40 -05:00
< Loader message = { loaderText } / >
2024-06-06 06:43:12 -05:00
< StyledBox >
2022-03-30 01:36:59 -05:00
{ data . length > 0 ?
(
< PgTable
2024-05-07 06:01:04 -05:00
hasSelectRow = { ! ( 'catalog' in treeNodeInfo ) && ( nodeData . label !== 'Catalogs' ) && _ . isUndefined ( node ? . canSelect ) }
2022-08-11 00:19:45 -05:00
CustomHeader = { CustomHeader }
2022-03-30 01:36:59 -05:00
columns = { pgTableColumns }
data = { data }
type = { 'panel' }
isSearch = { false }
2024-05-07 06:01:04 -05:00
selectedRows = { selectedObject }
setSelectedRows = { setSelectedObject }
2022-03-30 01:36:59 -05:00
/ >
)
:
(
2024-06-06 06:43:12 -05:00
< div className = 'CollectionNodeProperties-emptyPanel' >
2023-10-27 05:21:45 -05:00
< EmptyPanelMessage text = { gettext ( infoMsg ) } / >
2022-03-30 01:36:59 -05:00
< / div >
)
}
2024-06-06 06:43:12 -05:00
< / StyledBox >
< / >
2022-03-30 01:36:59 -05:00
) ;
}
2023-10-23 07:13:17 -05:00
CollectionNodeProperties . propTypes = {
2022-03-30 01:36:59 -05:00
node : PropTypes . func ,
2023-10-23 07:13:17 -05:00
nodeData : PropTypes . object ,
2022-03-30 01:36:59 -05:00
treeNodeInfo : PropTypes . object ,
2023-10-23 07:13:17 -05:00
nodeItem : PropTypes . object ,
isActive : PropTypes . bool ,
isStale : PropTypes . bool ,
setIsStale : PropTypes . func ,
2022-03-30 01:36:59 -05:00
} ;