From 64ffed0ddbcba79c1603b58e85fe0b617083ea9e Mon Sep 17 00:00:00 2001 From: Aditya Toshniwal Date: Fri, 29 Apr 2022 16:29:46 +0530 Subject: [PATCH] 1. Filter dialog doesn't work in edit mode (getting back end errors), reverting it back to create mode of SchemaView. 2. Enable the copy button when a cell is selected. 3. Exclude, Include related fixes. --- web/pgadmin/static/js/Theme/index.jsx | 8 + .../js/components/QueryToolComponent.jsx | 53 +++--- .../js/components/QueryToolConstants.js | 2 +- .../js/components/QueryToolDataGrid/index.jsx | 66 ++++---- .../js/components/dialogs/FilterDialog.jsx | 2 +- .../js/components/sections/MainToolBar.jsx | 2 +- .../js/components/sections/ResultSet.jsx | 157 ++++++++++-------- .../components/sections/ResultSetToolbar.jsx | 4 +- .../js/components/sections/StatusBar.jsx | 2 +- 9 files changed, 170 insertions(+), 126 deletions(-) diff --git a/web/pgadmin/static/js/Theme/index.jsx b/web/pgadmin/static/js/Theme/index.jsx index 2dbcadbe3..1f6be3d4c 100644 --- a/web/pgadmin/static/js/Theme/index.jsx +++ b/web/pgadmin/static/js/Theme/index.jsx @@ -372,6 +372,14 @@ function getFinalTheme(baseTheme) { } }, }, + MuiSelect: { + icon: { + color: baseTheme.palette.text.primary, + '&.Mui-disabled': { + color: baseTheme.palette.text.muted, + } + }, + }, MuiIconButton: { root: { color: baseTheme.palette.text.primary, diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx index 96aa1c1ee..8c7ecedaf 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx @@ -525,7 +525,6 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN }, isNew) ); }, ()=>{ - // selectConn(currSelectedConn, currConnected, false); }); } else { selectConn(currSelectedConn, currConnected, false); @@ -541,31 +540,37 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN id: 'new-conn', title: gettext('Add New Connection'), content: { - let connectionData = { - sgid: 0, - sid: data.sid, - did: data.did, - user: data.user, - role: data.role ?? null, - password: data.password, - title: getTitle(pgAdmin, qtState.preferences.browser, null, false, data.server_name, data.database_name, data.user, true), - conn_title: getTitle(pgAdmin, null, null, true, data.server_name, data.database_name, data.user, true), - server_name: data.server_name, - database_name: data.database_name, - is_selected: true, - }; + return new Promise((resolve, reject)=>{ + let connectionData = { + sgid: 0, + sid: data.sid, + did: data.did, + user: data.user, + role: data.role ?? null, + password: data.password, + title: getTitle(pgAdmin, qtState.preferences.browser, null, false, data.server_name, data.database_name, data.role || data.user, true), + conn_title: getTitle(pgAdmin, null, null, true, data.server_name, data.database_name, data.role || data.user, true), + server_name: data.server_name, + database_name: data.database_name, + is_selected: true, + }; - let existIdx = _.findIndex(qtState.connection_list, (conn)=>( - conn.sid == connectionData.sid && conn.did == connectionData.did - && conn.user == connectionData.user && conn.role == connectionData.role - )); - if(existIdx > -1) { - return Promise.reject(gettext('Connection with this configuration already present.')); - } - updateQueryToolConnection(connectionData, true).then(()=>{ - onClose(); + let existIdx = _.findIndex(qtState.connection_list, (conn)=>( + conn.sid == connectionData.sid && conn.did == connectionData.did + && conn.user == connectionData.user && conn.role == connectionData.role + )); + if(existIdx > -1) { + reject(gettext('Connection with this configuration already present.')); + return; + } + updateQueryToolConnection(connectionData, true) + .catch((err)=>{ + reject(err); + }).then(()=>{ + resolve(); + onClose(); + }); }); - return Promise.resolve(); }} onClose={onClose}/> }); diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js index a6635dc2d..ba6b038ca 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolConstants.js @@ -36,7 +36,7 @@ export const QUERY_TOOL_EVENTS = { CURSOR_ACTIVITY: 'CURSOR_ACTIVITY', SET_MESSAGE: 'SET_MESSAGE', ROWS_FETCHED: 'ROWS_FETCHED', - SELECTED_ROWS_COLS_CHANGED: 'SELECTED_ROWS_COLS_CHANGED', + SELECTED_ROWS_COLS_CELL_CHANGED: 'SELECTED_ROWS_COLS_CELL_CHANGED', DATAGRID_CHANGED: 'DATAGRID_CHANGED', HIGHLIGHT_ERROR: 'HIGHLIGHT_ERROR', FOCUS_PANEL: 'FOCUS_PANEL', diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx index 664497451..26079553a 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////// import { Box, makeStyles } from '@material-ui/core'; import _ from 'lodash'; -import React, {useState, useEffect, useCallback, useContext, useRef} from 'react'; +import React, {useState, useEffect, useMemo, useContext, useRef} from 'react'; import ReactDataGrid, {Row, useRowSelection} from 'react-data-grid'; import LockIcon from '@material-ui/icons/Lock'; import EditIcon from '@material-ui/icons/Edit'; @@ -19,7 +19,7 @@ import clsx from 'clsx'; import { PgIconButton } from '../../../../../../static/js/components/Buttons'; import MapIcon from '@material-ui/icons/Map'; import { QueryToolEventsContext } from '../QueryToolComponent'; -import PropTypes, { number } from 'prop-types'; +import PropTypes from 'prop-types'; import gettext from 'sources/gettext'; export const ROWNUM_KEY = '$_pgadmin_rownum_key_$'; @@ -99,15 +99,22 @@ const useStyles = makeStyles((theme)=>({ })); export const RowInfoContext = React.createContext(); +export const DataGridExtrasContext = React.createContext(); function CustomRow(props) { const rowRef = useRef(); + const dataGridExtras = useContext(DataGridExtrasContext); const rowInfoValue = { rowIdx: props.rowIdx, getCellElement: (colIdx)=>{ return rowRef.current?.querySelector(`.rdg-cell[aria-colindex="${colIdx+1}"]`); } }; + if(!props.isRowSelected && props.selectedCellIdx > 0) { + dataGridExtras.onSelectedCellChange?.([props.row, props.viewportColumns?.[props.selectedCellIdx]]); + } else if(props.selectedCellIdx == 0) { + dataGridExtras.onSelectedCellChange?.(null); + } return ( @@ -116,7 +123,11 @@ function CustomRow(props) { } CustomRow.propTypes = { - rowIdx: number, + rowIdx: PropTypes.number, + isRowSelected: PropTypes.bool, + selectedCellIdx: PropTypes.number, + row: PropTypes.object, + viewportColumns: PropTypes.array, }; function SelectAllHeaderRenderer(props) { @@ -134,9 +145,14 @@ SelectAllHeaderRenderer.propTypes = { onAllRowsSelectionChange: PropTypes.func, }; -function SelectableHeaderRenderer({column, selectedColumns, onSelectedColumnsChange}) { +function SelectableHeaderRenderer({column, selectedColumns, onSelectedColumnsChange, isCellSelected}) { const classes = useStyles(); const eventBus = useContext(QueryToolEventsContext); + const dataGridExtras = useContext(DataGridExtrasContext); + + if(isCellSelected) { + dataGridExtras.onSelectedCellChange?.(null); + } const onClick = ()=>{ eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, true, ()=>{ @@ -176,6 +192,7 @@ SelectableHeaderRenderer.propTypes = { column: PropTypes.object, selectedColumns: PropTypes.objectOf(Set), onSelectedColumnsChange: PropTypes.func, + isCellSelected: PropTypes.bool, }; function setEditorFormatter(col) { @@ -345,14 +362,6 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha }); }, [dataChangeStore, selectedColumns]); - const onRowClick = useCallback((row, column)=>{ - if(column.key === ROWNUM_KEY) { - onSelectedCellChange && onSelectedCellChange(null); - } else { - onSelectedCellChange && onSelectedCellChange([row, column]); - } - }, []); - function handleCopy() { if (window.isSecureContext) { eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_COPY_DATA); @@ -360,22 +369,23 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha } return ( - + ({onSelectedCellChange}), [])}> + + ); } diff --git a/web/pgadmin/tools/sqleditor/static/js/components/dialogs/FilterDialog.jsx b/web/pgadmin/tools/sqleditor/static/js/components/dialogs/FilterDialog.jsx index efd1c9bc7..336b47d31 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/dialogs/FilterDialog.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/dialogs/FilterDialog.jsx @@ -136,7 +136,7 @@ export default function FilterDialog({onClose, onSave}) { getInitData={getInitData} schema={filterSchemaObj} viewHelperProps={{ - mode: 'edit', + mode: 'create', }} onSave={onSaveClick} onClose={onClose} diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx index e971c0520..f766ff927 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx @@ -253,7 +253,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) { eventBus.registerListener(QUERY_TOOL_EVENTS.DATAGRID_CHANGED, (isDirty)=>{ setDisableButton('save-data', !isDirty); }); - eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CHANGED, (rows)=>{ + eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, (rows)=>{ setDisableButton('delete-rows', !rows); }); eventBus.registerListener(QUERY_TOOL_EVENTS.SET_FILTER_INFO, (canFilter, filterApplied)=>{ diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx index e434ecf61..225f05602 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx @@ -730,51 +730,101 @@ export function ResultSet() { const [selectedRows, setSelectedRows] = useState(new Set()); const [selectedColumns, setSelectedColumns] = useState(new Set()); const selectedCell = useRef([]); - const setSelectedCell = (val)=>selectedCell.current=val; + const setSelectedCell = (val)=>{ + selectedCell.current=val; + fireRowsColsCellChanged(); + }; const [rowsResetKey, setRowsResetKey] = useState(true); rsu.current.setEventBus(eventBus); + const isDataChanged = ()=>{ + return Boolean(_.size(dataChangeStore.updated) || _.size(dataChangeStore.added) || _.size(dataChangeStore.deleted)); + }; + + const fireRowsColsCellChanged = ()=>{ + eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, selectedRows.size, selectedColumns.size, selectedCell.current?.length); + }; + const executionStartCallback = async (query, explainObject, external=false, reconnect=false)=>{ - /* Reset */ - eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, null); - dispatchDataChange({type: 'reset'}); - setSelectedRows(new Set()); - setSelectedColumns(new Set()); - setLoaderText(gettext('Waiting for the query to complete...')); - let goForPoll = await rsu.current.startExecution( - query, explainObject, - ()=>{ - setColumns([]); - setRows([]); - }, - {isQueryTool: queryToolCtx.params.is_query_tool, external: external, reconnect: reconnect} - ); - if(goForPoll) { - rsu.current.pollForResult( - (procQueryData, procColumns, procRows)=>{ - setQueryData(procQueryData); - setColumns(procColumns); - setRows(procRows); - setRowsResetKey(!rowsResetKey); - }, - (planJson)=>{ - /* No need to open if plan is empty */ - if(!LayoutHelper.isTabOpen(queryToolCtx.docker, PANELS.EXPLAIN) && !planJson) { - return; - } - LayoutHelper.openTab(queryToolCtx.docker, { - id: PANELS.EXPLAIN, - title:gettext('Explain'), - content: , - closable: true, - }, PANELS.MESSAGES, 'after-tab', true); - }, + const yesCallback = async ()=>{ + /* Reset */ + eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, null); + dispatchDataChange({type: 'reset'}); + setSelectedRows(new Set()); + setSelectedColumns(new Set()); + setLoaderText(gettext('Waiting for the query to complete...')); + let goForPoll = await rsu.current.startExecution( + query, explainObject, ()=>{ setColumns([]); setRows([]); + }, + {isQueryTool: queryToolCtx.params.is_query_tool, external: external, reconnect: reconnect} + ); + if(goForPoll) { + rsu.current.pollForResult( + (procQueryData, procColumns, procRows)=>{ + setQueryData(procQueryData); + setColumns(procColumns); + setRows(procRows); + setRowsResetKey(!rowsResetKey); + }, + (planJson)=>{ + /* No need to open if plan is empty */ + if(!LayoutHelper.isTabOpen(queryToolCtx.docker, PANELS.EXPLAIN) && !planJson) { + return; + } + LayoutHelper.openTab(queryToolCtx.docker, { + id: PANELS.EXPLAIN, + title: gettext('Explain'), + content: , + closable: true, + }, PANELS.MESSAGES, 'after-tab', true); + }, + ()=>{ + setColumns([]); + setRows([]); + } + ); + } + }; + + if(isDataChanged()) { + queryToolCtx.modal.confirm( + gettext('Unsaved changes'), + gettext('The data has been modified, but not saved. Are you sure you wish to discard the changes?'), + yesCallback, + function() { + eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_END); } ); + } else { + yesCallback(); + } + }; + + const triggerFilter = async (include)=>{ + if(_.isEmpty(selectedCell.current)) { + return; + } + setLoaderText(gettext('Applying the new filter...')); + try { + let data = { + [selectedCell.current[1].key]: selectedCell.current[0][selectedCell.current[1].key], + }; + if(include) { + await rsu.current.includeFilter(data); + } else { + await rsu.current.excludeFilter(data); + } + setLoaderText(''); + eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION); + } catch(err) { + eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err, { + checkTransaction: true, + }); + setLoaderText(''); } }; @@ -831,6 +881,7 @@ export function ResultSet() { setLoaderText(''); } }); + eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, triggerFilter); }, []); useEffect(()=>{ @@ -838,39 +889,10 @@ export function ResultSet() { return ()=>{ eventBus.deregisterListener(QUERY_TOOL_EVENTS.EXECUTION_START, executionStartCallback); }; - }, [queryToolCtx.docker]); + }, [queryToolCtx.docker, dataChangeStore]); useEffect(()=>{ - const triggerFilter = async (include)=>{ - if(_.isEmpty(selectedCell.current)) { - return; - } - setLoaderText(gettext('Applying the new filter...')); - try { - let data = { - [selectedCell.current[1].key]: selectedCell.current[0][selectedCell.current[1].key], - }; - if(include) { - await rsu.current.includeFilter(data); - } else { - await rsu.current.excludeFilter(data); - } - setSelectedCell([]); - setLoaderText(''); - eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_EXECUTION); - } catch(err) { - eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err, { - checkTransaction: true, - }); - setLoaderText(''); - } - }; - eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, triggerFilter); - return ()=>eventBus.deregisterListener(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, triggerFilter); - }, [selectedCell.current]); - - useEffect(()=>{ - eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CHANGED, selectedRows.size, selectedColumns.size); + fireRowsColsCellChanged(); }, [selectedRows.size, selectedColumns.size]); useEffect(()=>{ @@ -905,8 +927,7 @@ export function ResultSet() { const warnSaveDataClose = ()=>{ // No changes. - if(!_.size(dataChangeStore.updated) && !_.size(dataChangeStore.added) && !_.size(dataChangeStore.deleted) - || !queryToolCtx.preferences?.sqleditor.prompt_save_data_changes) { + if(!isDataChanged() || !queryToolCtx.preferences?.sqleditor.prompt_save_data_changes) { eventBus.fireEvent(QUERY_TOOL_EVENTS.WARN_SAVE_TEXT_CLOSE); return; } diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx index 34c34c8db..bdab9e7d8 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx @@ -104,9 +104,9 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) { eventBus.registerListener(QUERY_TOOL_EVENTS.DATAGRID_CHANGED, (isDirty)=>{ setDisableButton('save-data', !isDirty); }); - eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CHANGED, (rows, cols)=>{ + eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, (rows, cols, cells)=>{ setDisableButton('delete-rows', !rows); - setDisableButton('copy-rows', (!rows && !cols)); + setDisableButton('copy-rows', (!rows && !cols && !cells)); }); }, []); diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/StatusBar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/StatusBar.jsx index 2fb459591..9b4c2d091 100644 --- a/web/pgadmin/tools/sqleditor/static/js/components/sections/StatusBar.jsx +++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/StatusBar.jsx @@ -73,7 +73,7 @@ export function StatusBar() { eventBus.registerListener(QUERY_TOOL_EVENTS.ROWS_FETCHED, (fetched, total)=>{ setRowsCount([fetched||0, total||0]); }); - eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CHANGED, (rows)=>{ + eventBus.registerListener(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, (rows)=>{ setSelectedRowsCount(rows); }); eventBus.registerListener(QUERY_TOOL_EVENTS.DATAGRID_CHANGED, (_isDirty, dataChangeStore)=>{