Fix issues found while testing pagination changes. #1780

This commit is contained in:
Aditya Toshniwal 2024-11-07 18:02:39 +05:30
parent 772c6ecd84
commit 3417186df7
8 changed files with 49 additions and 32 deletions

View File

@ -177,11 +177,7 @@ class BatchProcess:
import secrets import secrets
import string import string
return ''.join( return ''.join(secrets.choice(string.digits) for _ in range(size))
secrets.choice(
string.ascii_uppercase + string.digits
) for _ in range(size)
)
created = False created = False
size = 0 size = 0

View File

@ -33,7 +33,7 @@ const StyledReactDataGrid = styled(ReactDataGrid)(({theme})=>({
'&[aria-colindex="1"]': { '&[aria-colindex="1"]': {
padding: 0, padding: 0,
}, },
'&[aria-selected=true]:not([role="columnheader"])': { '&[aria-selected=true]:not([aria-colindex="1"]):not([role="columnheader"])': {
outlineWidth: '0px', outlineWidth: '0px',
outlineOffset: '0px', outlineOffset: '0px',
}, },
@ -61,7 +61,7 @@ const StyledReactDataGrid = styled(ReactDataGrid)(({theme})=>({
}, },
'&.ReactGrid-cellSelection': { '&.ReactGrid-cellSelection': {
'& .rdg-cell': { '& .rdg-cell': {
'&[aria-selected=true]:not([role="columnheader"])': { '&[aria-selected=true]:not([aria-colindex="1"]):not([role="columnheader"])': {
outlineWidth: '1px', outlineWidth: '1px',
outlineOffset: '-1px', outlineOffset: '-1px',
backgroundColor: theme.palette.primary.light, backgroundColor: theme.palette.primary.light,

View File

@ -15,7 +15,7 @@ import pgAdmin from 'sources/pgadmin';
export function minMaxValidator(label, value, minValue, maxValue) { export function minMaxValidator(label, value, minValue, maxValue) {
if((_.isUndefined(value) || _.isNull(value) || String(value) === '')) if((_.isUndefined(value) || _.isNull(value) || String(value) === ''))
return null; return null;
if (!_.isUndefined(minValue) && value < minValue) { if (!_.isUndefined(minValue) && (value < minValue || value === '-')) {
return sprintf(pgAdmin.Browser.messages.MUST_GR_EQ, label, minValue); return sprintf(pgAdmin.Browser.messages.MUST_GR_EQ, label, minValue);
} else if (!_.isUndefined(maxValue) && value > maxValue) { } else if (!_.isUndefined(maxValue) && value > maxValue) {
return sprintf(pgAdmin.Browser.messages.MUST_LESS_EQ, label, maxValue); return sprintf(pgAdmin.Browser.messages.MUST_LESS_EQ, label, maxValue);

View File

@ -263,10 +263,16 @@ def non_windows_platform(parent, p, fd, data, max_read_bytes, sid):
timeout = 0 timeout = 0
# module provides access to platform-specific I/O # module provides access to platform-specific I/O
# monitoring functions # monitoring functions
(data_ready, _, _) = select.select([parent, fd], [], [], try:
timeout) (data_ready, _, _) = select.select([parent, fd], [], [],
timeout)
read_terminal_data(parent, data_ready, max_read_bytes, sid) read_terminal_data(parent, data_ready, max_read_bytes, sid)
except OSError as e:
# If the process is killed, bad file descriptor exception may
# occur. Handle it gracefully
if p.poll() is not None:
raise e
def pty_handel_io(connection_data, data, sid): def pty_handel_io(connection_data, data, sid):

View File

@ -1129,7 +1129,7 @@ def poll(trans_id):
pagination = { pagination = {
'page_size': page_size, 'page_size': page_size,
'page_count': math.ceil(conn.total_rows / page_size), 'page_count': math.ceil(conn.total_rows / page_size),
'page_no': math.floor(rows_fetched_from / page_size) + 1, 'page_no': math.floor((rows_fetched_from - 1) / page_size) + 1,
'rows_from': rows_fetched_from, 'rows_from': rows_fetched_from,
'rows_to': rows_fetched_to 'rows_to': rows_fetched_to
} }
@ -1197,7 +1197,7 @@ def fetch_window(trans_id, from_rownum=0, to_rownum=0):
pagination = { pagination = {
'page_size': page_size, 'page_size': page_size,
'page_count': math.ceil(conn.total_rows / page_size), 'page_count': math.ceil(conn.total_rows / page_size),
'page_no': math.floor(rows_fetched_from / page_size) + 1, 'page_no': math.floor((rows_fetched_from - 1) / page_size) + 1,
'rows_from': rows_fetched_from, 'rows_from': rows_fetched_from,
'rows_to': rows_fetched_to 'rows_to': rows_fetched_to
} }

View File

@ -73,10 +73,6 @@ const StyledPgReactDataGrid = styled(PgReactDataGrid)(({theme})=>({
'& .rdg-cell:nth-of-type(1)': { '& .rdg-cell:nth-of-type(1)': {
backgroundColor: theme.palette.grey[600], backgroundColor: theme.palette.grey[600],
}, },
'& .rdg-cell:nth-of-type(1)[aria-selected="true"]':{
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
},
'&[aria-selected="true"] .rdg-cell:nth-of-type(1)': { '&[aria-selected="true"] .rdg-cell:nth-of-type(1)': {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,

View File

@ -868,15 +868,19 @@ export function ResultSet() {
eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, selectedRows.size, selectedColumns.size, selectedRange.current, selectedCell.current?.length); eventBus.fireEvent(QUERY_TOOL_EVENTS.SELECTED_ROWS_COLS_CELL_CHANGED, selectedRows.size, selectedColumns.size, selectedRange.current, selectedCell.current?.length);
}; };
const resetSelectionAndChanges = ()=>{
dispatchDataChange({type: 'reset'});
setSelectedRows(new Set());
setSelectedColumns(new Set());
};
const executionStartCallback = async (query, { const executionStartCallback = async (query, {
explainObject, macroSQL, external=false, reconnect=false, executeCursor=false, refreshData=false explainObject, macroSQL, external=false, reconnect=false, executeCursor=false, refreshData=false
})=>{ })=>{
const yesCallback = async ()=>{ const yesCallback = async ()=>{
/* Reset */ /* Reset */
eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, null); eventBus.fireEvent(QUERY_TOOL_EVENTS.HIGHLIGHT_ERROR, null);
dispatchDataChange({type: 'reset'}); resetSelectionAndChanges();
setSelectedRows(new Set());
setSelectedColumns(new Set());
rsu.current.resetClientPKIndex(); rsu.current.resetClientPKIndex();
setLoaderText(gettext('Waiting for the query to complete...')); setLoaderText(gettext('Waiting for the query to complete...'));
setDataOutputQuery(query); setDataOutputQuery(query);
@ -1110,6 +1114,7 @@ export function ResultSet() {
pageDataDirty.current = false; pageDataDirty.current = false;
fetchWindow(...args); fetchWindow(...args);
} }
resetSelectionAndChanges();
}); });
return ()=>{ return ()=>{
deregFetch(); deregFetch();
@ -1234,9 +1239,7 @@ export function ResultSet() {
}); });
setColumns((prev)=>prev); setColumns((prev)=>prev);
} }
dispatchDataChange({type: 'reset'}); resetSelectionAndChanges();
setSelectedRows(new Set());
setSelectedColumns(new Set());
eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, respData.data.transaction_status); eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_CONNECTION_STATUS, respData.data.transaction_status);
eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_MESSAGE, ''); eventBus.fireEvent(QUERY_TOOL_EVENTS.SET_MESSAGE, '');
pgAdmin.Browser.notifier.success(gettext('Data saved successfully.')); pgAdmin.Browser.notifier.success(gettext('Data saved successfully.'));

View File

@ -35,7 +35,7 @@ import PropTypes from 'prop-types';
import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror'; import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror';
import { setEditorPosition } from '../QueryToolDataGrid/Editors'; import { setEditorPosition } from '../QueryToolDataGrid/Editors';
import { InputText } from '../../../../../../static/js/components/FormComponents'; import { InputText } from '../../../../../../static/js/components/FormComponents';
import { minMaxValidator } from '../../../../../../static/js/validators'; import { isEmptyString, minMaxValidator } from '../../../../../../static/js/validators';
const StyledDiv = styled('div')(({theme})=>({ const StyledDiv = styled('div')(({theme})=>({
padding: '2px', padding: '2px',
@ -111,6 +111,7 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
from: pagination.rows_from ?? 0, from: pagination.rows_from ?? 0,
to: pagination.rows_to ?? 0, to: pagination.rows_to ?? 0,
pageNo: pagination.page_no ?? 0, pageNo: pagination.page_no ?? 0,
pageCount: pagination.page_count ?? 0,
}); });
const goToPage = (pageNo)=>{ const goToPage = (pageNo)=>{
@ -138,22 +139,31 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
} }
}; };
useEffect(()=>{
setInputs({
from: pagination.rows_from ?? 0,
to: pagination.rows_to ?? 0,
pageNo: pagination.page_no ?? 0,
pageCount: pagination.page_count ?? 0,
});
}, [pagination, editPageRange]);
useEffect(()=>{ useEffect(()=>{
// validate // validate
setErrorInputs((prev)=>{ setErrorInputs((prev)=>{
let errors = {...prev}; let errors = {...prev};
if(minMaxValidator('', inputs.pageNo, 1, pagination.page_count)) { if(minMaxValidator('', inputs.pageNo, 1, inputs.pageCount) || isEmptyString(inputs.pageNo)) {
errors.pageNo = true; errors.pageNo = true;
} else { } else {
errors.pageNo = false; errors.pageNo = false;
} }
if(minMaxValidator('', inputs.from, 1, inputs.to)) { if(minMaxValidator('', inputs.from, 1, inputs.to) || isEmptyString(inputs.from)) {
errors.from = true; errors.from = true;
} else { } else {
errors.from = false; errors.from = false;
} }
if(minMaxValidator('', inputs.to, 1, totalRowCount)) { if(minMaxValidator('', inputs.to, 1, totalRowCount) || isEmptyString(inputs.to)) {
errors.to = true; errors.to = true;
} else { } else {
errors.to = false; errors.to = false;
@ -161,14 +171,16 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
return errors; return errors;
}); });
}, [inputs, pagination]); }, [inputs]);
return ( return (
<Box className='PaginationInputs'> <Box className='PaginationInputs'>
{editPageRange ? {editPageRange ?
<Box display="flex" gap="2px" alignItems="center"> <Box display="flex" gap="2px" alignItems="center">
<div>{gettext('Showing rows:')}</div> <div>{gettext('Showing rows:')}</div>
<InputText size="small" <InputText
type="int"
size="small"
controlProps={{maxLength: 7}} controlProps={{maxLength: 7}}
style={{ style={{
maxWidth: '10ch' maxWidth: '10ch'
@ -179,7 +191,9 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
error={errorInputs['from']} error={errorInputs['from']}
/> />
<div>{gettext('to')}</div> <div>{gettext('to')}</div>
<InputText size="small" <InputText
type="int"
size="small"
controlProps={{maxLength: 7}} controlProps={{maxLength: 7}}
style={{ style={{
maxWidth: '10ch' maxWidth: '10ch'
@ -194,7 +208,7 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
{editPageRange && <PgIconButton size="xs" {editPageRange && <PgIconButton size="xs"
title={editPageRange ? gettext('Apply (or press Enter on input)') : gettext('Edit range')} title={editPageRange ? gettext('Apply (or press Enter on input)') : gettext('Edit range')}
onClick={()=>eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_WINDOW, inputs.from, inputs.to)} onClick={()=>eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_WINDOW, inputs.from, inputs.to)}
icon={<CheckRoundedIcon />} disabled={errorInputs.from || errorInputs.to} icon={<CheckRoundedIcon />}
/>} />}
<PgIconButton size="xs" <PgIconButton size="xs"
title={editPageRange ? gettext('Cancel edit') : gettext('Edit range')} title={editPageRange ? gettext('Cancel edit') : gettext('Edit range')}
@ -204,7 +218,9 @@ function PaginationInputs({pagination, totalRowCount, clearSelection}) {
</PgButtonGroup> </PgButtonGroup>
<div className='PaginationInputs-divider'>&nbsp;</div> <div className='PaginationInputs-divider'>&nbsp;</div>
<span>{gettext('Page No:')}</span> <span>{gettext('Page No:')}</span>
<InputText size="small" <InputText
type="int"
size="small"
controlProps={{maxLength: 7}} controlProps={{maxLength: 7}}
style={{ style={{
maxWidth: '10ch' maxWidth: '10ch'