mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
- Update MUI v4 to v5
- Remove the SCSS dependency completely and use MUI for theming. - Update - date-fns, @date-io, notistack. Remove - popper.js, sass-loader. - Cleanup webpack config. - Port PSQL tool to use MUI themes instead of SCSS theme. - Theme change will reflect realtime without refreshing pgAdmin.
This commit is contained in:
@@ -11,11 +11,11 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
import DeleteSweepIcon from '@material-ui/icons/DeleteSweep';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import BugReportRoundedIcon from '@material-ui/icons/BugReportRounded';
|
||||
import CloseSharpIcon from '@material-ui/icons/CloseSharp';
|
||||
import DeleteSweepIcon from '@mui/icons-material/DeleteSweep';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import BugReportRoundedIcon from '@mui/icons-material/BugReportRounded';
|
||||
import CloseSharpIcon from '@mui/icons-material/CloseSharp';
|
||||
|
||||
import url_for from 'sources/url_for';
|
||||
import gettext from 'sources/gettext';
|
||||
@@ -883,4 +883,3 @@ DebuggerArgumentComponent.propTypes = {
|
||||
pgTreeInfo: PropTypes.object,
|
||||
pgData: PropTypes.object,
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
@@ -69,7 +69,7 @@ export default function DebuggerEditor({ getEditor, params }) {
|
||||
self = this;
|
||||
getEditor(editor.current);
|
||||
}, [editor.current]);
|
||||
|
||||
|
||||
return (
|
||||
<CodeMirror
|
||||
currEditor={(obj) => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { DebuggerEventsContext } from './DebuggerComponent';
|
||||
import { DEBUGGER_EVENTS } from '../DebuggerConstants';
|
||||
|
||||
@@ -13,9 +13,9 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import TableContainer from '@material-ui/core/TableContainer';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import clsx from 'clsx';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Paper from '@mui/material/Paper';
|
||||
|
||||
import { DebuggerEventsContext } from './DebuggerComponent';
|
||||
import { DEBUGGER_EVENTS } from '../DebuggerConstants';
|
||||
|
||||
@@ -13,9 +13,9 @@ import gettext from 'sources/gettext';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import TableContainer from '@material-ui/core/TableContainer';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
import Paper from '@mui/material/Paper';
|
||||
|
||||
import { DebuggerEventsContext } from './DebuggerComponent';
|
||||
import { DEBUGGER_EVENTS } from '../DebuggerConstants';
|
||||
@@ -44,7 +44,7 @@ export function Stack() {
|
||||
const eventBus = React.useContext(DebuggerEventsContext);
|
||||
const [stackData, setStackData] = useState([]);
|
||||
const [disableFrameSelection, setDisableFrameSelection] = useState(false);
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
eventBus.registerListener(DEBUGGER_EVENTS.SET_STACK, (stackValues) => {
|
||||
setStackData(stackValues);
|
||||
|
||||
@@ -9,15 +9,16 @@
|
||||
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import FormatIndentIncreaseIcon from '@material-ui/icons/FormatIndentIncrease';
|
||||
import FormatIndentDecreaseIcon from '@material-ui/icons/FormatIndentDecrease';
|
||||
import PlayCircleFilledWhiteIcon from '@material-ui/icons/PlayCircleFilledWhite';
|
||||
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
||||
import NotInterestedIcon from '@material-ui/icons/NotInterested';
|
||||
import StopIcon from '@material-ui/icons/Stop';
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import RotateLeftRoundedIcon from '@material-ui/icons/RotateLeftRounded';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import FormatIndentIncreaseIcon from '@mui/icons-material/FormatIndentIncrease';
|
||||
import FormatIndentDecreaseIcon from '@mui/icons-material/FormatIndentDecrease';
|
||||
import PlayCircleFilledWhiteIcon from '@mui/icons-material/PlayCircleFilledWhite';
|
||||
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
|
||||
import NotInterestedIcon from '@mui/icons-material/NotInterested';
|
||||
import StopIcon from '@mui/icons-material/Stop';
|
||||
import HelpIcon from '@mui/icons-material/HelpRounded';
|
||||
import RotateLeftRoundedIcon from '@mui/icons-material/RotateLeftRounded';
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import { shortcut_key } from 'sources/keyboard_shortcuts';
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
/* To make font same as Query tool in messages tab */
|
||||
.messages {
|
||||
white-space: pre-wrap;
|
||||
font-family: $font-family-editor;
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
font-size: 0.925em;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.debugger-args {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -11,7 +11,8 @@ import React, { useMemo } from 'react';
|
||||
import gettext from 'sources/gettext';
|
||||
import PropTypes from 'prop-types';
|
||||
import { DefaultButton, PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import { Box, makeStyles, Tooltip, CircularProgress } from '@material-ui/core';
|
||||
import { Box, Tooltip, CircularProgress } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { ConnectedIcon, DisonnectedIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
|
||||
export const STATUS = {
|
||||
|
||||
@@ -26,7 +26,8 @@ import ERDDialogs from '../dialogs';
|
||||
import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent';
|
||||
import Loader from '../../../../../../static/js/components/Loader';
|
||||
import { MainToolBar } from './MainToolBar';
|
||||
import { Box, withStyles } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import EventBus from '../../../../../../static/js/helpers/EventBus';
|
||||
import { ERD_EVENTS } from '../ERDConstants';
|
||||
import getApiInstance, { callFetch, parseApiError } from '../../../../../../static/js/api_instance';
|
||||
|
||||
@@ -11,9 +11,10 @@ import React, { useEffect, useState, useMemo } from 'react';
|
||||
import gettext from 'sources/gettext';
|
||||
import PropTypes from 'prop-types';
|
||||
import CustomPropTypes from 'sources/custom_prop_types';
|
||||
import { Box, makeStyles, Popper } from '@material-ui/core';
|
||||
import { Box, Popper } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { DefaultButton } from '../../../../../../static/js/components/Buttons';
|
||||
import CheckIcon from '@material-ui/icons/Check';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
|
||||
|
||||
const useStyles = makeStyles((theme)=>({
|
||||
|
||||
@@ -7,27 +7,27 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box, useTheme } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import { PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import FolderRoundedIcon from '@material-ui/icons/FolderRounded';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import SaveRoundedIcon from '@material-ui/icons/SaveRounded';
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import ZoomInIcon from '@material-ui/icons/ZoomIn';
|
||||
import ZoomOutIcon from '@material-ui/icons/ZoomOut';
|
||||
import ZoomOutMapIcon from '@material-ui/icons/ZoomOutMap';
|
||||
import AddBoxIcon from '@material-ui/icons/AddBox';
|
||||
import EditRoundedIcon from '@material-ui/icons/EditRounded';
|
||||
import FileCopyRoundedIcon from '@material-ui/icons/FileCopyRounded';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import NoteRoundedIcon from '@material-ui/icons/NoteRounded';
|
||||
import VisibilityRoundedIcon from '@material-ui/icons/VisibilityRounded';
|
||||
import VisibilityOffRoundedIcon from '@material-ui/icons/VisibilityOffRounded';
|
||||
import ImageRoundedIcon from '@material-ui/icons/ImageRounded';
|
||||
import FormatColorFillRoundedIcon from '@material-ui/icons/FormatColorFillRounded';
|
||||
import FormatColorTextRoundedIcon from '@material-ui/icons/FormatColorTextRounded';
|
||||
import AccountTreeOutlinedIcon from '@material-ui/icons/AccountTreeOutlined';
|
||||
import FolderRoundedIcon from '@mui/icons-material/FolderRounded';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import SaveRoundedIcon from '@mui/icons-material/SaveRounded';
|
||||
import HelpIcon from '@mui/icons-material/HelpRounded';
|
||||
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
||||
import ZoomOutIcon from '@mui/icons-material/ZoomOut';
|
||||
import ZoomOutMapIcon from '@mui/icons-material/ZoomOutMap';
|
||||
import AddBoxIcon from '@mui/icons-material/AddBox';
|
||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import FileCopyRoundedIcon from '@mui/icons-material/FileCopyRounded';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import NoteRoundedIcon from '@mui/icons-material/NoteRounded';
|
||||
import VisibilityRoundedIcon from '@mui/icons-material/VisibilityRounded';
|
||||
import VisibilityOffRoundedIcon from '@mui/icons-material/VisibilityOffRounded';
|
||||
import ImageRoundedIcon from '@mui/icons-material/ImageRounded';
|
||||
import FormatColorFillRoundedIcon from '@mui/icons-material/FormatColorFillRounded';
|
||||
import FormatColorTextRoundedIcon from '@mui/icons-material/FormatColorTextRounded';
|
||||
import AccountTreeOutlinedIcon from '@mui/icons-material/AccountTreeOutlined';
|
||||
|
||||
import { PgMenu, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
import {Point} from '@projectstorm/geometry';
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import { ERDCanvasSettings } from '../components/ERDTool';
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ import UniqueKeyIcon from 'top/browser/server_groups/servers/databases/schemas/t
|
||||
import PropTypes from 'prop-types';
|
||||
import gettext from 'sources/gettext';
|
||||
import { PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import NoteRoundedIcon from '@material-ui/icons/NoteRounded';
|
||||
import VisibilityRoundedIcon from '@material-ui/icons/VisibilityRounded';
|
||||
import VisibilityOffRoundedIcon from '@material-ui/icons/VisibilityOffRounded';
|
||||
import { withStyles } from '@material-ui/styles';
|
||||
import NoteRoundedIcon from '@mui/icons-material/NoteRounded';
|
||||
import VisibilityRoundedIcon from '@mui/icons-material/VisibilityRounded';
|
||||
import VisibilityOffRoundedIcon from '@mui/icons-material/VisibilityOffRounded';
|
||||
import { withStyles } from '@mui/styles';
|
||||
import clsx from 'clsx';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
|
||||
|
||||
const TYPE = 'table';
|
||||
|
||||
@@ -11,8 +11,8 @@ import gettext from 'sources/gettext';
|
||||
import _ from 'lodash';
|
||||
import url_for from 'sources/url_for';
|
||||
import React from 'react';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Wizard from '../../../../static/js/helpers/wizard/Wizard';
|
||||
import WizardStep from '../../../../static/js/helpers/wizard/WizardStep';
|
||||
import PgTable from 'sources/components/PgTable';
|
||||
@@ -363,5 +363,3 @@ GrantWizard.propTypes = {
|
||||
nodeData: PropTypes.object,
|
||||
onClose: PropTypes.func
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/** Grant Wizard CSS **/
|
||||
|
||||
/**
|
||||
CSS to make db object type table
|
||||
fixed so that tbody content may
|
||||
scroll
|
||||
*/
|
||||
|
||||
.db_objects_container {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.db_objects_grid {
|
||||
height: calc(100% - 15px);
|
||||
}
|
||||
|
||||
.db_objects_filter {
|
||||
& .input-group-text {
|
||||
background: $input-bg;
|
||||
}
|
||||
|
||||
& .form-control {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
.object_type_table {
|
||||
height: calc(100% - 15px);
|
||||
display: block;
|
||||
padding: 0;
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
.object_type_table thead {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.object_type_table thead tr {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom: $panel-border;
|
||||
}
|
||||
|
||||
.object_type_table tbody {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
/* 100% minus thead height */
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.object_type_table tbody tr {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.object_type_table tbody tr td {
|
||||
background-position: 4px 4px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.object_type_table tbody tr td:nth-child(1),
|
||||
.object_type_table thead tr th:nth-child(1) {
|
||||
width: 28px;
|
||||
min-width: 28px;
|
||||
}
|
||||
|
||||
.object_type_table tbody tr td:nth-child(2) {
|
||||
width: 161px;
|
||||
min-width: 161px;
|
||||
max-width: 161px;
|
||||
}
|
||||
|
||||
.object_type_table thead tr th:nth-child(2) {
|
||||
width: 161px;
|
||||
min-width: 161px;
|
||||
max-width: 161px;
|
||||
}
|
||||
|
||||
.object_type_table tbody tr td:nth-child(3) {
|
||||
width: 109px;
|
||||
min-width: 109px;
|
||||
max-width: 109px;
|
||||
}
|
||||
|
||||
.object_type_table thead tr th:nth-child(3) {
|
||||
width: 109px;
|
||||
min-width: 109px;
|
||||
max-width: 109px;
|
||||
}
|
||||
|
||||
.object_type_table thead tr th:nth-child(4) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.object_type_table tbody tr td:nth-child(4) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/** Custom styling for Codemirror field **/
|
||||
.wizard-right-panel_content {
|
||||
border: 1px $color-gray-light;
|
||||
padding: 0.5rem 0rem;
|
||||
height: calc(100% - #{$footer-height-calc});
|
||||
}
|
||||
|
||||
.grant_wizard_container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#grantWizardDlg {
|
||||
padding-top: 0em;
|
||||
|
||||
}
|
||||
|
||||
.grant-wizard-objcol {
|
||||
min-width: 8em !important;
|
||||
width: 8em !important;
|
||||
}
|
||||
|
||||
.grant-wizard-panel-content {
|
||||
padding-top: 0.9em !important;
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import gettext from 'sources/gettext';
|
||||
import _ from 'lodash';
|
||||
import url_for from 'sources/url_for';
|
||||
import React from 'react';
|
||||
import { Box, Paper} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Box, Paper} from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import Wizard from '../../../../static/js/helpers/wizard/Wizard';
|
||||
import WizardStep from '../../../../static/js/helpers/wizard/WizardStep';
|
||||
import { FormFooterMessage, MESSAGE_TYPE, FormNote } from '../../../../static/js/components/FormComponents';
|
||||
|
||||
@@ -101,18 +101,21 @@ def panel(trans_id):
|
||||
|
||||
data = _get_database_role(params['sid'], params['did'])
|
||||
|
||||
params = {
|
||||
'sid': params['sid'],
|
||||
'db': underscore_escape(data['db_name']),
|
||||
'server_type': params['server_type'],
|
||||
'is_enable': config.ENABLE_PSQL,
|
||||
'title': underscore_unescape(params['title']),
|
||||
'theme': params['theme'],
|
||||
'o_db_name': underscore_escape(data['db_name']),
|
||||
'role': underscore_escape(data['role']),
|
||||
'platform': _platform
|
||||
}
|
||||
|
||||
set_env_variables(is_win=_platform == 'win32')
|
||||
return render_template('editor_template.html',
|
||||
sid=params['sid'],
|
||||
db=underscore_escape(data['db_name']),
|
||||
server_type=params['server_type'],
|
||||
is_enable=config.ENABLE_PSQL,
|
||||
title=underscore_unescape(params['title']),
|
||||
theme=params['theme'],
|
||||
o_db_name=underscore_escape(data['db_name']),
|
||||
role=underscore_escape(data['role']),
|
||||
platform=_platform
|
||||
)
|
||||
return render_template("psql/index.html",
|
||||
params=json.dumps(params))
|
||||
|
||||
|
||||
def set_env_variables(is_win=False):
|
||||
|
||||
202
web/pgadmin/tools/psql/static/js/PsqlModule.js
Normal file
202
web/pgadmin/tools/psql/static/js/PsqlModule.js
Normal file
@@ -0,0 +1,202 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import { getRandomInt, hasBinariesConfiguration } from 'sources/utils';
|
||||
import { retrieveAncestorOfTypeServer } from 'sources/tree/tree_utils';
|
||||
import { generateTitle } from 'tools/sqleditor/static/js/sqleditor_title';
|
||||
import { BROWSER_PANELS } from '../../../../browser/static/js/constants';
|
||||
import usePreferences,{ listenPreferenceBroadcast } from '../../../../preferences/static/js/store';
|
||||
import 'pgadmin.browser.keyboard';
|
||||
import pgWindow from 'sources/window';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import pgBrowser from 'pgadmin.browser';
|
||||
import PsqlComponent from './components/PsqlComponent';
|
||||
import { PgAdminContext } from '../../../../static/js/BrowserComponent';
|
||||
import getApiInstance from '../../../../static/js/api_instance';
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
import Theme from '../../../../static/js/Theme';
|
||||
import { NotifierProvider } from '../../../../static/js/helpers/Notifier';
|
||||
import ModalProvider from '../../../../static/js/helpers/ModalProvider';
|
||||
import * as csrfToken from 'sources/csrf';
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
|
||||
export default class Psql {
|
||||
static instance;
|
||||
|
||||
static getInstance(...args) {
|
||||
if (!Psql.instance) {
|
||||
Psql.instance = new Psql(...args);
|
||||
}
|
||||
return Psql.instance;
|
||||
}
|
||||
|
||||
constructor(pgAdmin, pgBrowser) {
|
||||
this.pgAdmin = pgAdmin;
|
||||
this.pgBrowser = pgBrowser;
|
||||
this.api = getApiInstance();
|
||||
}
|
||||
|
||||
/* Enable/disable PSQL tool menu in tools based
|
||||
* on node selected. if selected node is present
|
||||
* in unsupported_nodes, menu will be disabled
|
||||
* otherwise enabled.
|
||||
*/
|
||||
psqlToolEnabled(obj) {
|
||||
|
||||
let isEnabled = (() => {
|
||||
if (!_.isUndefined(obj) && !_.isNull(obj) && pgAdmin['enable_psql']) {
|
||||
if (_.indexOf(pgAdmin.unsupported_nodes, obj._type) == -1) {
|
||||
if (obj._type == 'database' && obj.allowConn) {
|
||||
return true;
|
||||
} else if (obj._type != 'database') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.initialized)
|
||||
return;
|
||||
this.initialized = true;
|
||||
csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
|
||||
// Define the nodes on which the menus to be appear
|
||||
|
||||
let menus = [{
|
||||
name: 'psql',
|
||||
module: this,
|
||||
applies: ['tools'],
|
||||
callback: 'openPsqlTool',
|
||||
enable: this.psqlToolEnabled,
|
||||
priority: 1,
|
||||
label: gettext('PSQL Tool'),
|
||||
data:{
|
||||
applies: 'tools',
|
||||
data_disabled: gettext('Please select a database from the object explorer to access Pql Tool.'),
|
||||
},
|
||||
}];
|
||||
|
||||
|
||||
this.enable_psql_tool = pgAdmin['enable_psql'];
|
||||
if(pgAdmin['enable_psql']) {
|
||||
pgBrowser.add_menus(menus);
|
||||
}
|
||||
}
|
||||
|
||||
openPsqlTool(data, treeIdentifier) {
|
||||
|
||||
const serverInformation = retrieveAncestorOfTypeServer(pgBrowser, treeIdentifier, gettext('PSQL Error'));
|
||||
if (!hasBinariesConfiguration(pgBrowser, serverInformation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = pgBrowser.tree.findNodeByDomElement(treeIdentifier);
|
||||
if (node === undefined || !node.getData()) {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('PSQL Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentData = pgBrowser.tree.getTreeNodeHierarchy(treeIdentifier);
|
||||
|
||||
if(_.isUndefined(parentData.server)) {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('PSQL Error'),
|
||||
gettext('Please select a server/database object.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const transId = getRandomInt(1, 9999999);
|
||||
|
||||
let panelTitle = '';
|
||||
// Set psql tab title as per prefrences setting.
|
||||
let title_data = {
|
||||
'database': parentData.database ? _.unescape(parentData.database.label) : 'postgres' ,
|
||||
'username': parentData.server.user.name,
|
||||
'server': parentData.server.label,
|
||||
'type': 'psql_tool',
|
||||
};
|
||||
let tab_title_placeholder = usePreferences.getState().getPreferencesForModule('browser').psql_tab_title_placeholder;
|
||||
panelTitle = generateTitle(tab_title_placeholder, title_data);
|
||||
|
||||
const [panelUrl, db_label] = this.getPanelUrls(transId, parentData);
|
||||
|
||||
const escapedTitle = _.escape(panelTitle);
|
||||
const open_new_tab = usePreferences.getState().getPreferencesForModule('browser').new_browser_tab_open;
|
||||
|
||||
pgAdmin.Browser.Events.trigger(
|
||||
'pgadmin:tool:show',
|
||||
`${BROWSER_PANELS.PSQL_TOOL}_${transId}`,
|
||||
panelUrl,
|
||||
{title: escapedTitle, db: db_label},
|
||||
{title: panelTitle, icon: 'fas fa-terminal psql-tab-style', manualClose: false, renamable: true},
|
||||
Boolean(open_new_tab?.includes('psql_tool'))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getPanelUrls(transId, pData) {
|
||||
let openUrl = url_for('psql.panel', {
|
||||
trans_id: transId,
|
||||
});
|
||||
const misc_preferences = usePreferences.getState().getPreferencesForModule('misc');
|
||||
let theme = misc_preferences.theme;
|
||||
|
||||
openUrl += `?sgid=${pData.server_group._id}`
|
||||
+`&sid=${pData.server._id}`
|
||||
+`&did=${pData.database._id}`
|
||||
+`&server_type=${pData.server.server_type}`
|
||||
+ `&theme=${theme}`;
|
||||
|
||||
if(pData.database?._id) {
|
||||
openUrl += `&db=${encodeURIComponent(pData.database._label)}`;
|
||||
} else {
|
||||
openUrl += `&db=${''}`;
|
||||
}
|
||||
|
||||
return [openUrl, pData.database._label];
|
||||
}
|
||||
|
||||
|
||||
async loadComponent(container, params) {
|
||||
pgAdmin.Browser.keyboardNavigation.init();
|
||||
await listenPreferenceBroadcast();
|
||||
ReactDOM.render(
|
||||
<Theme>
|
||||
<PgAdminContext.Provider value={pgAdmin}>
|
||||
<ModalProvider>
|
||||
<NotifierProvider pgAdmin={pgAdmin} pgWindow={pgWindow} />
|
||||
<PsqlComponent params={params} pgAdmin={pgAdmin} />
|
||||
</ModalProvider>
|
||||
</PgAdminContext.Provider>
|
||||
</Theme>,
|
||||
container
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
203
web/pgadmin/tools/psql/static/js/components/PsqlComponent.jsx
Normal file
203
web/pgadmin/tools/psql/static/js/components/PsqlComponent.jsx
Normal file
@@ -0,0 +1,203 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import url_for from 'sources/url_for';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Terminal } from 'xterm';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon } from 'xterm-addon-search';
|
||||
import { io } from 'socketio';
|
||||
import { copyToClipboard } from '../../../../../static/js/clipboard';
|
||||
import 'pgadmin.browser.keyboard';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
function psql_socket_io(socket, is_enable, sid, db, server_type, fitAddon, term, role){
|
||||
// Listen all the socket events emit from server.
|
||||
let init_psql = true;
|
||||
socket.on('pty-output', function(data){
|
||||
if(data.error) {
|
||||
term.write('\r\n');
|
||||
}
|
||||
term.write(data.result);
|
||||
if(data.error) {
|
||||
term.write('\r\n');
|
||||
}
|
||||
if (init_psql && data && role) {
|
||||
// setting role if available
|
||||
socket.emit('socket_set_role',{'role': _.unescape(role)});
|
||||
init_psql = false;
|
||||
}
|
||||
});
|
||||
// Connect socket
|
||||
socket.on('connect', () => {
|
||||
if(is_enable){
|
||||
socket.emit('start_process', {'sid': sid, 'db': db, 'stype': server_type });
|
||||
}
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('conn_error', (response) => {
|
||||
term.write(response.error);
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('conn_not_allow', () => {
|
||||
term.write('PSQL connection not allowed');
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('disconnect-psql', () => {
|
||||
socket.emit('server-disconnect', {'sid': sid});
|
||||
term.write('\r\nServer disconnected, Connection terminated, To create new connection please open another psql tool.');
|
||||
});
|
||||
}
|
||||
|
||||
function psql_terminal_io(term, socket, platform, pgAdmin) {
|
||||
// Listen key press event from terminal and emit socket event.
|
||||
term.attachCustomKeyEventHandler(e => {
|
||||
e.stopPropagation();
|
||||
if(e.type=='keydown' && (e.metaKey || e.ctrlKey) && (e.key == 'c' || e.key == 'C')) {
|
||||
let selected_text = term.getSelection();
|
||||
navigator.permissions.query({ name: 'clipboard-write' }).then(function(result) {
|
||||
if(result.state === 'granted' || result.state === 'prompt') {
|
||||
copyToClipboard(selected_text);
|
||||
} else {
|
||||
pgAdmin.Browser.notifier.alert(gettext('Clipboard write permission required'), gettext('To copy data from PSQL terminal, Clipboard write permission required.'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.pgAdmin.Browser.keyboardNavigation.triggerIframeEventsBroadcast(e,true);
|
||||
}
|
||||
|
||||
return !(e.ctrlKey && platform == 'win32');
|
||||
});
|
||||
|
||||
term.textarea.addEventListener('paste', function() {
|
||||
navigator.permissions.query({ name: 'clipboard-read' }).then(function(result) {
|
||||
if(result.state === 'granted' || result.state === 'prompt') {
|
||||
navigator.clipboard.readText().then( clipText => {
|
||||
let selected_text = clipText;
|
||||
if (selected_text.length > 0) {
|
||||
socket.emit('socket_input', {'input': selected_text, 'key_name': 'paste'});
|
||||
}
|
||||
});
|
||||
} else{
|
||||
pgAdmin.Browser.notifier.alert(gettext('Clipboard read permission required'), gettext('To paste data on the PSQL terminal, Clipboard read permission required.'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
term.onKey(function (ev) {
|
||||
socket.emit('socket_input', {'input': ev.key, 'key_name': ev.domEvent.code});
|
||||
});
|
||||
}
|
||||
|
||||
function psql_Addon(term) {
|
||||
const fitAddon = new FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
|
||||
const webLinksAddon = new WebLinksAddon();
|
||||
term.loadAddon(webLinksAddon);
|
||||
|
||||
const searchAddon = new SearchAddon();
|
||||
term.loadAddon(searchAddon);
|
||||
|
||||
fitAddon.fit();
|
||||
term.resize(15, 50);
|
||||
fitAddon.fit();
|
||||
return fitAddon;
|
||||
}
|
||||
|
||||
function psql_socket() {
|
||||
return io('/pty', {
|
||||
path: `${url_for('pgadmin.root')}/socket.io`,
|
||||
pingTimeout: 120000,
|
||||
pingInterval: 25000
|
||||
});
|
||||
}
|
||||
|
||||
export default function PsqlComponent({ params, pgAdmin }) {
|
||||
const theme = useTheme();
|
||||
const termRef = React.useRef(null);
|
||||
const containerRef = React.useRef(null);
|
||||
|
||||
const initializePsqlTool = (params)=>{
|
||||
const term = new Terminal({
|
||||
cursorBlink: true,
|
||||
scrollback: 5000,
|
||||
});
|
||||
/* Addon for fitAddon, webLinkAddon, SearchAddon */
|
||||
const fitAddon = psql_Addon(term);
|
||||
|
||||
term.open(containerRef.current);
|
||||
|
||||
/* Socket */
|
||||
const socket = psql_socket();
|
||||
|
||||
psql_socket_io(socket, params.is_enable, params.sid, params.db, params.server_type, fitAddon, term, params.role);
|
||||
|
||||
psql_terminal_io(term, socket, params.platform, pgAdmin);
|
||||
|
||||
/* Set terminal size */
|
||||
setTimeout(function(){
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
}, 1000);
|
||||
return [term, socket];
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
const [term, socket] = initializePsqlTool(params);
|
||||
termRef.current = term;
|
||||
|
||||
termRef.current?.setOption('theme', {
|
||||
background: '#ff0000'});
|
||||
|
||||
return () => {
|
||||
term.dispose();
|
||||
socket.disconnect();
|
||||
};
|
||||
|
||||
}, []);
|
||||
|
||||
useEffect(()=>{
|
||||
let psqlTheme = {
|
||||
background: theme.palette.background.default,
|
||||
foreground: theme.palette.text.primary,
|
||||
cursor: theme.palette.text.primary,
|
||||
cursorAccent: theme.palette.text.primary,
|
||||
selection: theme.palette.primary.main
|
||||
};
|
||||
termRef.current?.setOption('theme', psqlTheme );
|
||||
},[theme]);
|
||||
|
||||
|
||||
return (
|
||||
<Box width="100%" height="100%" display="flex" flexDirection="column" flexGrow="1" tabIndex="0" ref={containerRef}>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
PsqlComponent.propTypes = {
|
||||
params:PropTypes.shape({
|
||||
is_enable: PropTypes.Boolean,
|
||||
sid: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
db: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
server_type: PropTypes.string,
|
||||
role: PropTypes.string,
|
||||
platform: PropTypes.string
|
||||
}),
|
||||
pgAdmin: PropTypes.object.isRequired,
|
||||
};
|
||||
@@ -7,16 +7,17 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
import _ from 'lodash';
|
||||
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import pgBrowser from 'top/browser/static/js/browser';
|
||||
import * as csrfToken from 'sources/csrf';
|
||||
import {initialize} from './psql_module';
|
||||
import Psql from './PsqlModule';
|
||||
|
||||
let pgBrowserOut = initialize(gettext, url_for, _, pgAdmin, csrfToken, pgBrowser);
|
||||
|
||||
if(!pgAdmin.Tools) {
|
||||
pgAdmin.Tools = {};
|
||||
}
|
||||
pgAdmin.Tools.Psql = Psql.getInstance(pgAdmin, pgBrowser);
|
||||
|
||||
module.exports = {
|
||||
pgBrowser: pgBrowserOut,
|
||||
Psql: Psql
|
||||
};
|
||||
|
||||
@@ -1,342 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { Terminal } from 'xterm';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon } from 'xterm-addon-search';
|
||||
import { io } from 'socketio';
|
||||
import {getRandomInt, hasBinariesConfiguration} from 'sources/utils';
|
||||
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
|
||||
import pgWindow from 'sources/window';
|
||||
import { copyToClipboard } from '../../../../static/js/clipboard';
|
||||
import {generateTitle, refresh_db_node} from 'tools/sqleditor/static/js/sqleditor_title';
|
||||
import { BROWSER_PANELS } from '../../../../browser/static/js/constants';
|
||||
import usePreferences,{ listenPreferenceBroadcast } from '../../../../preferences/static/js/store';
|
||||
import 'pgadmin.browser.keyboard';
|
||||
export function setPanelTitle(psqlToolPanel, panelTitle) {
|
||||
psqlToolPanel.title('<span title="'+_.escape(panelTitle)+'">'+_.escape(panelTitle)+'</span>');
|
||||
}
|
||||
|
||||
export function initialize(gettext, url_for, _, pgAdmin, csrfToken, Browser) {
|
||||
let pgBrowser = Browser;
|
||||
let terminal = Terminal;
|
||||
let parentData = null;
|
||||
/* Return back, this has been called more than once */
|
||||
if (pgBrowser.psql)
|
||||
return pgBrowser.psql;
|
||||
|
||||
|
||||
// Create an Object Restore of pgBrowser class
|
||||
pgBrowser.psql = {
|
||||
init: function() {
|
||||
this.initialized = true;
|
||||
csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
|
||||
// Define the nodes on which the menus to be appear
|
||||
let menus = [{
|
||||
name: 'psql',
|
||||
module: this,
|
||||
applies: ['tools'],
|
||||
callback: 'psql_tool',
|
||||
priority: 1,
|
||||
label: gettext('PSQL Tool'),
|
||||
enable: this.psqlToolEnabled,
|
||||
}];
|
||||
|
||||
this.enable_psql_tool = pgAdmin['enable_psql'];
|
||||
if(pgAdmin['enable_psql']) {
|
||||
pgBrowser.add_menus(menus);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/* Enable/disable PSQL tool menu in tools based
|
||||
* on node selected. if selected node is present
|
||||
* in unsupported_nodes, menu will be disabled
|
||||
* otherwise enabled.
|
||||
*/
|
||||
psqlToolEnabled: function(obj) {
|
||||
|
||||
let isEnabled = (() => {
|
||||
if (!_.isUndefined(obj) && !_.isNull(obj) && pgAdmin['enable_psql']) {
|
||||
if (_.indexOf(pgAdmin.unsupported_nodes, obj._type) == -1) {
|
||||
if (obj._type == 'database' && obj.allowConn) {
|
||||
return true;
|
||||
} else if (obj._type != 'database') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
return isEnabled;
|
||||
},
|
||||
psql_tool: function(data, treeIdentifier) {
|
||||
const serverInformation = retrieveAncestorOfTypeServer(pgBrowser, treeIdentifier, gettext('PSQL Error'));
|
||||
if (!hasBinariesConfiguration(pgBrowser, serverInformation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = pgBrowser.tree.findNodeByDomElement(treeIdentifier);
|
||||
if (node === undefined || !node.getData()) {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('PSQL Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
parentData = pgBrowser.tree.getTreeNodeHierarchy(treeIdentifier);
|
||||
|
||||
if(_.isUndefined(parentData.server)) {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('PSQL Error'),
|
||||
gettext('Please select a server/database object.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const transId = getRandomInt(1, 9999999);
|
||||
|
||||
let panelTitle = '';
|
||||
// Set psql tab title as per prefrences setting.
|
||||
let title_data = {
|
||||
'database': parentData.database ? _.unescape(parentData.database.label) : 'postgres' ,
|
||||
'username': parentData.server.user.name,
|
||||
'server': parentData.server.label,
|
||||
'type': 'psql_tool',
|
||||
};
|
||||
let tab_title_placeholder = usePreferences.getState().getPreferencesForModule('browser').psql_tab_title_placeholder;
|
||||
panelTitle = generateTitle(tab_title_placeholder, title_data);
|
||||
|
||||
const [panelUrl, db_label] = this.getPanelUrls(transId, parentData);
|
||||
|
||||
const escapedTitle = _.escape(panelTitle);
|
||||
const open_new_tab = usePreferences.getState().getPreferencesForModule('browser').new_browser_tab_open;
|
||||
|
||||
pgAdmin.Browser.Events.trigger(
|
||||
'pgadmin:tool:show',
|
||||
`${BROWSER_PANELS.PSQL_TOOL}_${transId}`,
|
||||
panelUrl,
|
||||
{title: escapedTitle, db: db_label},
|
||||
{title: panelTitle, icon: 'fas fa-terminal psql-tab-style', manualClose: false, renamable: true},
|
||||
Boolean(open_new_tab?.includes('psql_tool'))
|
||||
);
|
||||
|
||||
return true;
|
||||
},
|
||||
getPanelUrls: function(transId, pData) {
|
||||
let openUrl = url_for('psql.panel', {
|
||||
trans_id: transId,
|
||||
});
|
||||
const misc_preferences = usePreferences.getState().getPreferencesForModule('misc');
|
||||
let theme = misc_preferences.theme;
|
||||
|
||||
openUrl += `?sgid=${pData.server_group._id}`
|
||||
+`&sid=${pData.server._id}`
|
||||
+`&did=${pData.database._id}`
|
||||
+`&server_type=${pData.server.server_type}`
|
||||
+ `&theme=${theme}`;
|
||||
|
||||
if(pData.database?._id) {
|
||||
openUrl += `&db=${encodeURIComponent(pData.database._label)}`;
|
||||
} else {
|
||||
openUrl += `&db=${''}`;
|
||||
}
|
||||
|
||||
return [openUrl, pData.database._label];
|
||||
},
|
||||
psql_terminal: function() {
|
||||
// theme colors
|
||||
return new terminal({
|
||||
cursorBlink: true,
|
||||
scrollback: 5000,
|
||||
});
|
||||
},
|
||||
psql_Addon: function(term) {
|
||||
const fitAddon = this.psql_fit_screen();
|
||||
term.loadAddon(fitAddon);
|
||||
|
||||
const webLinksAddon = this.psql_web_link();
|
||||
term.loadAddon(webLinksAddon);
|
||||
|
||||
const searchAddon = this.psql_search();
|
||||
term.loadAddon(searchAddon);
|
||||
|
||||
fitAddon.fit();
|
||||
term.resize(15, 50);
|
||||
fitAddon.fit();
|
||||
return fitAddon;
|
||||
},
|
||||
psql_fit_screen: function() {
|
||||
return new FitAddon();
|
||||
},
|
||||
psql_web_link: function() {
|
||||
return new WebLinksAddon();
|
||||
},
|
||||
psql_search: function() {
|
||||
return new SearchAddon();
|
||||
},
|
||||
psql_socket: function() {
|
||||
return io('/pty', {
|
||||
path: `${url_for('pgadmin.root')}/socket.io`,
|
||||
pingTimeout: 120000,
|
||||
pingInterval: 25000
|
||||
});
|
||||
},
|
||||
set_theme: function(term) {
|
||||
let theme = {
|
||||
background: getComputedStyle(document.documentElement).getPropertyValue('--psql-background'),
|
||||
foreground: getComputedStyle(document.documentElement).getPropertyValue('--psql-foreground'),
|
||||
cursor: getComputedStyle(document.documentElement).getPropertyValue('--psql-cursor'),
|
||||
cursorAccent: getComputedStyle(document.documentElement).getPropertyValue('--psql-cursorAccent'),
|
||||
selection: getComputedStyle(document.documentElement).getPropertyValue('--psql-selection'),
|
||||
};
|
||||
term.setOption('theme', theme);
|
||||
},
|
||||
psql_socket_io: function(socket, is_enable, sid, db, server_type, fitAddon, term, role) {
|
||||
// Listen all the socket events emit from server.
|
||||
let init_psql = true;
|
||||
socket.on('pty-output', function(data){
|
||||
if(data.error) {
|
||||
term.write('\r\n');
|
||||
}
|
||||
term.write(data.result);
|
||||
if(data.error) {
|
||||
term.write('\r\n');
|
||||
}
|
||||
if (init_psql && data && role !== 'None') {
|
||||
// setting role if available
|
||||
socket.emit('socket_set_role',{'role': _.unescape(role)});
|
||||
init_psql = false;
|
||||
}
|
||||
});
|
||||
// Connect socket
|
||||
socket.on('connect', () => {
|
||||
if(is_enable == 'True'){
|
||||
socket.emit('start_process', {'sid': sid, 'db': db, 'stype': server_type });
|
||||
}
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('conn_error', (response) => {
|
||||
term.write(response.error);
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('conn_not_allow', () => {
|
||||
term.write('PSQL connection not allowed');
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
});
|
||||
|
||||
socket.on('disconnect-psql', () => {
|
||||
socket.emit('server-disconnect', {'sid': sid});
|
||||
term.write('\r\nServer disconnected, Connection terminated, To create new connection please open another psql tool.');
|
||||
});
|
||||
},
|
||||
psql_terminal_io: function(term, socket, platform) {
|
||||
// Listen key press event from terminal and emit socket event.
|
||||
term.attachCustomKeyEventHandler(e => {
|
||||
e.stopPropagation();
|
||||
if(e.type=='keydown' && (e.metaKey || e.ctrlKey) && (e.key == 'c' || e.key == 'C')) {
|
||||
let selected_text = term.getSelection();
|
||||
navigator.permissions.query({ name: 'clipboard-write' }).then(function(result) {
|
||||
if(result.state === 'granted' || result.state === 'prompt') {
|
||||
copyToClipboard(selected_text);
|
||||
} else {
|
||||
pgAdmin.Browser.notifier.alert(gettext('Clipboard write permission required'), gettext('To copy data from PSQL terminal, Clipboard write permission required.'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.pgAdmin.Browser.keyboardNavigation.triggerIframeEventsBroadcast(e,true);
|
||||
}
|
||||
|
||||
return !(e.ctrlKey && platform == 'win32');
|
||||
});
|
||||
|
||||
term.textarea.addEventListener('paste', function() {
|
||||
navigator.permissions.query({ name: 'clipboard-read' }).then(function(result) {
|
||||
if(result.state === 'granted' || result.state === 'prompt') {
|
||||
navigator.clipboard.readText().then( clipText => {
|
||||
let selected_text = clipText;
|
||||
if (selected_text.length > 0) {
|
||||
socket.emit('socket_input', {'input': selected_text, 'key_name': 'paste'});
|
||||
}
|
||||
});
|
||||
} else{
|
||||
pgAdmin.Browser.notifier.alert(gettext('Clipboard read permission required'), gettext('To paste data on the PSQL terminal, Clipboard read permission required.'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
term.onKey(function (ev) {
|
||||
socket.emit('socket_input', {'input': ev.key, 'key_name': ev.domEvent.code});
|
||||
});
|
||||
},
|
||||
check_db_name_change: function(db_name, o_db_name) {
|
||||
if (db_name != o_db_name) {
|
||||
|
||||
let selected_item = pgWindow.pgAdmin.Browser.tree.selected(),
|
||||
tree_data = pgWindow.pgAdmin.Browser.tree.translateTreeNodeIdFromReactTree(selected_item),
|
||||
database_data = pgWindow.pgAdmin.Browser.tree.findNode(tree_data[3]),
|
||||
dbNode = database_data.domNode;
|
||||
|
||||
let message = `Current database has been moved or renamed to ${o_db_name}. Click on the OK button to refresh the database name, and reopen the psql again.`;
|
||||
refresh_db_node(message, dbNode);
|
||||
}
|
||||
},
|
||||
psql_mount: async function(params){
|
||||
self.pgAdmin.Browser.keyboardNavigation.init();
|
||||
await listenPreferenceBroadcast();
|
||||
const term = self.pgAdmin.Browser.psql.psql_terminal();
|
||||
/* Addon for fitAddon, webLinkAddon, SearchAddon */
|
||||
const fitAddon = self.pgAdmin.Browser.psql.psql_Addon(term);
|
||||
/* Update the theme for terminal as per pgAdmin 4 theme. */
|
||||
self.pgAdmin.Browser.psql.set_theme(term);
|
||||
/* Open the terminal */
|
||||
term.open(document.getElementById('psql-terminal'));
|
||||
/* Socket */
|
||||
const socket = self.pgAdmin.Browser.psql.psql_socket();
|
||||
self.pgAdmin.Browser.psql.psql_socket_io(socket, params.is_enable, params.sid, params.db, params.server_type, fitAddon, term, params.role);
|
||||
|
||||
self.pgAdmin.Browser.psql.psql_terminal_io(term, socket, params.platform);
|
||||
self.pgAdmin.Browser.psql.check_db_name_change(params.db, params.o_db_name);
|
||||
/* Set terminal size */
|
||||
setTimeout(function(){
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
}, 1000);
|
||||
|
||||
/* Resize the terminal */
|
||||
function fitToscreen(){
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', {'cols': term.cols, 'rows': term.rows});
|
||||
}
|
||||
|
||||
function debounce(func, wait_ms) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
const context = this;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(context, args), wait_ms);
|
||||
};
|
||||
}
|
||||
|
||||
window.onresize = debounce(fitToscreen, 25);
|
||||
}
|
||||
};
|
||||
|
||||
return pgBrowser.psql;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{title}}{% endblock %}
|
||||
|
||||
{% block css_link %}
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('browser.browser_css')}}"/>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<style>
|
||||
body {padding: 0px;}
|
||||
{% if is_desktop_mode and is_linux %}
|
||||
.sql-editor-busy-icon.fa-pulse{-webkit-animation: none;}
|
||||
{% endif %}
|
||||
</style>
|
||||
<div style="width: 100%; height: 100%;" id="psql-terminal" class="psql_terminal"></div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block init_script %}
|
||||
require(
|
||||
['sources/generated/psql_tool'],
|
||||
function(pgBrowser) {
|
||||
<!-- Call the PSQL mount-->
|
||||
self.pgAdmin.Browser.psql.psql_mount({
|
||||
"is_enable": '{{is_enable}}',
|
||||
"sid": '{{sid}}',
|
||||
"db":'{{db|safe}}',
|
||||
"server_type": '{{server_type}}',
|
||||
"role": '{{role|safe}}',
|
||||
"platform": '{{platform}}',
|
||||
"o_db_name": '{{o_db_name|safe}}'
|
||||
})
|
||||
|
||||
});
|
||||
{% endblock %}
|
||||
56
web/pgadmin/tools/psql/templates/psql/index.html
Normal file
56
web/pgadmin/tools/psql/templates/psql/index.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{title}}{% endblock %}
|
||||
|
||||
{% block css_link %}
|
||||
<style>
|
||||
#psql-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#psql-container:not(:empty) + .pg-sp-container {
|
||||
display: none;
|
||||
}
|
||||
{% if is_desktop_mode and is_linux %}
|
||||
.sql-editor-busy-icon.fa-pulse{-webkit-animation: none;}
|
||||
{% endif %}
|
||||
</style>
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('browser.browser_css')}}"/>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div id="psql-container" tabindex="0">
|
||||
<div class="pg-sp-container">
|
||||
<div class="pg-sp-content">
|
||||
<div class="row">
|
||||
<div class="col-12 pg-sp-icon"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block init_script %}
|
||||
try {
|
||||
require(
|
||||
['sources/generated/browser_nodes'],
|
||||
function() {
|
||||
require(['sources/generated/psql_tool'], function(module) {
|
||||
window.pgAdmin.Tools.Psql.loadComponent(
|
||||
document.getElementById('psql-container'),{{ params|safe }});
|
||||
}, function() {
|
||||
console.log(arguments);
|
||||
});
|
||||
},
|
||||
function() {
|
||||
console.log(arguments);
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
{% endblock %}
|
||||
@@ -10,8 +10,8 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import React, { useContext, useState } from 'react';
|
||||
|
||||
import { Box, Grid, Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box, Grid, Typography } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
|
||||
import { InputSelect } from '../../../../../static/js/components/FormComponents';
|
||||
import { SchemaDiffEventsContext } from './SchemaDiffComponent';
|
||||
|
||||
@@ -13,11 +13,11 @@ import clsx from 'clsx';
|
||||
import { SelectColumn } from 'react-data-grid';
|
||||
import React, { useContext, useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react';
|
||||
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import KeyboardArrowRightRoundedIcon from '@material-ui/icons/KeyboardArrowRightRounded';
|
||||
import KeyboardArrowDownRoundedIcon from '@material-ui/icons/KeyboardArrowDownRounded';
|
||||
import InfoIcon from '@material-ui/icons/InfoRounded';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded';
|
||||
import KeyboardArrowDownRoundedIcon from '@mui/icons-material/KeyboardArrowDownRounded';
|
||||
import InfoIcon from '@mui/icons-material/InfoRounded';
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
|
||||
@@ -10,8 +10,8 @@ import gettext from 'sources/gettext';
|
||||
|
||||
import React, { useContext, useState, useEffect } from 'react';
|
||||
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { InputSQL } from '../../../../../static/js/components/FormComponents';
|
||||
import { SchemaDiffEventsContext } from './SchemaDiffComponent';
|
||||
import { SCHEMA_DIFF_EVENT } from '../SchemaDiffConstants';
|
||||
@@ -84,7 +84,7 @@ export function Results() {
|
||||
<Box className={classes.label}>{gettext('Difference')}</Box>
|
||||
</Box>
|
||||
<Box className={classes.sqlContainer}>
|
||||
<Box className={classes.sqldata}>
|
||||
<Box className={classes.sqldata}>
|
||||
<Box className={classes.sqlInput}>
|
||||
<InputSQL
|
||||
onLable={true}
|
||||
@@ -135,4 +135,4 @@ export function Results() {
|
||||
|
||||
Results.propTypes = {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,11 +13,11 @@ import React, { useState, useRef, useContext, useEffect } from 'react';
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
import { Box } from '@material-ui/core';
|
||||
import CompareArrowsRoundedIcon from '@material-ui/icons/CompareArrowsRounded';
|
||||
import FeaturedPlayListRoundedIcon from '@material-ui/icons/FeaturedPlayListRounded';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import CompareArrowsRoundedIcon from '@mui/icons-material/CompareArrowsRounded';
|
||||
import FeaturedPlayListRoundedIcon from '@mui/icons-material/FeaturedPlayListRounded';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
|
||||
import { DefaultButton, PgButtonGroup, PgIconButton, PrimaryButton } from '../../../../../static/js/components/Buttons';
|
||||
import { FilterIcon } from '../../../../../static/js/components/ExternalIcon';
|
||||
@@ -169,7 +169,7 @@ export function SchemaDiffButtonComponent({ sourceData, targetData, selectedRowI
|
||||
<PgButtonGroup size="small" disabled={isDisableCompare}>
|
||||
<PrimaryButton startIcon={<CompareArrowsRoundedIcon />}
|
||||
onClick={compareDiff}>{gettext('Compare')}</PrimaryButton>
|
||||
<PgIconButton title={gettext('Compare')} icon={<KeyboardArrowDownIcon />} color={'primary'} splitButton
|
||||
<PgIconButton title={gettext('Compare')} disabled={isDisableCompare} icon={<KeyboardArrowDownIcon />} color={'primary'} splitButton
|
||||
name={MENUS.COMPARE} ref={compareRef} onClick={toggleMenu} ></PgIconButton>
|
||||
</PgButtonGroup>
|
||||
</Box>
|
||||
@@ -182,7 +182,7 @@ export function SchemaDiffButtonComponent({ sourceData, targetData, selectedRowI
|
||||
<PgButtonGroup size="small" disabled={isDisableCompare} style={{ paddingRight: '0.3rem' }}>
|
||||
<DefaultButton startIcon={<FilterIcon />} className={classes.noactionBtn}
|
||||
>{gettext('Filter')}</DefaultButton>
|
||||
<PgIconButton title={gettext('File')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
<PgIconButton title={gettext('Filter')} disabled={isDisableCompare} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
name={MENUS.FILTER} ref={filterRef} onClick={toggleMenu} ></PgIconButton>
|
||||
</PgButtonGroup>
|
||||
</Box>
|
||||
|
||||
@@ -11,10 +11,10 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { Box, Grid } from '@material-ui/core';
|
||||
import InfoRoundedIcon from '@material-ui/icons/InfoRounded';
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box, Grid } from '@mui/material';
|
||||
import InfoRoundedIcon from '@mui/icons-material/InfoRounded';
|
||||
import HelpIcon from '@mui/icons-material/HelpRounded';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
|
||||
@@ -14,7 +14,8 @@ import {DividerBox} from 'rc-dock';
|
||||
|
||||
import url_for from 'sources/url_for';
|
||||
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
|
||||
import { Results } from './Results';
|
||||
import { SchemaDiffCompare } from './SchemaDiffCompare';
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import SearchRoundedIcon from '@material-ui/icons/SearchRounded';
|
||||
import HelpIcon from '@mui/icons-material/HelpRounded';
|
||||
import SearchRoundedIcon from '@mui/icons-material/SearchRounded';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
|
||||
@@ -20,7 +20,7 @@ import getApiInstance, {callFetch, parseApiError} from '../../../../../static/js
|
||||
import url_for from 'sources/url_for';
|
||||
import { PANELS, QUERY_TOOL_EVENTS, CONNECTION_STATUS, MAX_QUERY_LENGTH } from './QueryToolConstants';
|
||||
import { useInterval } from '../../../../../static/js/custom_hooks';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { getDatabaseLabel, getTitle, setQueryToolDockerTitle } from '../sqleditor_title';
|
||||
import gettext from 'sources/gettext';
|
||||
import NewConnectionDialog from './dialogs/NewConnectionDialog';
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles, Box, Portal } from '@material-ui/core';
|
||||
import { Box, Portal } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React, {useContext, useLayoutEffect, useRef} from 'react';
|
||||
import { DefaultButton, PrimaryButton } from '../../../../../../static/js/components/Buttons';
|
||||
import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import gettext from 'sources/gettext';
|
||||
import clsx from 'clsx';
|
||||
import JSONBigNumber from 'json-bignumber';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import PropTypes from 'prop-types';
|
||||
import CustomPropTypes from '../../../../../../static/js/custom_prop_types';
|
||||
|
||||
|
||||
@@ -6,18 +6,19 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import _ from 'lodash';
|
||||
import React, {useState, useEffect, useContext, useRef, useLayoutEffect, useMemo} from 'react';
|
||||
import {Row, useRowSelection} from 'react-data-grid';
|
||||
import LockIcon from '@material-ui/icons/Lock';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import LockIcon from '@mui/icons-material/Lock';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import { QUERY_TOOL_EVENTS } from '../QueryToolConstants';
|
||||
import * as Editors from './Editors';
|
||||
import * as Formatters from './Formatters';
|
||||
import clsx from 'clsx';
|
||||
import { PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import MapIcon from '@material-ui/icons/Map';
|
||||
import MapIcon from '@mui/icons-material/Map';
|
||||
import { QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import PropTypes from 'prop-types';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { useModalStyles } from '../../../../../../static/js/helpers/ModalProvider';
|
||||
import gettext from 'sources/gettext';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { DefaultButton, PrimaryButton } from '../../../../../../static/js/components/Buttons';
|
||||
import CloseIcon from '@material-ui/icons/CloseRounded';
|
||||
import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
|
||||
import CloseIcon from '@mui/icons-material/CloseRounded';
|
||||
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
|
||||
import HTMLReactParser from 'html-react-parser';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useModalStyles } from '../../../../../../static/js/helpers/ModalProvider';
|
||||
import gettext from 'sources/gettext';
|
||||
import { Box, makeStyles } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { DefaultButton, PrimaryButton } from '../../../../../../static/js/components/Buttons';
|
||||
import CloseIcon from '@material-ui/icons/CloseRounded';
|
||||
import CloseIcon from '@mui/icons-material/CloseRounded';
|
||||
import HTMLReactParser from 'html-react-parser';
|
||||
import PropTypes from 'prop-types';
|
||||
import CheckRounded from '@material-ui/icons/CheckRounded';
|
||||
import CheckRounded from '@mui/icons-material/CheckRounded';
|
||||
import { InputCheckbox } from '../../../../../../static/js/components/FormComponents';
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { useModalStyles } from '../../../../../../static/js/helpers/ModalProvider';
|
||||
import gettext from 'sources/gettext';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { DefaultButton, PrimaryButton } from '../../../../../../static/js/components/Buttons';
|
||||
import CloseIcon from '@material-ui/icons/CloseRounded';
|
||||
import CloseIcon from '@mui/icons-material/CloseRounded';
|
||||
import HTMLReactParser from 'html-react-parser';
|
||||
import { CommitIcon, RollbackIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import SchemaView from '../../../../../../static/js/SchemaView';
|
||||
import BaseUISchema from '../../../../../../static/js/SchemaView/base_schema.ui';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import SchemaView from '../../../../../../static/js/SchemaView';
|
||||
import BaseUISchema from '../../../../../../static/js/SchemaView/base_schema.ui';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React, { useState } from 'react';
|
||||
import SchemaView from '../../../../../../static/js/SchemaView';
|
||||
import BaseUISchema from '../../../../../../static/js/SchemaView/base_schema.ui';
|
||||
|
||||
@@ -7,20 +7,20 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box, CircularProgress, Tooltip } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box, CircularProgress, Tooltip } from '@mui/material';
|
||||
import { DefaultButton, PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import { ConnectedIcon, DisonnectedIcon, QueryToolIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import { QueryToolContext } from '../QueryToolComponent';
|
||||
import { CONNECTION_STATUS, CONNECTION_STATUS_MESSAGE } from '../QueryToolConstants';
|
||||
import HourglassEmptyRoundedIcon from '@material-ui/icons/HourglassEmptyRounded';
|
||||
import QueryBuilderRoundedIcon from '@material-ui/icons/QueryBuilderRounded';
|
||||
import ErrorOutlineRoundedIcon from '@material-ui/icons/ErrorOutlineRounded';
|
||||
import ReportProblemRoundedIcon from '@material-ui/icons/ReportProblemRounded';
|
||||
import HourglassEmptyRoundedIcon from '@mui/icons-material/HourglassEmptyRounded';
|
||||
import QueryBuilderRoundedIcon from '@mui/icons-material/QueryBuilderRounded';
|
||||
import ErrorOutlineRoundedIcon from '@mui/icons-material/ErrorOutlineRounded';
|
||||
import ReportProblemRoundedIcon from '@mui/icons-material/ReportProblemRounded';
|
||||
import { PgMenu, PgMenuItem } from '../../../../../../static/js/components/Menu';
|
||||
import gettext from 'sources/gettext';
|
||||
import RotateLeftRoundedIcon from '@material-ui/icons/RotateLeftRounded';
|
||||
import RotateLeftRoundedIcon from '@mui/icons-material/RotateLeftRounded';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useKeyboardShortcuts } from '../../../../../../static/js/custom_hooks';
|
||||
import CustomPropTypes from '../../../../../../static/js/custom_prop_types';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import _ from 'lodash';
|
||||
import { MapContainer, TileLayer, LayersControl, GeoJSON, useMap } from 'react-leaflet';
|
||||
import Leaflet, { CRS } from 'leaflet';
|
||||
@@ -18,7 +18,7 @@ import gettext from 'sources/gettext';
|
||||
import Theme from 'sources/Theme';
|
||||
import clsx from 'clsx';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { PANELS } from '../QueryToolConstants';
|
||||
import { QueryToolContext } from '../QueryToolComponent';
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ import gettext from 'sources/gettext';
|
||||
import PropTypes from 'prop-types';
|
||||
import url_for from 'sources/url_for';
|
||||
import Loader from 'sources/components/Loader';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@material-ui/core';
|
||||
import ShowChartRoundedIcon from '@material-ui/icons/ShowChartRounded';
|
||||
import ZoomOutMapIcon from '@material-ui/icons/ZoomOutMap';
|
||||
import SaveAltIcon from '@material-ui/icons/SaveAlt';
|
||||
import ExpandLessRoundedIcon from '@material-ui/icons/ExpandLessRounded';
|
||||
import ExpandMoreRoundedIcon from '@material-ui/icons/ExpandMoreRounded';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import ShowChartRoundedIcon from '@mui/icons-material/ShowChartRounded';
|
||||
import ZoomOutMapIcon from '@mui/icons-material/ZoomOutMap';
|
||||
import SaveAltIcon from '@mui/icons-material/SaveAlt';
|
||||
import ExpandLessRoundedIcon from '@mui/icons-material/ExpandLessRounded';
|
||||
import ExpandMoreRoundedIcon from '@mui/icons-material/ExpandMoreRounded';
|
||||
import { InputSelect } from '../../../../../../static/js/components/FormComponents';
|
||||
import { DefaultButton, PgButtonGroup, PgIconButton} from '../../../../../../static/js/components/Buttons';
|
||||
import { LineChart, BarChart, PieChart, DATA_POINT_STYLE, DATA_POINT_SIZE,
|
||||
|
||||
@@ -7,20 +7,20 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, {useContext, useCallback, useEffect, useState} from 'react';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import { PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import FolderRoundedIcon from '@material-ui/icons/FolderRounded';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import SaveRoundedIcon from '@material-ui/icons/SaveRounded';
|
||||
import StopRoundedIcon from '@material-ui/icons/StopRounded';
|
||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import FolderRoundedIcon from '@mui/icons-material/FolderRounded';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import SaveRoundedIcon from '@mui/icons-material/SaveRounded';
|
||||
import StopRoundedIcon from '@mui/icons-material/StopRounded';
|
||||
import PlayArrowRoundedIcon from '@mui/icons-material/PlayArrowRounded';
|
||||
import { FilterIcon, CommitIcon, RollbackIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import EditRoundedIcon from '@material-ui/icons/EditRounded';
|
||||
import AssessmentRoundedIcon from '@material-ui/icons/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@material-ui/icons/ExplicitRounded';
|
||||
import FormatListNumberedRoundedIcon from '@material-ui/icons/FormatListNumberedRounded';
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import AssessmentRoundedIcon from '@mui/icons-material/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@mui/icons-material/ExplicitRounded';
|
||||
import FormatListNumberedRoundedIcon from '@mui/icons-material/FormatListNumberedRounded';
|
||||
import HelpIcon from '@mui/icons-material/HelpRounded';
|
||||
import {QUERY_TOOL_EVENTS, CONNECTION_STATUS} from '../QueryToolConstants';
|
||||
import { QueryToolConnectionContext, QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import { PgMenu, PgMenuDivider, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu';
|
||||
@@ -457,10 +457,10 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
disabled={!queryToolCtx.params.is_query_tool} accesskey={shortcut_key(queryToolPref.btn_edit_options)}
|
||||
name="menu-edit" ref={editMenuRef} onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small" color={highlightFilter ? 'primary' : 'default'}>
|
||||
<PgIconButton title={gettext('Sort/Filter')} icon={<FilterIcon />}
|
||||
<PgButtonGroup size="small" >
|
||||
<PgIconButton title={gettext('Sort/Filter')} color={highlightFilter ? 'primary' : 'default'} icon={<FilterIcon />}
|
||||
onClick={onFilterClick} disabled={buttonsDisabled['filter']} accesskey={shortcut_key(queryToolPref.btn_filter_dialog)}/>
|
||||
<PgIconButton title={gettext('Filter options')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
<PgIconButton title={gettext('Filter options')} color={highlightFilter ? 'primary' : 'default'} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
disabled={buttonsDisabled['filter']} name="menu-filter" ref={filterMenuRef} accesskey={shortcut_key(queryToolPref.btn_filter_options)}
|
||||
onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import { QUERY_TOOL_EVENTS } from '../QueryToolConstants';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React, {useContext, useCallback, useEffect, useMemo } from 'react';
|
||||
import { format } from 'sql-formatter';
|
||||
import { QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
@@ -258,6 +258,38 @@ export default function Query() {
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_QUERY_CHANGE, ()=>{
|
||||
change();
|
||||
});
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_FORMAT_SQL, ()=>{
|
||||
let selection = true, sql = editor.current?.getSelection();
|
||||
let sqlEditorPref = preferencesStore.getPreferencesForModule('sqleditor');
|
||||
/* New library does not support capitalize casing
|
||||
so if a user has set capitalize casing we will
|
||||
use preserve casing which is default for the library.
|
||||
*/
|
||||
let formatPrefs = {
|
||||
language: 'postgresql',
|
||||
keywordCase: sqlEditorPref.keyword_case === 'capitalize' ? 'preserve' : sqlEditorPref.keyword_case,
|
||||
identifierCase: sqlEditorPref.identifier_case === 'capitalize' ? 'preserve' : sqlEditorPref.identifier_case,
|
||||
dataTypeCase: sqlEditorPref.data_type_case,
|
||||
functionCase: sqlEditorPref.function_case,
|
||||
logicalOperatorNewline: sqlEditorPref.logical_operator_new_line,
|
||||
expressionWidth: sqlEditorPref.expression_width,
|
||||
linesBetweenQueries: sqlEditorPref.lines_between_queries,
|
||||
tabWidth: sqlEditorPref.tab_size,
|
||||
useTabs: !sqlEditorPref.use_spaces,
|
||||
denseOperators: !sqlEditorPref.spaces_around_operators,
|
||||
newlineBeforeSemicolon: sqlEditorPref.new_line_before_semicolon
|
||||
};
|
||||
if(sql == '') {
|
||||
sql = editor.current.getValue();
|
||||
selection = false;
|
||||
}
|
||||
let formattedSql = format(sql,formatPrefs);
|
||||
if(selection) {
|
||||
editor.current.replaceSelection(formattedSql, 'around');
|
||||
} else {
|
||||
editor.current.setValue(formattedSql);
|
||||
}
|
||||
});
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_TOGGLE_CASE, ()=>{
|
||||
let selectedText = editor.current?.getSelection();
|
||||
if (!selectedText) return;
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import React, { useContext } from 'react';
|
||||
import { PANELS, QUERY_TOOL_EVENTS, MAX_QUERY_LENGTH } from '../QueryToolConstants';
|
||||
import gettext from 'sources/gettext';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import _ from 'lodash';
|
||||
import clsx from 'clsx';
|
||||
import { Box, Grid, List, ListItem, ListSubheader } from '@material-ui/core';
|
||||
import { Box, Grid, List, ListItem, ListSubheader } from '@mui/material';
|
||||
import url_for from 'sources/url_for';
|
||||
import { QueryToolConnectionContext, QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import moment from 'moment';
|
||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import AssessmentRoundedIcon from '@material-ui/icons/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@material-ui/icons/ExplicitRounded';
|
||||
import PlayArrowRoundedIcon from '@mui/icons-material/PlayArrowRounded';
|
||||
import AssessmentRoundedIcon from '@mui/icons-material/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@mui/icons-material/ExplicitRounded';
|
||||
import { SaveDataIcon, CommitIcon, RollbackIcon, ViewDataIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import { InputSwitch } from '../../../../../../static/js/components/FormComponents';
|
||||
import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror';
|
||||
@@ -512,7 +512,7 @@ export function QueryHistory() {
|
||||
</Box>
|
||||
</Box>
|
||||
<Box flexGrow="1" overflow="auto" className={classes.listRoot}>
|
||||
<List innerRef={listRef} className={classes.root} subheader={<li />} tabIndex="0" onKeyDown={onKeyPressed}>
|
||||
<List ref={listRef} className={classes.root} subheader={<li />} tabIndex="0" onKeyDown={onKeyPressed}>
|
||||
{qhu.current.getGroups().map(([groupKey, groupHeader]) => (
|
||||
<ListItem key={`section-${groupKey}`} className={classes.removePadding}>
|
||||
<List className={classes.removePadding}>
|
||||
|
||||
@@ -15,7 +15,7 @@ import getApiInstance, { parseApiError } from '../../../../../../static/js/api_i
|
||||
import { QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import gettext from 'sources/gettext';
|
||||
import Loader from 'sources/components/Loader';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Box } from '@mui/material';
|
||||
import { ResultSetToolbar } from './ResultSetToolbar';
|
||||
import { LayoutDockerContext } from '../../../../../../static/js/helpers/Layout';
|
||||
import { GeometryViewer } from './GeometryViewer';
|
||||
@@ -25,7 +25,7 @@ import { getBrowser } from '../../../../../../static/js/utils';
|
||||
import CopyData from '../QueryToolDataGrid/CopyData';
|
||||
import moment from 'moment';
|
||||
import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import EmptyPanelMessage from '../../../../../../static/js/components/EmptyPanelMessage';
|
||||
import { GraphVisualiser } from './GraphVisualiser';
|
||||
import { usePgAdmin } from '../../../../../../static/js/BrowserComponent';
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, {useContext, useCallback, useEffect, useState} from 'react';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import { PgButtonGroup, PgIconButton } from '../../../../../../static/js/components/Buttons';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import PlaylistAddRoundedIcon from '@material-ui/icons/PlaylistAddRounded';
|
||||
import FileCopyRoundedIcon from '@material-ui/icons/FileCopyRounded';
|
||||
import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded';
|
||||
import TimelineRoundedIcon from '@material-ui/icons/TimelineRounded';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import PlaylistAddRoundedIcon from '@mui/icons-material/PlaylistAddRounded';
|
||||
import FileCopyRoundedIcon from '@mui/icons-material/FileCopyRounded';
|
||||
import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
|
||||
import TimelineRoundedIcon from '@mui/icons-material/TimelineRounded';
|
||||
import { PasteIcon, SaveDataIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import GetAppRoundedIcon from '@material-ui/icons/GetAppRounded';
|
||||
import GetAppRoundedIcon from '@mui/icons-material/GetAppRounded';
|
||||
import {QUERY_TOOL_EVENTS} from '../QueryToolConstants';
|
||||
import { QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import { PgMenu, PgMenuItem } from '../../../../../../static/js/components/Menu';
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React, { useEffect, useState, useContext } from 'react';
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import { Box } from '@mui/material';
|
||||
import clsx from 'clsx';
|
||||
import _ from 'lodash';
|
||||
import { QUERY_TOOL_EVENTS } from '../QueryToolConstants';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { makeStyles } from '@mui/styles';
|
||||
import SchemaView from '../../../../static/js/SchemaView';
|
||||
import BaseUISchema from '../../../../static/js/SchemaView/base_schema.ui';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
.bg-user-invalid {
|
||||
@extend .bg-warning-light;
|
||||
}
|
||||
|
||||
.user_container {
|
||||
border-bottom: $panel-border;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin-top: $title-height;
|
||||
}
|
||||
|
||||
.user_management {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
& .navtab-inline-controls {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.user_management .search_users form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.user_management table {
|
||||
display: block;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
border: 0 none;
|
||||
}
|
||||
Reference in New Issue
Block a user