diff --git a/web/pgadmin/misc/dependencies/static/js/DependenciesComponent.jsx b/web/pgadmin/misc/dependencies/static/js/DependenciesComponent.jsx new file mode 100644 index 000000000..db5230db2 --- /dev/null +++ b/web/pgadmin/misc/dependencies/static/js/DependenciesComponent.jsx @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2021, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import _ from 'lodash'; +import React, { useEffect } from 'react'; +import PgTable from 'sources/components/PgTable'; +import gettext from 'sources/gettext'; +import PropTypes from 'prop-types'; + +export default function DependenciesComponent(res) { + const [tablebData, setTableData] = React.useState([]); + var columns = [ + { + Header: 'Type', + accessor: 'type', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + { + Header: 'Name', + accessor: 'name', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + { + Header: 'Restriction', + accessor: 'field', + sortble: true, + resizable: true, + disableGlobalFilter: false, + minWidth: 280, + }, + ]; + + useEffect(() => { + var data = res.res; + if (!_.isUndefined(data)) { + data.forEach((element) => { + if (element.icon && _.isUndefined(element.icon.type)) { + element['icon'] = { + type: element.icon, + }; + } + }); + setTableData(data); + } + }); + + return ( + <> + {!_.isUndefined(res.res) ? ( + + ) : ( + <> +
+
+ {' '} + {gettext(res.msg)} +
+
+ + )} + + ); +} + +DependenciesComponent.propTypes = { + res: PropTypes.array, +}; diff --git a/web/pgadmin/misc/dependencies/static/js/dependencies.js b/web/pgadmin/misc/dependencies/static/js/dependencies.js index 86ae5364d..47a37deb1 100644 --- a/web/pgadmin/misc/dependencies/static/js/dependencies.js +++ b/web/pgadmin/misc/dependencies/static/js/dependencies.js @@ -8,6 +8,10 @@ ////////////////////////////////////////////////////////////// import Notify from '../../../../static/js/helpers/Notifier'; +import ReactDOM from 'react-dom'; +import DependenciesComponent from './DependenciesComponent'; +import Theme from 'sources/Theme'; +import React from 'react'; define('misc.dependencies', [ 'sources/gettext', 'underscore', 'jquery', 'backbone', @@ -168,8 +172,6 @@ define('misc.dependencies', [ msg = gettext('Please select an object in the tree view.'), panel = this.dependenciesPanel, $container = panel.layout().scene().find('.pg-panel-content'), - $msgContainer = $container.find('.pg-panel-depends-message'), - $gridContainer = $container.find('.pg-panel-dependencies-container'), treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item); if (node) { @@ -199,101 +201,93 @@ define('misc.dependencies', [ this.dependenciesGrid.columns.models[2].set({ 'label': gettext('Restriction'), }); - - // Hide message container and show grid container. - $msgContainer.addClass('d-none'); - $gridContainer.removeClass('d-none'); - var timer = ''; var ajaxHook = function() { $.ajax({ url: url, type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader(pgAdmin.csrf_token_header, pgAdmin.csrf_token); - // Generate a timer for the request - timer = setTimeout(function() { - // notify user if request is taking longer than 1 second - - $msgContainer.text(gettext('Fetching dependency information from the server...')); - $msgContainer.removeClass('d-none'); - msg = ''; - - }, 1000); - }, }) - .done(function(res) { + .done(function (res) { clearTimeout(timer); - if (res.length > 0) { + res.forEach((Element) => { + var node = pgBrowser.Nodes[Element.type]; + if (Element.icon == null || Element.icon == '') { + Element.icon = node + ? _.isFunction(node['node_image']) + ? node['node_image'].apply(node, [null, null]) + : node['node_image'] || 'icon-' + Element.type + : 'icon-' + Element.type; + } + }); - if (!$msgContainer.hasClass('d-none')) { - $msgContainer.addClass('d-none'); - } - $gridContainer.removeClass('d-none'); - - self.dependenciesData = res; - - // Load only 100 rows - self.dependenciesCollection.reset(self.dependenciesData.splice(0, 100), {parse: true}); - - // Load more rows on scroll down - pgBrowser.Events.on( - 'pgadmin-browser:panel-dependencies:' + - wcDocker.EVENT.SCROLLED, - self.__loadMoreRows + ReactDOM.render( + + + , + $container[0] ); } else { - // Do not listen the scroll event - pgBrowser.Events.off( - 'pgadmin-browser:panel-dependencies:' + - wcDocker.EVENT.SCROLLED + ReactDOM.render( + + + , + $container[0] ); - - self.dependenciesCollection.reset({silent: true}); - $msgContainer.text(msg); - $msgContainer.removeClass('d-none'); - - if (!$gridContainer.hasClass('d-none')) { - $gridContainer.addClass('d-none'); - } } - - }) - .fail(function(xhr, error, message) { + .fail(function (xhr, error, message) { var _label = treeHierarchy[node_type].label; pgBrowser.Events.trigger( - 'pgadmin:node:retrieval:error', 'depends', xhr, error, message + 'pgadmin:node:retrieval:error', + 'depends', + xhr, + error, + message ); - if (!Alertify.pgHandleItemError(xhr, error, message, { - item: item, - info: treeHierarchy, - })) { + if ( + !Alertify.pgHandleItemError(xhr, error, message, { + item: item, + info: treeHierarchy, + }) + ) { Notify.pgNotifier( - error, xhr, - gettext('Error retrieving data from the server: %s', message || _label), - function(alertMsg) { - if(alertMsg === 'CRYPTKEY_SET') { - ajaxHook(); + error, + xhr, + gettext( + 'Error retrieving data from the server: %s', + message || _label + ), + function (alertMsg) { + if (alertMsg === 'CRYPTKEY_SET') { + ajaxHook($container); } else { console.warn(arguments); } - }); + } + ); } // show failed message. - $msgContainer.text(gettext('Failed to retrieve data from the server.')); + ReactDOM.render( + + + , + $container[0] + ); }); }; - ajaxHook(); + ajaxHook($container); } } if (msg != '') { - $msgContainer.text(msg); - $msgContainer.removeClass('d-none'); - if (!$gridContainer.hasClass('d-none')) { - $gridContainer.addClass('d-none'); - } + ReactDOM.render( + + + , + $container[0] + ); } }, showReactDependencies: function(item, data, node) { diff --git a/web/pgadmin/misc/dependents/static/js/DependentComponent.jsx b/web/pgadmin/misc/dependents/static/js/DependentComponent.jsx new file mode 100644 index 000000000..2362c3249 --- /dev/null +++ b/web/pgadmin/misc/dependents/static/js/DependentComponent.jsx @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2021, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import _ from 'lodash'; +import React, { useEffect } from 'react'; +import PgTable from 'sources/components/PgTable'; +import gettext from 'sources/gettext'; +import PropTypes from 'prop-types'; + +export default function DependentComponent(res) { + const [tablebData, setTableData] = React.useState([]); + var columns = [ + { + Header: 'Type', + accessor: 'type', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + { + Header: 'Name', + accessor: 'name', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + { + Header: 'Restriction', + accessor: 'field', + sortble: true, + resizable: true, + disableGlobalFilter: false, + minWidth: 280, + }, + ]; + + // setTableData(res); + useEffect(() => { + var data = res.res; + if (!_.isUndefined(data)) { + data.forEach( + (element) => { + if (element.icon && _.isUndefined(element.icon.type)) { + element['icon'] = { + type: element.icon, + }; + } + }, + ); + setTableData(data); + } + }); + + + + return ( + <> + {!_.isUndefined(res.res) ? ( + + ) : ( + <> +
+
+ {' '} + {gettext(res.msg)} +
+
+ + )} + + ); +} + +DependentComponent.propTypes = { + res: PropTypes.array, +}; diff --git a/web/pgadmin/misc/dependents/static/js/dependents.js b/web/pgadmin/misc/dependents/static/js/dependents.js index ce7932a88..7ac469ffb 100644 --- a/web/pgadmin/misc/dependents/static/js/dependents.js +++ b/web/pgadmin/misc/dependents/static/js/dependents.js @@ -8,6 +8,10 @@ ////////////////////////////////////////////////////////////// import Notify from '../../../../static/js/helpers/Notifier'; +import ReactDOM from 'react-dom'; +import DependentComponent from './DependentComponent'; +import Theme from 'sources/Theme'; +import React from 'react'; define('misc.dependents', [ 'sources/gettext', 'underscore', 'jquery', 'backbone', @@ -18,8 +22,6 @@ define('misc.dependents', [ if (pgBrowser.NodeDependents) return pgBrowser.NodeDependents; - var wcDocker = window.wcDocker; - pgBrowser.NodeDependents = pgBrowser.NodeDependents || {}; _.extend(pgBrowser.NodeDependents, { @@ -164,12 +166,9 @@ define('misc.dependents', [ // Fetch the actual data and update the collection __updateCollection: function(url, node, item, node_type) { - let self = this, - msg = gettext('Please select an object in the tree view.'), + let msg = gettext('Please select an object in the tree view.'), panel = this.dependentsPanel, $container = panel.layout().scene().find('.pg-panel-content'), - $msgContainer = $container.find('.pg-panel-depends-message'), - $gridContainer = $container.find('.pg-panel-dependents-container'), treeHierarchy = pgBrowser.tree.getTreeNodeHierarchy(item); if (node) { @@ -204,68 +203,37 @@ define('misc.dependents', [ 'label': gettext('Restriction'), }); } - - // Hide message container and show grid container. - $msgContainer.addClass('d-none'); - $gridContainer.removeClass('d-none'); - - var timer = ''; var ajaxHook = function() { $.ajax({ url: url, type: 'GET', - beforeSend: function(xhr) { - xhr.setRequestHeader(pgAdmin.csrf_token_header, pgAdmin.csrf_token); - // Generate a timer for the request - timer = setTimeout(function() { - // notify user if request is taking longer than 1 second - - $msgContainer.text(gettext('Fetching dependent information from the server...')); - $msgContainer.removeClass('d-none'); - msg = ''; - - }, 1000); - }, }) .done(function(res) { - clearTimeout(timer); - if (res.length > 0) { - - if (!$msgContainer.hasClass('d-none')) { - $msgContainer.addClass('d-none'); - } - $gridContainer.removeClass('d-none'); - - self.dependentData = res; - - // Load only 100 rows - self.dependentCollection.reset(self.dependentData.splice(0, 100), {parse: true}); - - // Load more rows on scroll down - pgBrowser.Events.on( - 'pgadmin-browser:panel-dependents:' + - wcDocker.EVENT.SCROLLED, - self.__loadMoreRows + res.forEach((Element)=>{ + var node = pgBrowser.Nodes[Element.type]; + if(Element.icon == null || Element.icon == '') { + Element.icon = node ? (_.isFunction(node['node_image']) ? + (node['node_image']).apply(node, [null, null]) : + (node['node_image'] || ('icon-' + Element.type))) : + ('icon-' + Element.type); + } + }); + ReactDOM.render( + + + , + $container[0] ); - - } else { - // Do not listen the scroll event - pgBrowser.Events.off( - 'pgadmin-browser:panel-dependents:' + - wcDocker.EVENT.SCROLLED + } + else{ + ReactDOM.render( + + + , + $container[0] ); - - self.dependentCollection.reset({silent: true}); - $msgContainer.text(msg); - $msgContainer.removeClass('d-none'); - - if (!$gridContainer.hasClass('d-none')) { - $gridContainer.addClass('d-none'); - } } - - }) .fail(function(xhr, error, message) { var _label = treeHierarchy[node_type].label; @@ -288,18 +256,24 @@ define('misc.dependents', [ }); } // show failed message. - $msgContainer.text(gettext('Failed to retrieve data from the server.')); + ReactDOM.render( + + + , + $container[0] + ); }); }; ajaxHook(); } } if (msg != '') { - $msgContainer.text(msg); - $msgContainer.removeClass('d-none'); - if (!$gridContainer.hasClass('d-none')) { - $gridContainer.addClass('d-none'); - } + ReactDOM.render( + + + , + $container[0] + ); } }, __loadMoreRows: function() { diff --git a/web/pgadmin/misc/statistics/static/js/StatiscticsComponent.jsx b/web/pgadmin/misc/statistics/static/js/StatiscticsComponent.jsx new file mode 100644 index 000000000..795a1ab2f --- /dev/null +++ b/web/pgadmin/misc/statistics/static/js/StatiscticsComponent.jsx @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2021, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import _ from 'lodash'; +import React, { useEffect } from 'react'; +import PgTable from 'sources/components/PgTable'; +import gettext from 'sources/gettext'; +import PropTypes from 'prop-types'; + +export default function StaticticsComponent({ + res, + tableData, + singleLineStatistics, + msg +}) { + // const classes = useStyles(); + const [tablebData, setTableData] = React.useState([]); + var columns = ''; + + if (singleLineStatistics) { + columns = [ + { + Header: 'Statictics', + accessor: 'name', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + { + Header: 'Value', + accessor: 'value', + sortble: true, + resizable: false, + disableGlobalFilter: true, + }, + ]; + } else { + columns = []; + if (!_.isUndefined(res)) { + res.forEach((row) => { + var column = { + Header: row.name, + accessor: row.name, + sortble: true, + resizable: false, + disableGlobalFilter: true, + }; + columns.push(column); + }); + } + } + useEffect(() => { + var data = tableData; + if (!_.isUndefined(data)) { + data.forEach((element) => { + if (element.icon && _.isUndefined(element.icon.type)) { + element['icon'] = { + type: element.icon, + }; + } + }); + setTableData(tableData); + } + }); + + return ( + <> + {!_.isUndefined(res) ? ( + + ) : ( + <> +
+
+ {' '} + {gettext(msg)} +
+
+ + )} + + ); +} + +StaticticsComponent.propTypes = { + res: PropTypes.array, + tableData: PropTypes.array, + msg: PropTypes.string, + singleLineStatistics: PropTypes.bool, +}; diff --git a/web/pgadmin/misc/statistics/static/js/statistics.js b/web/pgadmin/misc/statistics/static/js/statistics.js index a32d7f4e6..ce5aee7e5 100644 --- a/web/pgadmin/misc/statistics/static/js/statistics.js +++ b/web/pgadmin/misc/statistics/static/js/statistics.js @@ -8,6 +8,10 @@ ////////////////////////////////////////////////////////////// import Notify from '../../../../static/js/helpers/Notifier'; +import ReactDOM from 'react-dom'; +import StatiscticsComponent from './StatiscticsComponent'; +import Theme from 'sources/Theme'; +import React from 'react'; define('misc.statistics', [ 'sources/gettext', 'underscore', 'jquery', 'backbone', @@ -46,70 +50,6 @@ define('misc.statistics', [ }, }); - var PGBooleanCell = Backgrid.Extension.SwitchCell.extend({ - defaults: _.extend({}, Backgrid.Extension.SwitchCell.prototype.defaults), - }), - typeCellMapper = { - // boolean - 16: PGBooleanCell, - // int8 - 20: Backgrid.IntegerCell, - // int2 - 21: Backgrid.IntegerCell, - // int4 - 23: Backgrid.IntegerCell, - // float4 - 700: Backgrid.NumberCell, - // float8 - 701: Backgrid.NumberCell, - // numeric - 1700: Backgrid.NumberCell, - // abstime - 702: Backgrid.DatetimeCell, - // reltime - 703: Backgrid.DatetimeCell, - // date - 1082: Backgrid.DatetimeCell.extend({ - includeDate: true, - includeTime: false, - includeMilli: false, - }), - // time - 1083: Backgrid.DatetimeCell.extend({ - includeDate: false, - includeTime: true, - includeMilli: true, - }), - // timestamp - 1114: Backgrid.DatetimeCell.extend({ - includeDate: true, - includeTime: true, - includeMilli: true, - }), - // timestamptz - 1184: 'string' - /* Backgrid.DatetimeCell.extend({ - includeDate: true, includeTime: true, includeMilli: true - }) */ - , - 1266: 'string', - /* Backgrid.DatetimeCell.extend({ - includeDate: false, includeTime: true, includeMilli: true - }) */ - }, - GRID_CLASSES = 'backgrid presentation table table-bordered table-noouter-border table-hover', - wcDocker = window.wcDocker; - - _.extend( - PGBooleanCell.prototype.defaults.options, { - onText: gettext('True'), - offText: gettext('False'), - onColor: 'success', - offColor: 'ternary', - size: 'mini', - } - ); - _.extend(pgBrowser.NodeStatistics, { init: function() { if (this.initialized) { @@ -119,7 +59,7 @@ define('misc.statistics', [ _.bindAll( this, 'showStatistics', 'toggleVisibility', - '__createMultiLineStatistics', '__createSingleLineStatistics', '__loadMoreRows'); + '__createSingleLineStatistics', '__loadMoreRows'); _.extend( this, { @@ -188,7 +128,6 @@ define('misc.statistics', [ __updateCollection: function(url, node, item, node_type) { var $container = this.panel[0].layout().scene().find('.pg-panel-content'), $msgContainer = $container.find('.pg-panel-statistics-message'), - $gridContainer = $container.find('.pg-panel-statistics-container'), panel = this.panel, self = this, msg = '', @@ -228,11 +167,12 @@ define('misc.statistics', [ timer = setTimeout(function() { // notify user if request is taking longer than 1 second - $msgContainer.text(gettext('Retrieving data from the server...')); - $msgContainer.removeClass('d-none'); - if (self.grid) { - self.grid.remove(); - } + ReactDOM.render( + + + , + $container[0] + ); }, 1000); }, }) @@ -243,49 +183,35 @@ define('misc.statistics', [ if (res.data) { var data = self.data = res.data; if (node.hasCollectiveStatistics || data['rows'].length > 1) { - // Listen scroll event to load more rows - pgBrowser.Events.on( - 'pgadmin-browser:panel-statistics:' + - wcDocker.EVENT.SCROLLED, - self.__loadMoreRows + let tableData = []; + res.data.rows.forEach((row) => { + tableData.push({...row, icon: ''}); + }); + ReactDOM.render( + + + , + $container[0] ); - self.__createMultiLineStatistics.call(self, data, node.statsPrettifyFields); } else { - // Do not listen the scroll event - pgBrowser.Events.off( - 'pgadmin-browser:panel-statistics:' + - wcDocker.EVENT.SCROLLED, - self.__loadMoreRows + var tableData = self.__createSingleLineStatistics.call(self, data, node.statsPrettifyFields); + ReactDOM.render( + + + , + $container[0] ); - self.__createSingleLineStatistics.call(self, data, node.statsPrettifyFields); - } - - if (self.grid) { - delete self.grid; - self.grid = null; } - - self.grid = new Backgrid.Grid({ - emptyText: gettext('No data found'), - columns: self.columns, - collection: self.collection, - className: GRID_CLASSES, - }); - self.grid.render(); - $gridContainer.empty(); - $gridContainer.append(self.grid.$el); - - if (!$msgContainer.hasClass('d-none')) { - $msgContainer.addClass('d-none'); - } - $gridContainer.removeClass('d-none'); - - } else if (res.info) { - if (!$gridContainer.hasClass('d-none')) { - $gridContainer.addClass('d-none'); - } - $msgContainer.text(res.info); - $msgContainer.removeClass('d-none'); + } + else if (res.info) { + + ReactDOM.render( + + + , + $container[0] + ); + } }) .fail(function(xhr, error, message) { @@ -310,7 +236,12 @@ define('misc.statistics', [ ); } // show failed message. - $msgContainer.text(gettext('Failed to retrieve data from the server.')); + ReactDOM.render( + + + , + $container[0] + ); }); }; @@ -318,12 +249,12 @@ define('misc.statistics', [ } } if (msg != '') { - // Hide the grid container and show the default message container - if (!$gridContainer.hasClass('d-none')) - $gridContainer.addClass('d-none'); - $msgContainer.removeClass('d-none'); - - $msgContainer.text(msg); + ReactDOM.render( + + + , + $container[0] + ); } }, refreshStatistics: function(item, data, node) { @@ -363,37 +294,6 @@ define('misc.statistics', [ }, 400); }, - __createMultiLineStatistics: function(data, prettifyFields) { - var rows = data['rows'], - columns = data['columns']; - - this.columns = []; - for (var idx in columns) { - var rawColumn = columns[idx], - cell_type = typeCellMapper[rawColumn['type_code']] || 'string'; - - // Don't show PID comma separated - if (rawColumn['name'] == 'PID') { - cell_type = cell_type.extend({ - orderSeparator: '', - }); - } - - var col = { - editable: false, - name: rawColumn['name'], - cell: cell_type, - }; - if (_.indexOf(prettifyFields, rawColumn['name']) != -1) { - col['formatter'] = SizeFormatter; - } - this.columns.push(col); - - } - - this.collection.reset(rows.splice(0, 50)); - }, - __loadMoreRows: function() { let elem = $('.pg-panel-statistics-container').closest('.wcFrameCenter')[0]; if ((elem.scrollHeight - 10) < elem.scrollTop + elem.offsetHeight) { @@ -414,15 +314,16 @@ define('misc.statistics', [ for (var idx in columns) { name = (columns[idx])['name']; res.push({ - 'statistics': name, + 'name': name, // Check if row is undefined? 'value': row && row[name] ? ((_.indexOf(prettifyFields, name) != -1) ? sizePrettify(row[name]) : row[name]) : null, + 'icon': '', }); } - this.collection.reset(res); + return res; }, }); diff --git a/web/pgadmin/static/js/components/PgTable.jsx b/web/pgadmin/static/js/components/PgTable.jsx index da27a43dc..f97cecb2a 100644 --- a/web/pgadmin/static/js/components/PgTable.jsx +++ b/web/pgadmin/static/js/components/PgTable.jsx @@ -17,6 +17,7 @@ import clsx from 'clsx'; import PropTypes from 'prop-types'; import AutoSizer from 'react-virtualized-auto-sizer'; import { Checkbox } from '@material-ui/core'; +import gettext from 'sources/gettext'; const useStyles = makeStyles((theme) => ({ root: { @@ -236,50 +237,73 @@ export default function PgTable({ columns, data, isSelectRow, ...props }) { ); // Render the UI for your table return ( - - {({ height }) => ( -
-
- {headerGroups.map(headerGroup => ( -
- {headerGroup.headers.map(column => ( -
-
- {column.render('Header')} - - {column.isSorted - ? column.isSortedDesc - ? ' 🔽' - : ' 🔼' - : ''} - - {column.resizable && + <> + {rows.length > 0 ? ( + + {({ height }) => ( +
+
+ {headerGroups.map((headerGroup) => ( +
+ {headerGroup.headers.map((column) => ( +
} -
+ {...(column.sortble + ? column.getSortByToggleProps() + : {})} + > + {column.render('Header')} + + {column.isSorted + ? column.isSortedDesc + ? ' 🔽' + : ' 🔼' + : ''} + + {column.resizable && ( +
+ )} +
+
+ ))}
))}
- ))} -
- -
- - - {RenderRow} - +
+ + {RenderRow} + +
+
+ )} +
+ ) : ( + <> +
+
+ {' '} + {gettext('No Record')} +
-
+ )} - + ); }