Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/en_US/images/query_data_pagination.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/en_US/query_tool_toolbar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ Pagination Options
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
| *Edit Range* | Click to open the from and to rows range inputs to allow setting them. | |
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
| *Show Entire Range* | Click to get all the rows and set the from and to rows range | |
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
| *Page No* | Enter the page no you want to jump to out of total shown next to this input | |
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
| *First Page* | Click to go to the first page. | |
Expand Down
7 changes: 7 additions & 0 deletions web/pgadmin/static/js/custom_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,10 @@ export function useBeforeUnload({ enabled, isNewTab, beforeClose, closePanel })

return {forceClose};
}

export function useLatestFunc(fn) {
const fnRef = useRef(fn);
fnRef.current = fn;

return useCallback(((...args) => fnRef.current(...args)), []);
}
9 changes: 2 additions & 7 deletions web/pgadmin/static/js/helpers/ModalProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,14 @@ function alert(title, text, onOkClick, okLabel = gettext('OK')) {
function confirm(title, text, onOkClick, onCancelClick, okLabel = gettext('Yes'), cancelLabel = gettext('No'), okIcon = 'default', modalId=null) {
// bind the modal provider before calling
this.showModal(title, (closeModal) => {
const onCancelClickClose = () => {
onCancelClick?.();
closeModal();
};

const onOkClickClose = () => {
onOkClick?.();
closeModal();
};
return (
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={onCancelClickClose} okLabel={okLabel} cancelLabel={cancelLabel} okIcon={okIcon}/>
<AlertContent text={text} confirm onOkClick={onOkClickClose} onCancelClick={closeModal} okLabel={okLabel} cancelLabel={cancelLabel} okIcon={okIcon}/>
);
}, {id: modalId});
}, {id: modalId, onClose: onCancelClick});
}

