mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
1) Port Properties panel for collection node, Dashboard, and SQL panel in React. Fixes #7132
2) Added transaction start time to Server activity sessions view. Fixes #7215
This commit is contained in:
committed by
Akshay Joshi
parent
931a399890
commit
cb052f1988
67
web/pgadmin/dashboard/static/js/ActiveQuery.ui.js
Normal file
67
web/pgadmin/dashboard/static/js/ActiveQuery.ui.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
|
||||
export default class ActiveQuery extends BaseUISchema {
|
||||
constructor(initValues) {
|
||||
super({
|
||||
...initValues,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return [
|
||||
|
||||
{
|
||||
id: 'backend_type',
|
||||
label: gettext('Backend type'),
|
||||
type: 'text',
|
||||
editable: true,
|
||||
noEmpty: true,
|
||||
readonly: true,
|
||||
mode: ['properties'],
|
||||
group: gettext('Details'),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
id: 'query_start',
|
||||
label: gettext('Query started at'),
|
||||
type: 'text',
|
||||
editable: false,
|
||||
readonly: true,
|
||||
group: gettext('Details'),
|
||||
disabled: true
|
||||
|
||||
},
|
||||
{
|
||||
id: 'state_change',
|
||||
label: gettext('Last state changed at'),
|
||||
type: 'text',
|
||||
editable: false,
|
||||
readonly: true,
|
||||
group: gettext('Details'),
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
id: 'query',
|
||||
label: gettext('SQL'),
|
||||
cell: 'string',
|
||||
editable: false,
|
||||
readonly: true,
|
||||
type: 'sql',
|
||||
group: gettext('Details'),
|
||||
},
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
907
web/pgadmin/dashboard/static/js/Dashboard.jsx
Normal file
907
web/pgadmin/dashboard/static/js/Dashboard.jsx
Normal file
@@ -0,0 +1,907 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
// eslint-disable-next-line react/display-name
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import gettext from 'sources/gettext';
|
||||
import PropTypes from 'prop-types';
|
||||
import getApiInstance from 'sources/api_instance';
|
||||
import PgTable from 'sources/components/PgTable';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import url_for from 'sources/url_for';
|
||||
import Graphs from './Graphs';
|
||||
import Notify from '../../../static/js/helpers/Notifier';
|
||||
import { Box, Tab, Tabs } from '@material-ui/core';
|
||||
import { PgIconButton } from '../../../static/js/components/Buttons';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import SquareIcon from '@mui/icons-material/Square';
|
||||
import ArrowRightOutlinedIcon from '@mui/icons-material/ArrowRightOutlined';
|
||||
import ArrowDropDownOutlinedIcon from '@mui/icons-material/ArrowDropDownOutlined';
|
||||
import WelcomeDashboard from './WelcomeDashboard';
|
||||
import ActiveQuery from './ActiveQuery.ui';
|
||||
import _ from 'lodash';
|
||||
|
||||
function parseData(data) {
|
||||
var res = [];
|
||||
|
||||
data.forEach((row) => {
|
||||
res.push({ ...row, icon: '' });
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
emptyPanel: {
|
||||
height: '100%',
|
||||
background: theme.palette.grey[400],
|
||||
overflow: 'auto',
|
||||
padding: '8px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexGrow: 1,
|
||||
},
|
||||
fixedSizeList: {
|
||||
overflowX: 'hidden !important',
|
||||
overflow: 'overlay !important',
|
||||
height: 'auto !important',
|
||||
},
|
||||
dashboardPanel: {
|
||||
height: '100%',
|
||||
background: theme.palette.grey[400],
|
||||
},
|
||||
cardHeader: {
|
||||
padding: '0.25rem 0.5rem',
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: theme.otherVars.tableBg,
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: theme.otherVars.borderColor,
|
||||
},
|
||||
searchPadding: {
|
||||
display: 'flex',
|
||||
flex: 2.5,
|
||||
},
|
||||
component: {
|
||||
padding: '8px',
|
||||
},
|
||||
searchInput: {
|
||||
flex: 1,
|
||||
},
|
||||
panelIcon: {
|
||||
width: '80%',
|
||||
margin: '0 auto',
|
||||
marginTop: '25px !important',
|
||||
position: 'relative',
|
||||
textAlign: 'center',
|
||||
},
|
||||
panelMessage: {
|
||||
marginLeft: '0.5rem',
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
panelContent: {
|
||||
...theme.mixins.panelBorder,
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden !important',
|
||||
flexGrow: 1
|
||||
},
|
||||
terminateButton: {
|
||||
color: theme.palette.error.main
|
||||
},
|
||||
buttonClick: {
|
||||
backgroundColor: theme.palette.grey[400]
|
||||
}
|
||||
}));
|
||||
|
||||
/* eslint-disable react/display-name */
|
||||
export default function Dashboard({
|
||||
nodeData,
|
||||
node,
|
||||
item,
|
||||
pgBrowser,
|
||||
preferences,
|
||||
sid,
|
||||
did,
|
||||
treeNodeInfo,
|
||||
...props
|
||||
}) {
|
||||
const classes = useStyles();
|
||||
let tab = ['Sessions', 'Locks', 'Prepared Transactions'];
|
||||
const [dashData, setdashData] = useState([]);
|
||||
const [msg, setMsg] = useState('');
|
||||
const[infoMsg, setInfo] = useState('');
|
||||
const [val, setVal] = useState(0);
|
||||
const [schemaDict, setSchemaDict] = React.useState({});
|
||||
|
||||
if (!did) {
|
||||
tab.push('Configuration');
|
||||
}
|
||||
val == 3 && did && setVal(0);
|
||||
const tabChanged = (e, tabVal) => {
|
||||
setVal(tabVal);
|
||||
};
|
||||
|
||||
const serverConfigColumns = [
|
||||
{
|
||||
accessor: 'name',
|
||||
Header: gettext('Name'),
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 110,
|
||||
},
|
||||
{
|
||||
accessor: 'category',
|
||||
Header: gettext('Category'),
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 150,
|
||||
},
|
||||
{
|
||||
accessor: 'setting',
|
||||
Header: gettext('Setting'),
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 50,
|
||||
},
|
||||
{
|
||||
accessor: 'unit',
|
||||
Header: gettext('Unit'),
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 30,
|
||||
},
|
||||
{
|
||||
accessor: 'short_desc',
|
||||
Header: gettext('Description'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
];
|
||||
|
||||
const activityColumns = [
|
||||
{
|
||||
accessor: 'terminate_query',
|
||||
Header: () => null,
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 16,
|
||||
maxWidth: 30,
|
||||
id: 'btn-terminate',
|
||||
// eslint-disable-next-line react/display-name
|
||||
Cell: ({ row }) => {
|
||||
var terminate_session_url =
|
||||
url_for('dashboard.index') + 'terminate_session' + '/' + sid,
|
||||
title = gettext('Terminate Session?'),
|
||||
txtConfirm = gettext(
|
||||
'Are you sure you wish to terminate the session?'
|
||||
),
|
||||
txtSuccess = gettext('Session terminated successfully.'),
|
||||
txtError = gettext(
|
||||
'An error occurred whilst terminating the active query.'
|
||||
);
|
||||
const action_url = did
|
||||
? terminate_session_url + '/' + did
|
||||
: terminate_session_url;
|
||||
|
||||
const api = getApiInstance();
|
||||
|
||||
return (
|
||||
<PgIconButton
|
||||
size="xs"
|
||||
noBorder
|
||||
icon={<CancelIcon />}
|
||||
className={classes.terminateButton}
|
||||
onClick={() => {
|
||||
if (
|
||||
!canTakeAction(row, 'terminate')
|
||||
)
|
||||
return;
|
||||
let url = action_url + '/' + row.values.pid;
|
||||
Notify.confirm(
|
||||
title,
|
||||
txtConfirm,
|
||||
function () {
|
||||
api
|
||||
.delete(url)
|
||||
.then(function (res) {
|
||||
if (res.data == gettext('Success')) {
|
||||
setInfo(txtSuccess);
|
||||
Notify.success(txtSuccess);
|
||||
} else {
|
||||
setInfo(txtError);
|
||||
Notify.error(txtError);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
Notify.alert(
|
||||
gettext('Failed to retrieve data from the server.'),
|
||||
gettext(error.message)
|
||||
);
|
||||
});
|
||||
},
|
||||
function () {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}}
|
||||
color="default"
|
||||
aria-label="Terminate Session?"
|
||||
title={gettext('Terminate Session?')}
|
||||
></PgIconButton>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: 'cancel_Query',
|
||||
Header: () => null,
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 16,
|
||||
maxWidth: 30,
|
||||
id: 'btn-cancel',
|
||||
Cell: ({ row }) => {
|
||||
var cancel_query_url =
|
||||
url_for('dashboard.index') + 'cancel_query' + '/' + sid,
|
||||
title = gettext('Cancel Active Query?'),
|
||||
txtConfirm = gettext(
|
||||
'Are you sure you wish to cancel the active query?'
|
||||
),
|
||||
txtSuccess = gettext('Active query cancelled successfully.'),
|
||||
txtError = gettext(
|
||||
'An error occurred whilst cancelling the active query.'
|
||||
);
|
||||
|
||||
const action_url = did ? cancel_query_url + '/' + did : cancel_query_url;
|
||||
|
||||
const api = getApiInstance();
|
||||
|
||||
return (
|
||||
<PgIconButton
|
||||
size="xs"
|
||||
noBorder
|
||||
icon={<SquareIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
if (!canTakeAction(row, 'cancel'))
|
||||
return;
|
||||
let url = action_url + '/' + row.values.pid;
|
||||
Notify.confirm(
|
||||
title,
|
||||
txtConfirm,
|
||||
function () {
|
||||
api
|
||||
.delete(url)
|
||||
.then(function (res) {
|
||||
if (res.data == gettext('Success')) {
|
||||
setInfo(txtSuccess);
|
||||
Notify.success(txtSuccess);
|
||||
} else {
|
||||
setInfo(txtError);
|
||||
Notify.error(txtError);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
Notify.alert(
|
||||
gettext('Failed to retrieve data from the server.'),
|
||||
gettext(error.message)
|
||||
);
|
||||
});
|
||||
},
|
||||
function () {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}}
|
||||
color="default"
|
||||
aria-label="Cancel the query"
|
||||
title={gettext('Cancel the active query')}
|
||||
></PgIconButton>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: 'view_active_query',
|
||||
Header: () => null,
|
||||
sortble: true,
|
||||
resizable: true,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 16,
|
||||
maxWidth: 30,
|
||||
id: 'btn-edit',
|
||||
Cell: ({ row }) => {
|
||||
let canEditRow = true;
|
||||
return (
|
||||
<PgIconButton
|
||||
className={row.isExpanded ?classes.buttonClick : ''}
|
||||
icon={
|
||||
row.isExpanded ? (
|
||||
<ArrowDropDownOutlinedIcon />
|
||||
) : (
|
||||
<ArrowRightOutlinedIcon />
|
||||
)
|
||||
}
|
||||
size="xs"
|
||||
noBorder
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
row.toggleRowExpanded(!row.isExpanded);
|
||||
if(!(row.id in schemaDict)){
|
||||
let schema = new ActiveQuery({
|
||||
query: row.original.query,
|
||||
backend_type: row.original.backend_type,
|
||||
state_change: row.original.state_change,
|
||||
query_start: row.original.query_start,
|
||||
});
|
||||
setSchemaDict(prevState => ({
|
||||
...prevState,
|
||||
[row.id]: schema
|
||||
}));
|
||||
}
|
||||
}}
|
||||
disabled={!canEditRow}
|
||||
aria-label="View the active session details"
|
||||
title={gettext('View the active session details')}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessor: 'pid',
|
||||
Header: gettext('PID'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 60,
|
||||
},
|
||||
{
|
||||
accessor: 'datname',
|
||||
Header: gettext('Database'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 80,
|
||||
isVisible: !did ? true: false
|
||||
},
|
||||
{
|
||||
accessor: 'usename',
|
||||
Header: gettext('User'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 80,
|
||||
},
|
||||
{
|
||||
accessor: 'application_name',
|
||||
Header: gettext('Application'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 150,
|
||||
},
|
||||
{
|
||||
accessor: 'client_addr',
|
||||
Header: gettext('Client'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 60,
|
||||
},
|
||||
{
|
||||
accessor: 'backend_start',
|
||||
Header: gettext('Backend start'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 150,
|
||||
},
|
||||
{
|
||||
accessor: 'xact_start',
|
||||
Header: gettext('Transaction start'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 150,
|
||||
},
|
||||
{
|
||||
accessor: 'state',
|
||||
Header: gettext('State'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 60,
|
||||
},
|
||||
|
||||
{
|
||||
accessor: 'waiting',
|
||||
Header: gettext('Waiting'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
isVisible: treeNodeInfo?.server?.version < 90600
|
||||
},
|
||||
{
|
||||
accessor: 'wait_event',
|
||||
Header: gettext('Wait event'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
accessor: 'blocking_pids',
|
||||
Header: gettext('Blocking PIDs'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
];
|
||||
|
||||
const databaseLocksColumns = [
|
||||
{
|
||||
accessor: 'pid',
|
||||
Header: gettext('PID'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 50,
|
||||
},
|
||||
{
|
||||
accessor: 'datname',
|
||||
Header: gettext('Database'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 80,
|
||||
isVisible: !did ? true: false
|
||||
},
|
||||
{
|
||||
accessor: 'locktype',
|
||||
Header: gettext('Lock type'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 60,
|
||||
},
|
||||
{
|
||||
accessor: 'relation',
|
||||
Header: gettext('Target relation'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
accessor: 'page',
|
||||
Header: gettext('Page'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 50,
|
||||
},
|
||||
{
|
||||
accessor: 'tuple',
|
||||
Header: gettext('Tuple'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 50,
|
||||
},
|
||||
{
|
||||
accessor: 'virtualxid',
|
||||
Header: gettext('vXID (target)'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
},
|
||||
{
|
||||
accessor: 'transactionid',
|
||||
Header: gettext('XID (target)'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 100,
|
||||
},
|
||||
{
|
||||
accessor: 'classid',
|
||||
Header: gettext('Class'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 50,
|
||||
},
|
||||
{
|
||||
accessor: 'objid',
|
||||
Header: gettext('Object ID'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 100,
|
||||
},
|
||||
{
|
||||
accessor: 'virtualtransaction',
|
||||
Header: gettext('vXID (owner)'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 80,
|
||||
},
|
||||
{
|
||||
accessor: 'mode',
|
||||
Header: gettext('Mode'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
id: 'granted',
|
||||
accessor: 'granted',
|
||||
Header: gettext('Granted?'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 50,
|
||||
maxWidth: 80,
|
||||
Cell: ({ value }) => String(value)
|
||||
},
|
||||
];
|
||||
|
||||
const databasePreparedColumns = [
|
||||
{
|
||||
accessor: 'git',
|
||||
Header: gettext('Name'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
accessor: 'datname',
|
||||
Header: gettext('Database'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
minWidth: 26,
|
||||
maxWidth: 80,
|
||||
isVisible: !did ? true: false
|
||||
},
|
||||
{
|
||||
accessor: 'Owner',
|
||||
Header: gettext('Owner'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
accessor: 'transaction',
|
||||
Header: gettext('XID'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
{
|
||||
accessor: 'prepared',
|
||||
Header: gettext('Prepared at'),
|
||||
sortble: true,
|
||||
resizable: false,
|
||||
disableGlobalFilter: false,
|
||||
},
|
||||
];
|
||||
|
||||
const canTakeAction = (row, cellAction) => {
|
||||
// We will validate if user is allowed to cancel the active query
|
||||
// If there is only one active session means it probably our main
|
||||
// connection session
|
||||
cellAction = cellAction || null;
|
||||
var pg_version = treeNodeInfo.server.version || null,
|
||||
is_cancel_session = cellAction === 'cancel',
|
||||
txtMessage,
|
||||
maintenance_database = treeNodeInfo.server.db,
|
||||
is_super_user,
|
||||
current_user;
|
||||
|
||||
var can_signal_backend =
|
||||
treeNodeInfo.server && treeNodeInfo.server.user
|
||||
? treeNodeInfo.server.user.can_signal_backend
|
||||
: false;
|
||||
|
||||
if (
|
||||
treeNodeInfo.server &&
|
||||
treeNodeInfo.server.user &&
|
||||
treeNodeInfo.server.user.is_superuser
|
||||
) {
|
||||
is_super_user = true;
|
||||
} else {
|
||||
is_super_user = false;
|
||||
current_user =
|
||||
treeNodeInfo.server && treeNodeInfo.server.user
|
||||
? treeNodeInfo.server.user.name
|
||||
: null;
|
||||
}
|
||||
|
||||
// With PG10, We have background process showing on dashboard
|
||||
// We will not allow user to cancel them as they will fail with error
|
||||
// anyway, so better usability we will throw our on notification
|
||||
|
||||
// Background processes do not have database field populated
|
||||
if (pg_version && pg_version >= 100000 && !row.original.datname) {
|
||||
if (is_cancel_session) {
|
||||
txtMessage = gettext('You cannot cancel background worker processes.');
|
||||
} else {
|
||||
txtMessage = gettext(
|
||||
'You cannot terminate background worker processes.'
|
||||
);
|
||||
}
|
||||
Notify.info(txtMessage);
|
||||
return false;
|
||||
// If it is the last active connection on maintenance db then error out
|
||||
} else if (
|
||||
maintenance_database == row.original.datname &&
|
||||
row.original.state == 'active'
|
||||
) {
|
||||
if (is_cancel_session) {
|
||||
txtMessage = gettext(
|
||||
'You are not allowed to cancel the main active session.'
|
||||
);
|
||||
} else {
|
||||
txtMessage = gettext(
|
||||
'You are not allowed to terminate the main active session.'
|
||||
);
|
||||
}
|
||||
Notify.error(txtMessage);
|
||||
return false;
|
||||
} else if (is_cancel_session && row.original.state == 'idle') {
|
||||
// If this session is already idle then do nothing
|
||||
Notify.info(gettext('The session is already in idle state.'));
|
||||
return false;
|
||||
} else if (can_signal_backend) {
|
||||
// user with membership of 'pg_signal_backend' can terminate the session of non admin user.
|
||||
return true;
|
||||
} else if (is_super_user) {
|
||||
// Super user can do anything
|
||||
return true;
|
||||
} else if (current_user && current_user == treeNodeInfo.server.user) {
|
||||
// Non-super user can cancel only their active queries
|
||||
return true;
|
||||
} else {
|
||||
// Do not allow to cancel someone else session to non-super user
|
||||
if (is_cancel_session) {
|
||||
txtMessage = gettext(
|
||||
'Superuser privileges are required to cancel another users query.'
|
||||
);
|
||||
} else {
|
||||
txtMessage = gettext(
|
||||
'Superuser privileges are required to terminate another users query.'
|
||||
);
|
||||
}
|
||||
Notify.error(txtMessage);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let url,
|
||||
message = gettext(
|
||||
'Please connect to the selected server to view the dashboard.'
|
||||
);
|
||||
|
||||
if (sid && props.serverConnected) {
|
||||
|
||||
if (val === 0) {
|
||||
url = url_for('dashboard.activity');
|
||||
} else if (val === 1) {
|
||||
url = url_for('dashboard.locks');
|
||||
} else if (val === 2) {
|
||||
url = url_for('dashboard.prepared');
|
||||
} else {
|
||||
url = url_for('dashboard.config');
|
||||
}
|
||||
|
||||
message = gettext('Loading dashboard...');
|
||||
if (did) url += sid + '/' + did;
|
||||
else url += sid;
|
||||
|
||||
const api = getApiInstance();
|
||||
if (node) {
|
||||
api({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
})
|
||||
.then((res) => {
|
||||
setdashData(parseData(res.data));
|
||||
})
|
||||
.catch((e) => {
|
||||
Notify.alert(
|
||||
gettext('Failed to retrieve data from the server.'),
|
||||
gettext(e.message)
|
||||
);
|
||||
// show failed message.
|
||||
setMsg(gettext('Failed to retrieve data from the server.'));
|
||||
});
|
||||
} else {
|
||||
setMsg(message);
|
||||
}
|
||||
}
|
||||
if (message != '') {
|
||||
setMsg(message);
|
||||
}
|
||||
}, [nodeData, val, did, preferences, infoMsg]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{sid && props.serverConnected ? (
|
||||
<Box className={classes.dashboardPanel}>
|
||||
<Box className={classes.emptyPanel}>
|
||||
{!_.isUndefined(preferences) && preferences.show_graphs && (
|
||||
<Graphs
|
||||
preferences={preferences}
|
||||
sid={sid}
|
||||
did={did}
|
||||
pageVisible={true}
|
||||
></Graphs>
|
||||
)}
|
||||
<Box className={classes.panelContent}>
|
||||
<Box
|
||||
className={classes.cardHeader}
|
||||
title={gettext('Server activity')}
|
||||
>
|
||||
{gettext('Server activity')}{' '}
|
||||
</Box>
|
||||
<Tabs
|
||||
value={val}
|
||||
onChange={tabChanged}
|
||||
className={classes.searchInput}
|
||||
>
|
||||
{tab.map((tabValue, i) => {
|
||||
return <Tab key={i} label={tabValue} />;
|
||||
})}
|
||||
</Tabs>
|
||||
|
||||
<PgTable
|
||||
columns={
|
||||
val === 0
|
||||
? activityColumns
|
||||
: val === 1
|
||||
? databaseLocksColumns
|
||||
: val == 2
|
||||
? databasePreparedColumns
|
||||
: serverConfigColumns
|
||||
}
|
||||
data={dashData}
|
||||
schema={schemaDict}
|
||||
offset={145}
|
||||
></PgTable>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
) : sid && !props.serverConnected ? (
|
||||
<Box className={classes.dashboardPanel}>
|
||||
<div className={classes.emptyPanel}>
|
||||
<div className={classes.panelIcon}>
|
||||
<i className="fa fa-exclamation-circle"></i>
|
||||
<span className={classes.panelMessage}>{gettext(msg)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
) : (
|
||||
<WelcomeDashboard
|
||||
pgBrowser={pgBrowser}
|
||||
node={node}
|
||||
itemData={nodeData}
|
||||
item={item}
|
||||
sid={sid}
|
||||
did={did}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Dashboard.propTypes = {
|
||||
node: PropTypes.func,
|
||||
itemData: PropTypes.object,
|
||||
nodeData: PropTypes.object,
|
||||
treeNodeInfo: PropTypes.object,
|
||||
item: PropTypes.object,
|
||||
pgBrowser: PropTypes.object,
|
||||
preferences: PropTypes.object,
|
||||
sid: PropTypes.string,
|
||||
did: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
|
||||
row: PropTypes.object,
|
||||
serverConnected: PropTypes.bool,
|
||||
};
|
||||
|
||||
export function ChartContainer(props) {
|
||||
return (
|
||||
<div
|
||||
className="card dashboard-graph"
|
||||
role="object-document"
|
||||
tabIndex="0"
|
||||
aria-labelledby={props.id}
|
||||
>
|
||||
<div className="card-header">
|
||||
<div className="d-flex">
|
||||
<div id={props.id}>{props.title}</div>
|
||||
<div className="ml-auto my-auto legend" ref={props.legendRef}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body dashboard-graph-body">
|
||||
<div className={'chart-wrapper ' + (props.errorMsg ? 'd-none' : '')}>
|
||||
{props.children}
|
||||
</div>
|
||||
<ChartError message={props.errorMsg} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChartContainer.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
legendRef: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.shape({ current: PropTypes.any }),
|
||||
]).isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
errorMsg: PropTypes.string,
|
||||
};
|
||||
|
||||
export function ChartError(props) {
|
||||
if (props.message === null) {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<div className="pg-panel-error pg-panel-message" role="alert">
|
||||
{props.message}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChartError.propTypes = {
|
||||
message: PropTypes.string,
|
||||
};
|
||||
|
||||
export function DashboardRow({ children }) {
|
||||
return <div className="row dashboard-row">{children}</div>;
|
||||
}
|
||||
DashboardRow.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export function DashboardRowCol({ breakpoint, parts, children }) {
|
||||
return <div className={`col-${breakpoint}-${parts}`}>{children}</div>;
|
||||
}
|
||||
|
||||
DashboardRowCol.propTypes = {
|
||||
breakpoint: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']).isRequired,
|
||||
parts: PropTypes.number.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, { useEffect, useRef, useState, useReducer, useCallback, useMemo } from 'react';
|
||||
import {LineChart} from 'sources/chartjs';
|
||||
import {ChartContainer, DashboardRowCol, DashboardRow} from './dashboard_components';
|
||||
import {ChartContainer, DashboardRowCol, DashboardRow} from './Dashboard';
|
||||
import url_for from 'sources/url_for';
|
||||
import axios from 'axios';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
219
web/pgadmin/dashboard/static/js/PgAdminLogo.jsx
Normal file
219
web/pgadmin/dashboard/static/js/PgAdminLogo.jsx
Normal file
@@ -0,0 +1,219 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React from 'react';
|
||||
|
||||
export default function PgAdminLogo() {
|
||||
|
||||
return (
|
||||
<div className="welcome-logo" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 130">
|
||||
<defs>
|
||||
<style>{'.cls-1{stroke:#000;stroke-width:10.19px;}.cls-2{fill:#336791;}.cls-3,.cls-4,.cls-9{fill:none;}.cls-3,.cls-4,.cls-5,.cls-6{stroke:#fff;}.cls-3,.cls-4{stroke-linecap:round;stroke-width:3.4px;}.cls-3{stroke-linejoin:round;}.cls-4{stroke-linejoin:bevel;}.cls-5,.cls-6{fill:#fff;}.cls-5{stroke-width:1.13px;}.cls-6{stroke-width:0.57px;}.cls-7{fill:#2775b6;}.cls-8{fill:#333;}.cls-9{stroke:#333;stroke-width:3px;}'}</style>
|
||||
</defs>
|
||||
<title>pgAdmin_PostgreSQL</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<g id="Layer_3">
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M95.59,93.65c.77-6.44.54-7.38,5.33-6.34l1.21.11a27.6,27.6,0,0,0,11.34-1.91c6.09-2.83,9.71-7.55,3.7-6.31-13.71,2.83-14.65-1.81-14.65-1.81C117,55.91,123,28.64,117.82,22,103.57,3.76,78.91,12.37,78.5,12.6l-.13,0a48.65,48.65,0,0,0-9.15-.95C63,11.57,58.31,13.29,54.74,16c0,0-44-18.12-41.95,22.8.44,8.7,12.48,65.86,26.84,48.6C44.88,81.08,50,75.75,50,75.75A13.39,13.39,0,0,0,58.65,78l.25-.21a9,9,0,0,0,.1,2.46c-3.7,4.13-2.62,4.86-10,6.38s-3.09,4.29-.22,5c3.48.87,11.53,2.1,17-5.52l-.22.87c1.46,1.16,1.36,8.35,1.56,13.48s.55,9.93,1.6,12.75,2.28,10.1,12,8C88.81,119.46,95,117,95.59,93.65"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M117.17,79.2c-13.71,2.83-14.65-1.81-14.65-1.81C117,55.91,123,28.64,117.82,22,103.57,3.76,78.91,12.37,78.5,12.6l-.13,0a48.65,48.65,0,0,0-9.15-.95C63,11.57,58.31,13.29,54.74,16c0,0-44-18.12-41.95,22.8.44,8.7,12.48,65.86,26.84,48.6C44.88,81.08,50,75.75,50,75.75A13.39,13.39,0,0,0,58.65,78l.25-.21A9.41,9.41,0,0,0,59,80.22c-3.7,4.13-2.61,4.86-10,6.38s-3.08,4.29-.21,5c3.48.87,11.53,2.1,17-5.52l-.22.87c1.45,1.16,2.47,7.56,2.3,13.35s-.28,9.77.86,12.88,2.28,10.1,12,8C88.81,119.46,93,115,93.6,107.42,94,102.07,95,102.87,95,98.08l.75-2.26c.87-7.26.14-9.6,5.15-8.51l1.21.11a27.6,27.6,0,0,0,11.34-1.91c6.09-2.83,9.71-7.55,3.7-6.31Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M66.33,83.36c-.38,13.5.09,27.09,1.41,30.39s4.15,9.73,13.88,7.64c8.12-1.74,11.08-5.11,12.36-12.55.94-5.47,2.77-20.67,3-23.79"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M54.67,15.7s-44-18-42,22.93c.44,8.7,12.48,65.87,26.84,48.6,5.25-6.32,10-11.27,10-11.27"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M78.45,12.42c-1.52.47,24.49-9.51,39.28,9.38,5.22,6.67-.83,33.94-15.31,55.42"
|
||||
/>
|
||||
<path
|
||||
className="cls-4"
|
||||
d="M102.42,77.22s.94,4.64,14.65,1.81c6-1.24,2.4,3.48-3.7,6.31-5,2.32-16.21,2.92-16.39-.29-.47-8.27,5.9-5.76,5.44-7.83-.42-1.87-3.26-3.7-5.15-8.27-1.64-4-22.57-34.58,5.8-30,1-.22-7.4-27-33.95-27.42S43.45,44.14,43.45,44.14"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M58.9,80.05c-3.7,4.13-2.61,4.86-10,6.38s-3.09,4.29-.22,5c3.48.87,11.53,2.1,17-5.52,1.66-2.32,0-6-2.28-7-1.1-.46-2.57-1-4.46,1.09Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M58.66,80c-.38-2.44.79-5.33,2.05-8.71C62.6,66.19,67,61.11,63.47,45c-2.6-12-20-2.5-20-.87a81.48,81.48,0,0,1-.29,16c-1.41,10.06,6.4,18.57,15.39,17.7"
|
||||
/>
|
||||
<path
|
||||
className="cls-5"
|
||||
d="M54.51,43.9c-.08.55,1,2,2.45,2.23a2.62,2.62,0,0,0,2.72-1.51c.08-.56-1-1.17-2.44-1.37s-2.65.09-2.73.65Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-6"
|
||||
d="M98,42.76c.07.56-1,2-2.45,2.24a2.64,2.64,0,0,1-2.73-1.52c-.07-.55,1-1.16,2.45-1.36s2.65.09,2.73.64Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M103.07,38.92c.24,4.36-.94,7.33-1.08,12-.22,6.74,3.21,14.46-2,22.19"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M154.72,28.15h5.16v4.16A12.84,12.84,0,0,1,163.35,29a11.17,11.17,0,0,1,6.28-1.76,11.84,11.84,0,0,1,9.08,4.09c2.48,2.72,3.73,6.62,3.73,11.67q0,10.26-5.38,14.65a12.2,12.2,0,0,1-7.95,2.79,10.78,10.78,0,0,1-6-1.56,13.55,13.55,0,0,1-3.14-3v16h-5.28Zm19.84,24.6Q177,49.65,177,43.5a17,17,0,0,0-1.09-6.44,7.51,7.51,0,0,0-7.53-5.19q-5.49,0-7.52,5.48a21.49,21.49,0,0,0-1.09,7.44A15.64,15.64,0,0,0,160.88,51a8,8,0,0,0,13.68,1.78Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M206,29.26a14.6,14.6,0,0,1,3,3V28.3h4.86V56.83c0,4-.58,7.13-1.75,9.44q-3.27,6.38-12.35,6.38a15.07,15.07,0,0,1-8.5-2.27,8.86,8.86,0,0,1-3.85-7.1h5.36a6,6,0,0,0,1.52,3.25q1.77,1.75,5.59,1.76,6,0,7.9-4.28,1.1-2.52,1-9a10.39,10.39,0,0,1-3.8,3.57,13.56,13.56,0,0,1-14.75-2.45q-3.81-3.62-3.81-12,0-7.89,3.84-12.31a11.85,11.85,0,0,1,9.27-4.42A11.37,11.37,0,0,1,206,29.26Zm.64,5.66a7.61,7.61,0,0,0-6.09-2.81A7.52,7.52,0,0,0,193,37.32a20.56,20.56,0,0,0-1.08,7.3c0,3.53.72,6.22,2.14,8.07a6.93,6.93,0,0,0,5.76,2.77,8.09,8.09,0,0,0,8-5.13A16.72,16.72,0,0,0,209,43.56Q209,37.73,206.62,34.92Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M235.16,16.34h6.58l15.62,43H251l-4.5-12.89H229.6l-4.67,12.89h-6Zm9.67,25.4-6.63-19-6.88,19Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M279.16,29a14.3,14.3,0,0,1,3.18,3.08V16.2h5.07V59.38h-4.75V55a11.33,11.33,0,0,1-4.35,4.19,12.51,12.51,0,0,1-5.75,1.28,11.61,11.61,0,0,1-9-4.4q-3.82-4.41-3.83-11.74a20.35,20.35,0,0,1,3.49-11.88,11.41,11.41,0,0,1,10-5A11.15,11.15,0,0,1,279.16,29ZM267.39,52.5q2.13,3.39,6.82,3.39a7.17,7.17,0,0,0,6-3.14c1.56-2.1,2.35-5.12,2.35-9s-.81-6.9-2.42-8.81a7.56,7.56,0,0,0-6-2.85,7.88,7.88,0,0,0-6.43,3c-1.64,2-2.46,5-2.46,9A15.62,15.62,0,0,0,267.39,52.5Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M295.29,28h5.21v4.46a17.4,17.4,0,0,1,3.4-3.37,10.24,10.24,0,0,1,5.92-1.79,9.34,9.34,0,0,1,6,1.85,9.61,9.61,0,0,1,2.34,3.1,11.37,11.37,0,0,1,4.13-3.73,11.52,11.52,0,0,1,5.33-1.22q6.33,0,8.62,4.57a15,15,0,0,1,1.23,6.62V59.38H332V37.58c0-2.09-.52-3.52-1.57-4.3a6.2,6.2,0,0,0-3.82-1.17,7.58,7.58,0,0,0-5.35,2.08c-1.49,1.38-2.24,3.7-2.24,6.94V59.38h-5.36V38.9a10.78,10.78,0,0,0-.76-4.66q-1.2-2.19-4.49-2.19A7.73,7.73,0,0,0,303,34.36c-1.63,1.54-2.45,4.34-2.45,8.38V59.38h-5.27Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M345.27,16.34h5.36v6h-5.36Zm0,11.81h5.36V59.38h-5.36Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-7 app-name"
|
||||
d="M358.6,28h5v4.46a14,14,0,0,1,4.72-4,12.56,12.56,0,0,1,5.53-1.2c4.46,0,7.46,1.55,9,4.66a16.52,16.52,0,0,1,1.29,7.29V59.38h-5.37V39.61A10.8,10.8,0,0,0,378,35a5.15,5.15,0,0,0-5.1-2.93,10.21,10.21,0,0,0-3.08.38A8,8,0,0,0,366,35a7.66,7.66,0,0,0-1.71,3.2,21.84,21.84,0,0,0-.4,4.74V59.38H358.6Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M155.24,86.87h3.9l5.77,17,5.74-17h3.87V107h-2.6V95.1q0-.61,0-2c0-.94,0-2,0-3L166.24,107h-2.7L157.75,90v.61c0,.49,0,1.24,0,2.25s.05,1.75.05,2.22V107h-2.6Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M186.15,98.09a1.35,1.35,0,0,0,1.14-.71,2.31,2.31,0,0,0,.16-.94,2,2,0,0,0-.89-1.84A4.79,4.79,0,0,0,184,94a3.21,3.21,0,0,0-2.73,1,3.44,3.44,0,0,0-.59,1.72h-2.3A4.28,4.28,0,0,1,180.14,93,7.16,7.16,0,0,1,184.05,92a8,8,0,0,1,4.19,1,3.34,3.34,0,0,1,1.6,3.06v8.44a1.06,1.06,0,0,0,.16.62.77.77,0,0,0,.66.23l.37,0,.44-.07V107a7.38,7.38,0,0,1-.88.21,5.92,5.92,0,0,1-.82,0,2,2,0,0,1-1.84-.9,3.63,3.63,0,0,1-.43-1.36,6.16,6.16,0,0,1-2.16,1.71,6.56,6.56,0,0,1-3.1.73,4.59,4.59,0,0,1-3.33-1.24,4.09,4.09,0,0,1-1.29-3.09,4,4,0,0,1,1.27-3.16,6.16,6.16,0,0,1,3.34-1.38ZM181,104.74a2.88,2.88,0,0,0,1.84.62,5.51,5.51,0,0,0,2.52-.61,3.37,3.37,0,0,0,2-3.26v-2a3.79,3.79,0,0,1-1.16.48,10.37,10.37,0,0,1-1.39.28l-1.49.19a5.68,5.68,0,0,0-2,.56,2.18,2.18,0,0,0-1.14,2A2,2,0,0,0,181,104.74Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M193.88,92.31h2.33v2.08a6.73,6.73,0,0,1,2.2-1.85A6,6,0,0,1,201,92q3.12,0,4.21,2.18a7.73,7.73,0,0,1,.6,3.4V107h-2.5V97.73a4.87,4.87,0,0,0-.4-2.16,2.41,2.41,0,0,0-2.38-1.37,4.75,4.75,0,0,0-1.43.18,3.68,3.68,0,0,0-1.78,1.2,3.55,3.55,0,0,0-.8,1.5,10.3,10.3,0,0,0-.18,2.21V107h-2.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M217.29,98.09a1.33,1.33,0,0,0,1.14-.71,2.15,2.15,0,0,0,.16-.94,2,2,0,0,0-.89-1.84,4.79,4.79,0,0,0-2.56-.56,3.24,3.24,0,0,0-2.73,1,3.44,3.44,0,0,0-.58,1.72h-2.3A4.27,4.27,0,0,1,211.28,93,7.19,7.19,0,0,1,215.2,92a8,8,0,0,1,4.19,1A3.36,3.36,0,0,1,221,96v8.44a1.14,1.14,0,0,0,.15.62.79.79,0,0,0,.67.23l.37,0,.43-.07V107a7.32,7.32,0,0,1-.87.21,6,6,0,0,1-.82,0,2,2,0,0,1-1.85-.9,3.46,3.46,0,0,1-.42-1.36,6.16,6.16,0,0,1-2.16,1.71,6.63,6.63,0,0,1-3.11.73,4.58,4.58,0,0,1-3.32-1.24,4.06,4.06,0,0,1-1.3-3.09A4,4,0,0,1,210,100a6.13,6.13,0,0,1,3.33-1.38Zm-5.18,6.65a2.91,2.91,0,0,0,1.85.62,5.47,5.47,0,0,0,2.51-.61,3.38,3.38,0,0,0,2.06-3.26v-2a3.9,3.9,0,0,1-1.16.48,10.51,10.51,0,0,1-1.4.28l-1.48.19a5.55,5.55,0,0,0-2,.56,2.17,2.17,0,0,0-1.15,2A2,2,0,0,0,212.11,104.74Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M233.16,92.9a7.05,7.05,0,0,1,1.42,1.39V92.45h2.27v13.32a10,10,0,0,1-.82,4.4c-1,2-2.94,3-5.77,3a7.09,7.09,0,0,1-4-1.06,4.15,4.15,0,0,1-1.8-3.32H227a2.81,2.81,0,0,0,.71,1.52,3.57,3.57,0,0,0,2.61.82c1.88,0,3.1-.66,3.68-2a11.15,11.15,0,0,0,.48-4.2,4.84,4.84,0,0,1-1.77,1.67,5.93,5.93,0,0,1-2.74.54,5.79,5.79,0,0,1-4.14-1.69q-1.79-1.68-1.78-5.58a8.49,8.49,0,0,1,1.79-5.74,5.51,5.51,0,0,1,4.32-2.07A5.33,5.33,0,0,1,233.16,92.9Zm.3,2.64a3.77,3.77,0,0,0-6.38,1.12,9.73,9.73,0,0,0-.5,3.4,6.05,6.05,0,0,0,1,3.77,3.21,3.21,0,0,0,2.68,1.29,3.77,3.77,0,0,0,3.72-2.39,7.71,7.71,0,0,0,.6-3.16A6.13,6.13,0,0,0,233.46,95.54Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M249.64,92.72a5.44,5.44,0,0,1,2.21,1.89,6.52,6.52,0,0,1,1,2.58,17.44,17.44,0,0,1,.22,3.23H242.4a6.34,6.34,0,0,0,1,3.59,3.49,3.49,0,0,0,3,1.35,3.9,3.9,0,0,0,3.05-1.28,4.5,4.5,0,0,0,.9-1.72h2.42a5,5,0,0,1-.63,1.8,6.58,6.58,0,0,1-1.21,1.62,5.71,5.71,0,0,1-2.75,1.48,8.71,8.71,0,0,1-2,.21,6.11,6.11,0,0,1-4.6-2,7.79,7.79,0,0,1-1.89-5.58,8.41,8.41,0,0,1,1.9-5.72,6.26,6.26,0,0,1,5-2.21A6.59,6.59,0,0,1,249.64,92.72Zm.88,5.74a6.46,6.46,0,0,0-.69-2.55,3.54,3.54,0,0,0-3.35-1.78,3.72,3.72,0,0,0-2.82,1.22,4.69,4.69,0,0,0-1.21,3.11Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M256.16,92.31h2.44v2.08a8.23,8.23,0,0,1,1.58-1.57A4.79,4.79,0,0,1,263,92a4.31,4.31,0,0,1,2.81.87,4.5,4.5,0,0,1,1.1,1.44,5.27,5.27,0,0,1,1.92-1.74,5.37,5.37,0,0,1,2.49-.57,4.08,4.08,0,0,1,4,2.14,7,7,0,0,1,.58,3.09V107h-2.56V96.78a2.41,2.41,0,0,0-.73-2,2.93,2.93,0,0,0-1.79-.54,3.53,3.53,0,0,0-2.49,1,4.23,4.23,0,0,0-1.05,3.24V107h-2.5V97.4a5,5,0,0,0-.36-2.18,2.17,2.17,0,0,0-2.09-1,3.59,3.59,0,0,0-2.53,1.08c-.76.72-1.14,2-1.14,3.91V107h-2.47Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M288.53,92.72a5.47,5.47,0,0,1,2.22,1.89,6.67,6.67,0,0,1,1,2.58,17.66,17.66,0,0,1,.21,3.23H281.29a6.42,6.42,0,0,0,1,3.59,3.48,3.48,0,0,0,3,1.35,3.9,3.9,0,0,0,3.06-1.28,4.5,4.5,0,0,0,.9-1.72h2.42a5.23,5.23,0,0,1-.64,1.8,6.56,6.56,0,0,1-1.2,1.62,5.7,5.7,0,0,1-2.76,1.48,8.62,8.62,0,0,1-2,.21,6.14,6.14,0,0,1-4.61-2,7.79,7.79,0,0,1-1.89-5.58,8.41,8.41,0,0,1,1.91-5.72,6.24,6.24,0,0,1,5-2.21A6.58,6.58,0,0,1,288.53,92.72Zm.88,5.74a6.46,6.46,0,0,0-.69-2.55,3.53,3.53,0,0,0-3.35-1.78,3.72,3.72,0,0,0-2.82,1.22,4.63,4.63,0,0,0-1.2,3.11Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M295.06,92.31h2.34v2.08a6.63,6.63,0,0,1,2.2-1.85,5.91,5.91,0,0,1,2.58-.56c2.08,0,3.49.73,4.21,2.18a7.57,7.57,0,0,1,.61,3.4V107h-2.51V97.73a5,5,0,0,0-.39-2.16,2.41,2.41,0,0,0-2.38-1.37,4.86,4.86,0,0,0-1.44.18,3.7,3.7,0,0,0-1.77,1.2,3.55,3.55,0,0,0-.8,1.5,9.58,9.58,0,0,0-.19,2.21V107h-2.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M311.13,88.22h2.48v4.09H316v2h-2.34v9.56a1,1,0,0,0,.52,1,2.21,2.21,0,0,0,1,.15h.38l.48,0v2a4.16,4.16,0,0,1-.88.18,7.74,7.74,0,0,1-1,.06,2.69,2.69,0,0,1-2.34-.88,3.94,3.94,0,0,1-.61-2.29v-9.7h-2v-2h2Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M340.63,86.87v2.39h-6.77V107h-2.75V89.26h-6.76V86.87Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M350.31,93.77a7.42,7.42,0,0,1,1.94,5.55,9.57,9.57,0,0,1-1.71,5.85,6.19,6.19,0,0,1-5.31,2.3,6,6,0,0,1-4.76-2A8.08,8.08,0,0,1,338.7,100a8.78,8.78,0,0,1,1.86-5.88,6.25,6.25,0,0,1,5-2.18A6.6,6.6,0,0,1,350.31,93.77Zm-1.53,9.74a9.32,9.32,0,0,0,.9-4.12,7.39,7.39,0,0,0-.65-3.33,3.63,3.63,0,0,0-3.54-2,3.49,3.49,0,0,0-3.25,1.72,8.07,8.07,0,0,0-1,4.15,7.05,7.05,0,0,0,1,3.89,3.56,3.56,0,0,0,3.22,1.56A3.35,3.35,0,0,0,348.78,103.51Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M365.88,93.77a7.42,7.42,0,0,1,1.94,5.55,9.57,9.57,0,0,1-1.71,5.85,6.19,6.19,0,0,1-5.31,2.3,6,6,0,0,1-4.76-2,8.08,8.08,0,0,1-1.77-5.48,8.78,8.78,0,0,1,1.86-5.88,6.25,6.25,0,0,1,5-2.18A6.58,6.58,0,0,1,365.88,93.77Zm-1.53,9.74a9.32,9.32,0,0,0,.9-4.12,7.26,7.26,0,0,0-.65-3.33,3.63,3.63,0,0,0-3.54-2,3.46,3.46,0,0,0-3.24,1.72,8,8,0,0,0-1,4.15,7,7,0,0,0,1,3.89,3.54,3.54,0,0,0,3.21,1.56A3.35,3.35,0,0,0,364.35,103.51Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M370.91,86.87h2.46V107h-2.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M378.53,102.36a3.47,3.47,0,0,0,.63,1.89,4,4,0,0,0,3.29,1.19,4.86,4.86,0,0,0,2.45-.6A2,2,0,0,0,386,103a1.56,1.56,0,0,0-.84-1.43,10.63,10.63,0,0,0-2.14-.7l-2-.49a10,10,0,0,1-2.81-1,3.11,3.11,0,0,1-1.61-2.76,4.21,4.21,0,0,1,1.52-3.37,6.13,6.13,0,0,1,4.08-1.28q3.36,0,4.83,1.94a4.24,4.24,0,0,1,.91,2.65h-2.33A2.72,2.72,0,0,0,385,95a3.92,3.92,0,0,0-3-1,3.7,3.7,0,0,0-2.16.53,1.65,1.65,0,0,0-.74,1.4,1.73,1.73,0,0,0,1,1.53,5.69,5.69,0,0,0,1.64.6l1.66.4A12.73,12.73,0,0,1,387,99.75a3.3,3.3,0,0,1,1.44,3,4.48,4.48,0,0,1-1.5,3.37,6.45,6.45,0,0,1-4.58,1.43c-2.2,0-3.77-.5-4.68-1.49a5.59,5.59,0,0,1-1.48-3.67Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M400,87.84c.58-.84,1.68-1.26,3.32-1.26l.48,0,.56,0v2.24l-.56,0h-.32c-.76,0-1.21.19-1.36.58a11.75,11.75,0,0,0-.22,3h2.46v1.94h-2.46V107h-2.43V94.32h-2V92.38h2v-2.3A4.43,4.43,0,0,1,400,87.84Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M417.23,93.77a7.38,7.38,0,0,1,1.94,5.55,9.57,9.57,0,0,1-1.71,5.85,6.18,6.18,0,0,1-5.3,2.3,6,6,0,0,1-4.77-2,8.07,8.07,0,0,1-1.76-5.48,8.83,8.83,0,0,1,1.85-5.88,6.25,6.25,0,0,1,5-2.18A6.58,6.58,0,0,1,417.23,93.77Zm-1.53,9.74a9.32,9.32,0,0,0,.9-4.12,7.26,7.26,0,0,0-.65-3.33,3.63,3.63,0,0,0-3.54-2,3.47,3.47,0,0,0-3.24,1.72,8,8,0,0,0-1,4.15,7,7,0,0,0,1,3.89,3.55,3.55,0,0,0,3.22,1.56A3.35,3.35,0,0,0,415.7,103.51Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M422.26,92.31h2.34v2.53A5.61,5.61,0,0,1,426,93,3.68,3.68,0,0,1,428.59,92l.24,0,.56,0v2.6a2.08,2.08,0,0,0-.41-.05l-.4,0a3.52,3.52,0,0,0-2.86,1.2,4.2,4.2,0,0,0-1,2.75V107h-2.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M439.89,86.87h9a6.09,6.09,0,0,1,4.31,1.51,5.5,5.5,0,0,1,1.64,4.25,6.15,6.15,0,0,1-1.47,4.09,5.5,5.5,0,0,1-4.47,1.74h-6.27V107h-2.72Zm10.55,2.76a5.92,5.92,0,0,0-2.46-.42h-5.37v7H448a5.07,5.07,0,0,0,2.95-.78,3.1,3.1,0,0,0,1.14-2.75A3,3,0,0,0,450.44,89.63Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M468.58,93.77a7.38,7.38,0,0,1,1.95,5.55,9.51,9.51,0,0,1-1.72,5.85,6.17,6.17,0,0,1-5.3,2.3,6,6,0,0,1-4.77-2A8.07,8.07,0,0,1,457,100a8.78,8.78,0,0,1,1.86-5.88,6.23,6.23,0,0,1,5-2.18A6.56,6.56,0,0,1,468.58,93.77Zm-1.52,9.74a9.32,9.32,0,0,0,.9-4.12,7.39,7.39,0,0,0-.65-3.33,3.65,3.65,0,0,0-3.55-2,3.48,3.48,0,0,0-3.24,1.72,8,8,0,0,0-1,4.15,7,7,0,0,0,1,3.89,3.56,3.56,0,0,0,3.22,1.56A3.36,3.36,0,0,0,467.06,103.51Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M475,102.36a3.47,3.47,0,0,0,.63,1.89,4,4,0,0,0,3.29,1.19,4.93,4.93,0,0,0,2.46-.6,2,2,0,0,0,1.06-1.84,1.55,1.55,0,0,0-.85-1.43,10.4,10.4,0,0,0-2.14-.7l-2-.49a9.78,9.78,0,0,1-2.8-1,3.1,3.1,0,0,1-1.62-2.76,4.21,4.21,0,0,1,1.52-3.37,6.13,6.13,0,0,1,4.08-1.28q3.36,0,4.84,1.94a4.17,4.17,0,0,1,.9,2.65h-2.33a2.72,2.72,0,0,0-.6-1.51,3.92,3.92,0,0,0-3-1,3.7,3.7,0,0,0-2.16.53,1.64,1.64,0,0,0-.73,1.4,1.72,1.72,0,0,0,1,1.53,5.66,5.66,0,0,0,1.65.6l1.65.4a12.83,12.83,0,0,1,3.63,1.24,3.31,3.31,0,0,1,1.43,3,4.48,4.48,0,0,1-1.5,3.37,6.45,6.45,0,0,1-4.58,1.43q-3.3,0-4.68-1.49a5.59,5.59,0,0,1-1.48-3.67Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M488,88.22h2.49v4.09h2.34v2h-2.34v9.56a1,1,0,0,0,.52,1,2.19,2.19,0,0,0,.95.15h.39l.48,0v2a4.39,4.39,0,0,1-.89.18,7.52,7.52,0,0,1-1,.06,2.69,2.69,0,0,1-2.34-.88A3.94,3.94,0,0,1,488,104v-9.7h-2v-2h2Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M503.47,92.9a6.78,6.78,0,0,1,1.41,1.39V92.45h2.27v13.32a10,10,0,0,1-.81,4.4c-1,2-2.94,3-5.77,3a7.09,7.09,0,0,1-4-1.06,4.1,4.1,0,0,1-1.8-3.32h2.5a2.74,2.74,0,0,0,.71,1.52,3.57,3.57,0,0,0,2.61.82c1.87,0,3.1-.66,3.68-2a11.37,11.37,0,0,0,.48-4.2,4.84,4.84,0,0,1-1.77,1.67,6,6,0,0,1-2.74.54,5.83,5.83,0,0,1-4.15-1.69q-1.77-1.68-1.77-5.58a8.43,8.43,0,0,1,1.79-5.74,5.51,5.51,0,0,1,4.32-2.07A5.38,5.38,0,0,1,503.47,92.9Zm.3,2.64a3.56,3.56,0,0,0-2.85-1.31,3.5,3.5,0,0,0-3.53,2.43,9.48,9.48,0,0,0-.51,3.4,6.12,6.12,0,0,0,1,3.77,3.24,3.24,0,0,0,2.69,1.29,3.75,3.75,0,0,0,3.71-2.39,7.71,7.71,0,0,0,.6-3.16A6.14,6.14,0,0,0,503.77,95.54Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M511,92.31h2.33v2.53a5.91,5.91,0,0,1,1.41-1.8A3.69,3.69,0,0,1,517.3,92l.23,0,.56,0v2.6a2.08,2.08,0,0,0-.4-.05l-.41,0a3.48,3.48,0,0,0-2.85,1.2,4.14,4.14,0,0,0-1,2.75V107H511Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M529.27,92.72a5.44,5.44,0,0,1,2.21,1.89,6.52,6.52,0,0,1,1,2.58,16.6,16.6,0,0,1,.22,3.23H522a6.34,6.34,0,0,0,1,3.59,3.49,3.49,0,0,0,3,1.35,3.9,3.9,0,0,0,3-1.28,4.37,4.37,0,0,0,.9-1.72h2.42a5,5,0,0,1-.63,1.8,6.34,6.34,0,0,1-1.21,1.62,5.71,5.71,0,0,1-2.75,1.48,8.65,8.65,0,0,1-2,.21,6.11,6.11,0,0,1-4.6-2,7.79,7.79,0,0,1-1.89-5.58,8.41,8.41,0,0,1,1.9-5.72,6.26,6.26,0,0,1,5-2.21A6.59,6.59,0,0,1,529.27,92.72Zm.88,5.74a6.46,6.46,0,0,0-.69-2.55,3.54,3.54,0,0,0-3.35-1.78,3.72,3.72,0,0,0-2.82,1.22,4.69,4.69,0,0,0-1.21,3.11Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M537.9,100.47a5.6,5.6,0,0,0,.78,2.78q1.3,2,4.59,2a7.9,7.9,0,0,0,2.69-.44,3.09,3.09,0,0,0,2.34-3,2.64,2.64,0,0,0-1-2.33,9.55,9.55,0,0,0-3.15-1.19l-2.64-.62a11.41,11.41,0,0,1-3.65-1.33A4.23,4.23,0,0,1,536,92.54a5.86,5.86,0,0,1,1.83-4.44A7.16,7.16,0,0,1,543,86.37a8.75,8.75,0,0,1,5.22,1.52,5.57,5.57,0,0,1,2.15,4.87h-2.56a5.12,5.12,0,0,0-.84-2.47c-.79-1.05-2.14-1.57-4.05-1.57a4.51,4.51,0,0,0-3.31,1,3.2,3.2,0,0,0-1,2.35,2.33,2.33,0,0,0,1.19,2.16,16.76,16.76,0,0,0,3.54,1.09l2.73.65a8.15,8.15,0,0,1,3,1.27,4.81,4.81,0,0,1,1.86,4.09,5.14,5.14,0,0,1-2.37,4.77,10.46,10.46,0,0,1-5.5,1.43,8.07,8.07,0,0,1-5.72-1.91,6.57,6.57,0,0,1-2-5.16Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M573.17,106.9l-1.36,1.65-3.11-2.36a11.33,11.33,0,0,1-2.43,1,10.29,10.29,0,0,1-2.85.37,9.18,9.18,0,0,1-7.32-3.06A11.71,11.71,0,0,1,553.76,97a11.9,11.9,0,0,1,2-7,8.78,8.78,0,0,1,7.69-3.72c3.54,0,6.17,1.14,7.87,3.42a11.08,11.08,0,0,1,2,6.82,14.28,14.28,0,0,1-.48,3.73,9.67,9.67,0,0,1-2.44,4.46ZM565.35,105a3.36,3.36,0,0,0,1.29-.47l-2.22-1.72,1.37-1.68,2.62,2A7.5,7.5,0,0,0,570.1,100a13.76,13.76,0,0,0,.45-3.39,8.48,8.48,0,0,0-1.85-5.7,6.35,6.35,0,0,0-5.07-2.17,6.6,6.6,0,0,0-5.15,2.08q-1.9,2.07-1.9,6.38A8.64,8.64,0,0,0,558.4,103a6.63,6.63,0,0,0,5.36,2.15A11.24,11.24,0,0,0,565.35,105Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-8 app-tagline"
|
||||
d="M576.58,86.87h2.72v17.69h10.08V107h-12.8Z"
|
||||
/>
|
||||
<line
|
||||
className="cls-9 app-name-underline"
|
||||
x1="219.17"
|
||||
y1="66.5"
|
||||
x2="384.17"
|
||||
y2="66.5"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>);
|
||||
|
||||
|
||||
}
|
||||
249
web/pgadmin/dashboard/static/js/WelcomeDashboard.jsx
Normal file
249
web/pgadmin/dashboard/static/js/WelcomeDashboard.jsx
Normal file
@@ -0,0 +1,249 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import React from 'react';
|
||||
import gettext from 'sources/gettext';
|
||||
import _ from 'lodash';
|
||||
import { Link, BrowserRouter } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import PgAdminLogo from './PgAdminLogo';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
emptyPanel: {
|
||||
background: theme.palette.grey[400],
|
||||
overflow: 'hidden',
|
||||
padding: '8px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexGrow: 1,
|
||||
height: '100%'
|
||||
|
||||
},
|
||||
dashboardContainer: {
|
||||
paddingBottom: '8px',
|
||||
minHeight: '100%'
|
||||
},
|
||||
card: {
|
||||
position: 'relative',
|
||||
minWidth: 0,
|
||||
wordWrap: 'break-word',
|
||||
backgroundColor: theme.otherVars.tableBg,
|
||||
backgroundClip: 'border-box',
|
||||
border: '1px solid' + theme.otherVars.borderColor,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
marginTop: 8
|
||||
},
|
||||
row: {
|
||||
marginRight: '-8px',
|
||||
marginLeft: '-8px'
|
||||
},
|
||||
rowContent: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
marginRight: '-7.5px',
|
||||
marginLeft: '-7.5px'
|
||||
},
|
||||
cardHeader: {
|
||||
padding: '0.25rem 0.5rem',
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: theme.otherVars.tableBg,
|
||||
borderBottom: '1px solid',
|
||||
borderBottomColor: theme.otherVars.borderColor,
|
||||
},
|
||||
dashboardLink: {
|
||||
color: theme.otherVars.colorFg + '!important',
|
||||
flex: '0 0 50%',
|
||||
maxWidth: '50%',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer'
|
||||
},
|
||||
gettingStartedLink: {
|
||||
flex: '0 0 25%',
|
||||
maxWidth: '50%',
|
||||
textAlign: 'center',
|
||||
cursor: 'pointer'
|
||||
},
|
||||
link: {
|
||||
color: theme.otherVars.colorFg + '!important',
|
||||
},
|
||||
cardColumn: {
|
||||
flex: '0 0 100%',
|
||||
maxWidth: '100%',
|
||||
margin: '8px'
|
||||
},
|
||||
cardBody: {
|
||||
flex: '1 1 auto',
|
||||
minHeight: '1px',
|
||||
padding: '0.5rem !important',
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
function AddNewServer(pgBrowser) {
|
||||
if (pgBrowser && pgBrowser.tree) {
|
||||
var i = _.isUndefined(pgBrowser.tree.selected()) ?
|
||||
pgBrowser.tree.first(null, false) :
|
||||
pgBrowser.tree.selected(),
|
||||
serverModule = pgAdmin.Browser.Nodes.server,
|
||||
itemData = pgBrowser.tree.itemData(i);
|
||||
|
||||
while (itemData && itemData._type != 'server_group') {
|
||||
i = pgBrowser.tree.next(i);
|
||||
itemData = pgBrowser.tree.itemData(i);
|
||||
}
|
||||
|
||||
if (!itemData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverModule) {
|
||||
serverModule.callbacks.show_obj_properties.apply(
|
||||
serverModule, [{
|
||||
action: 'create',
|
||||
}, i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function WelcomeDashboard({ pgBrowser }) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className={classes.emptyPanel}>
|
||||
<div className={classes.dashboardContainer}>
|
||||
<div className={classes.row}>
|
||||
<div className={classes.cardColumn}>
|
||||
<div className={classes.card}>
|
||||
<div className={classes.cardHeader}>{gettext('Welcome')}</div>
|
||||
<div className={classes.cardBody}>
|
||||
<PgAdminLogo />
|
||||
<h4>
|
||||
{gettext('Feature rich')} | {gettext('Maximises PostgreSQL')}{' '}
|
||||
| {gettext('Open Source')}{' '}
|
||||
</h4>
|
||||
<p>
|
||||
{gettext(
|
||||
'pgAdmin is an Open Source administration and management tool for the PostgreSQL database. It includes a graphical administration interface, an SQL query tool, a procedural code debugger and much more. The tool is designed to answer the needs of developers, DBAs and system administrators alike.'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.row}>
|
||||
<div className={classes.cardColumn}>
|
||||
<div className={classes.card}>
|
||||
<div className={classes.cardHeader}>{gettext('Quick Links')}</div>
|
||||
<div className={classes.cardBody}>
|
||||
<div className={classes.rowContent}>
|
||||
<div className={classes.dashboardLink}>
|
||||
<Link to="#" onClick={() => { AddNewServer(pgBrowser); }} className={classes.link}>
|
||||
<span
|
||||
className="fa fa-4x dashboard-icon fa-server"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('Add New Server')}
|
||||
</Link>
|
||||
</div>
|
||||
<div className={classes.dashboardLink}>
|
||||
<Link to="#" onClick={() => pgAdmin.Preferences.show()} className={classes.link}>
|
||||
<span
|
||||
id="mnu_preferences"
|
||||
className="fa fa-4x dashboard-icon fa-cogs"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('Configure pgAdmin')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.row}>
|
||||
<div className={classes.cardColumn}>
|
||||
<div className={classes.card}>
|
||||
<div className={classes.cardHeader}>{gettext('Getting Started')}</div>
|
||||
<div className={classes.cardBody}>
|
||||
<div className={classes.rowContent}>
|
||||
<div className={classes.gettingStartedLink}>
|
||||
<a
|
||||
href="http://www.postgresql.org/docs"
|
||||
target="postgres_help"
|
||||
className={classes.link}
|
||||
>
|
||||
<span
|
||||
className="fa fa-4x dashboard-icon dashboard-pg-doc"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('PostgreSQL Documentation')}
|
||||
</a>
|
||||
</div>
|
||||
<div className={classes.gettingStartedLink}>
|
||||
<a href="https://www.pgadmin.org" target="pgadmin_website" className={classes.link}>
|
||||
<span
|
||||
className="fa fa-4x dashboard-icon fa-globe"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('pgAdmin Website')}
|
||||
</a>
|
||||
</div>
|
||||
<div className={classes.gettingStartedLink}>
|
||||
<a
|
||||
href="http://planet.postgresql.org"
|
||||
target="planet_website"
|
||||
className={classes.link}
|
||||
>
|
||||
<span
|
||||
className="fa fa-4x dashboard-icon fa-book"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('Planet PostgreSQL')}
|
||||
</a>
|
||||
</div>
|
||||
<div className={classes.gettingStartedLink}>
|
||||
<a
|
||||
href="http://www.postgresql.org/community"
|
||||
target="postgres_website"
|
||||
className={classes.link}
|
||||
>
|
||||
<span
|
||||
className="fa fa-4x dashboard-icon fa-users"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<br />
|
||||
{gettext('Community Support')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
WelcomeDashboard.propTypes = {
|
||||
pgBrowser: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,74 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2022, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export function ChartContainer(props) {
|
||||
return (
|
||||
<div className="card dashboard-graph" role="object-document" tabIndex="0" aria-labelledby={props.id}>
|
||||
<div className="card-header">
|
||||
<div className="d-flex">
|
||||
<div id={props.id}>{props.title}</div>
|
||||
<div className="ml-auto my-auto legend" ref={props.legendRef}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body dashboard-graph-body">
|
||||
<div className={'chart-wrapper ' + (props.errorMsg ? 'd-none': '')}>
|
||||
{props.children}
|
||||
</div>
|
||||
<ChartError message={props.errorMsg} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChartContainer.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
legendRef: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.shape({ current: PropTypes.any }),
|
||||
]).isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
errorMsg: PropTypes.string,
|
||||
};
|
||||
|
||||
export function ChartError(props) {
|
||||
if(props.message === null) {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<div className="pg-panel-error pg-panel-message" role="alert">{props.message}</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChartError.propTypes = {
|
||||
message: PropTypes.string,
|
||||
};
|
||||
|
||||
export function DashboardRow({children}) {
|
||||
return (
|
||||
<div className="row dashboard-row">{children}</div>
|
||||
);
|
||||
}
|
||||
DashboardRow.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export function DashboardRowCol({breakpoint, parts, children}) {
|
||||
return (
|
||||
<div className={`col-${breakpoint}-${parts}`}>{children}</div>
|
||||
);
|
||||
}
|
||||
|
||||
DashboardRowCol.propTypes = {
|
||||
breakpoint: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']).isRequired,
|
||||
parts: PropTypes.number.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
Reference in New Issue
Block a user