function confirmDelete(title, text, onDeleteClick, onCancelClick, deleteLabel = gettext('Delete'), cancelLabel = gettext('Cancel')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { GraphVisualiser } from './GraphVisualiser';
import { usePgAdmin } from '../../../../../../static/js/PgAdminProvider';
import pgAdmin from 'sources/pgadmin';
import { connectServer, connectServerModal } from '../connectServer';
import { useLatestFunc } from '../../../../../../static/js/custom_hooks';

const StyledBox = styled(Box)(({theme}) => ({
display: 'flex',
Expand Down Expand Up @@ -846,7 +847,7 @@ export function ResultSet() {
const modalId = MODAL_DIALOGS.QT_CONFIRMATIONS;
// We'll use this track if any changes were saved.
// It will help to decide whether results refresh is required or not on page change.
const pageDataDirty = useRef(false);
const pageDataOutOfSync = useRef(false);

const selectedCell = useRef([]);
const selectedRange = useRef(null);
Expand All @@ -873,9 +874,10 @@ export function ResultSet() {
// To use setLoaderText to the ResultSetUtils.
rsu.current.setLoaderText = setLoaderText;

const isDataChanged = ()=>{
return Boolean(_.size(dataChangeStore.updated) || _.size(dataChangeStore.added) || _.size(dataChangeStore.deleted));
};
const isDataChangedRef = useRef(false);
useEffect(()=>{
isDataChangedRef.current = Boolean(_.size(dataChangeStore.updated) || _.size(dataChangeStore.added) || _.size(dataChangeStore.deleted));
}, [dataChangeStore]);

const fireRowsColsCellChanged = ()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, selectedRows.size, selectedColumns.size, selectedRange.current, selectedCell.current?.length);
Expand Down Expand Up @@ -948,7 +950,7 @@ export function ResultSet() {
});
};

if(isDataChanged() && !refreshData) {
if(isDataChangedRef.current && !refreshData) {
queryToolCtx.modal.confirm(
gettext('Unsaved changes'),
gettext('The data has been modified, but not saved. Are you sure you wish to discard the changes?'),
Expand Down Expand Up @@ -1093,6 +1095,7 @@ export function ResultSet() {
setLoaderText(gettext('Fetching rows...'));
try {
res = await rsu.current.getWindowRows(fromRownum, toRownum);
resetSelectionAndChanges();
const newRows = rsu.current.processRows(res.data.data.result, columns);
setRows([...newRows]);
setQueryData((prev)=>({
Expand All @@ -1119,18 +1122,33 @@ export function ResultSet() {
useEffect(()=>{
let deregExecEnd;
const deregFetch = eventBus.registerListener(QUERY_TOOL_EVENTS.FETCH_WINDOW, (...args)=>{
if(pageDataDirty.current) {
deregExecEnd = eventBus.registerListener(QUERY_TOOL_EVENTS.EXECUTION_END, (success)=>{
if(!success) return;
pageDataDirty.current = false;
const impl = ()=> {
if(pageDataOutOfSync.current) {
deregExecEnd = eventBus.registerListener(QUERY_TOOL_EVENTS.EXECUTION_END, (success)=>{
if(!success) return;
pageDataOutOfSync.current = false;
fetchWindow(...args);
}, true);
eventBus.fireEvent(QUERY_TOOL_EVENTS.EXECUTION_START, rsu.current.query, {refreshData: true});
// executionStartCallback(rsu.current.query, {refreshData: true});
} else {
pageDataOutOfSync.current = false;
fetchWindow(...args);
}, true);
executionStartCallback(rsu.current.query, {refreshData: true});
}
};

if(isDataChangedRef.current) {
queryToolCtx.modal.confirm(
gettext('Unsaved changes'),
gettext('The data has been modified, but not saved. Are you sure you wish to discard the changes?'),
impl,
function() {
/* Do nothing */
}
);
} else {
pageDataDirty.current = false;
fetchWindow(...args);
impl();
}
resetSelectionAndChanges();
});
return ()=>{
deregFetch();
Expand All @@ -1144,7 +1162,7 @@ export function ResultSet() {

const warnSaveDataClose = ()=>{
// No changes.
if(!isDataChanged() || !queryToolCtx.preferences?.sqleditor.prompt_save_data_changes) {
if(!isDataChangedRef.current || !queryToolCtx.preferences?.sqleditor.prompt_save_data_changes) {
eventBus.fireEvent(QUERY_TOOL_EVENTS.WARN_SAVE_TEXT_CLOSE);
return;
}
Expand Down Expand Up @@ -1172,7 +1190,7 @@ export function ResultSet() {
};
}, [dataChangeStore]);

const triggerSaveData = async ()=>{
const triggerSaveData = useLatestFunc(async ()=>{
if(!_.size(dataChangeStore.updated) && !_.size(dataChangeStore.added) && !_.size(dataChangeStore.deleted)) {
return;
}
Expand Down Expand Up @@ -1210,7 +1228,7 @@ export function ResultSet() {
} catch {/* History errors should not bother others */}

if(!respData.data.status) {
pageDataDirty.current = false;
pageDataOutOfSync.current = false;
eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_MESSAGE, respData.data.result);
pgAdmin.Browser.notifier.error(respData.data.result, 20000);
// If the transaction is not idle, notify the user that previous queries are not rolled back,
Expand All @@ -1223,7 +1241,7 @@ export function ResultSet() {
return;
}

pageDataDirty.current = true;
pageDataOutOfSync.current = true;
if(_.size(dataChangeStore.added)) {
// Update the rows in a grid after addition
respData.data.query_results.forEach((qr)=>{
Expand Down Expand Up @@ -1258,18 +1276,19 @@ export function ResultSet() {
resetSelectionAndChanges();
eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, respData.data.transaction_status);
eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_MESSAGE, '');
setLoaderText(null);
pgAdmin.Browser.notifier.success(gettext('Data saved successfully.'));
if(respData.data.transaction_status > CONNECTION_STATUS.TRANSACTION_STATUS_IDLE) {
pgAdmin.Browser.notifier.info(gettext('Auto-commit is off. You still need to commit changes to the database.'));
}
} catch (error) {
pageDataDirty.current = false;
pageDataOutOfSync.current = false;
eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, error, {
checkTransaction: true,
});
setLoaderText(null);
}
setLoaderText(null);
};
});

useEffect(()=>{
eventBus.registerListener(QUERY_TOOL_EVENTS.TRIGGER_SAVE_DATA, triggerSaveData);
Expand Down
3 changes: 2 additions & 1 deletion web/pgadmin/utils/driver/psycopg3/server_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,8 @@ def create_connection_string(self, database, user, password=None):
if key == 'hostaddr' and self.use_ssh_tunnel:
continue

# Convert boolean connection parameters to integer for libpq compatibility
# Convert boolean connection parameters to integer for
# libpq compatibility
if key in ('sslcompression', 'sslsni'):
value = 1 if value else 0

Expand Down
Loading