mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fix Dashboard minor UI issues.
Fix the issue where PG logs doesn't display in CSV or JSON format even if it gets selected through the UI.
This commit is contained in:
@@ -536,16 +536,18 @@ def logs(log_format=None, disp_format=None, sid=None, page=0):
|
||||
status, _format = g.conn.execute_scalar(sql)
|
||||
|
||||
# Check the requested format is available or not
|
||||
log_format = ''
|
||||
if log_format == 'C' and 'csvlog' in _format:
|
||||
log_format = 'csvlog'
|
||||
elif log_format == 'J' and 'jsonlog' in _format:
|
||||
log_format = 'jsonlog'
|
||||
else:
|
||||
log_format = ''
|
||||
|
||||
sql = render_template(
|
||||
"/".join([g.template_path, 'log_stat.sql']),
|
||||
log_format=log_format, conn=g.conn
|
||||
)
|
||||
|
||||
status, res = g.conn.execute_scalar(sql)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
@@ -557,6 +559,12 @@ def logs(log_format=None, disp_format=None, sid=None, page=0):
|
||||
|
||||
file_stat = json.loads(res[0])
|
||||
|
||||
if file_stat <= 0:
|
||||
return ajax_response(
|
||||
response={'logs_disabled': True},
|
||||
status=200
|
||||
)
|
||||
|
||||
_start = 0
|
||||
_end = ON_DEMAND_LOG_COUNT
|
||||
page = int(page)
|
||||
@@ -573,13 +581,12 @@ def logs(log_format=None, disp_format=None, sid=None, page=0):
|
||||
log_format=log_format, conn=g.conn
|
||||
)
|
||||
status, res = g.conn.execute_dict(sql)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
final_res = res['rows'][0]['pg_read_file'].split('\n')
|
||||
# Json format
|
||||
if log_format == 'J':
|
||||
if log_format == 'jsonlog':
|
||||
for f in final_res:
|
||||
try:
|
||||
_tmp_log = json.loads(f)
|
||||
@@ -591,7 +598,7 @@ def logs(log_format=None, disp_format=None, sid=None, page=0):
|
||||
pass
|
||||
|
||||
# CSV format
|
||||
elif log_format == 'C':
|
||||
elif log_format == 'csvlog':
|
||||
for f in final_res:
|
||||
try:
|
||||
_tmp_log = f.split(',')
|
||||
|
||||
@@ -83,15 +83,19 @@ const Root = styled('div')(({theme}) => ({
|
||||
},
|
||||
'& .Dashboard-textArea': {
|
||||
height: '88%',
|
||||
}
|
||||
},
|
||||
'& .RefreshButtons': {
|
||||
display: 'flex',
|
||||
},
|
||||
'& .Mui-disabled': {
|
||||
pointerEvents: 'auto',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'& .Dashboard-emptyPanel': {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: theme.otherVars.emptySpaceBg,
|
||||
overflow: 'auto',
|
||||
padding: '8px',
|
||||
display: 'flex',
|
||||
},
|
||||
@@ -234,7 +238,7 @@ function getCancelCell(pgAdmin, sid, did, canTakeAction, onSuccess) {
|
||||
|
||||
function CustomRefresh({refresh, setRefresh}) {
|
||||
return (
|
||||
<RefreshButton onClick={(e) => {
|
||||
<RefreshButton noBorder={false} onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setRefresh(!refresh);
|
||||
}}/>
|
||||
@@ -245,12 +249,8 @@ CustomRefresh.propTypes = {
|
||||
setRefresh: PropTypes.func,
|
||||
};
|
||||
|
||||
function ActiveOnlyHeader({activeOnly, setActiveOnly, refresh, setRefresh}) {
|
||||
return (<Fragment>
|
||||
<RefreshButton onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setRefresh(!refresh);
|
||||
}}/>
|
||||
function ActiveOnlyHeader({activeOnly, setActiveOnly}) {
|
||||
return (
|
||||
<InputCheckbox
|
||||
label={gettext('Active sessions only')}
|
||||
labelPlacement="end"
|
||||
@@ -263,7 +263,7 @@ function ActiveOnlyHeader({activeOnly, setActiveOnly, refresh, setRefresh}) {
|
||||
controlProps={{
|
||||
label: gettext('Active sessions only'),
|
||||
}}
|
||||
/></Fragment>
|
||||
/>
|
||||
);
|
||||
}
|
||||
ActiveOnlyHeader.propTypes = {
|
||||
@@ -768,7 +768,6 @@ function Dashboard({
|
||||
enableFilters: true,
|
||||
minSize: 50,
|
||||
size: 80,
|
||||
cell: ({ value }) => String(value)
|
||||
},
|
||||
];
|
||||
|
||||
@@ -824,8 +823,10 @@ function Dashboard({
|
||||
let _format = res.data;
|
||||
let _frm = [
|
||||
{'label': gettext('Text'), 'value': 'T', 'disabled': !_format.includes('stderr')},
|
||||
{'label': gettext('JSON'), 'value': 'J', 'disabled': !_format.includes('jsonlog')},
|
||||
{'label': gettext('CSV'), 'value': 'C', 'disabled': !_format.includes('csvlog')}
|
||||
{'label': gettext('JSON'), 'value': 'J', 'disabled': !_format.includes('jsonlog'),
|
||||
tooltip: gettext('Enable JSON logging from postgresql.conf.')},
|
||||
{'label': gettext('CSV'), 'value': 'C', 'disabled': !_format.includes('csvlog'),
|
||||
tooltip: gettext('Enable CSV logging from postgres.conf.')}
|
||||
];
|
||||
setLogConfigFormat(_frm);
|
||||
})
|
||||
@@ -840,7 +841,6 @@ function Dashboard({
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (mainTabVal == 0) return;
|
||||
// disable replication tab
|
||||
if(!treeNodeInfo?.server?.replication_type && mainTabVal == 5) {
|
||||
setMainTabVal(0);
|
||||
@@ -879,7 +879,7 @@ function Dashboard({
|
||||
if (node) {
|
||||
setSsMsg(gettext('Loading logs...'));
|
||||
setDashData([]);
|
||||
if (mainTabVal != 4 && mainTabVal != 5) {
|
||||
if (mainTabVal == 1 || mainTabVal == 2 || mainTabVal == 3) {
|
||||
api({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
@@ -1081,6 +1081,7 @@ function Dashboard({
|
||||
<TabPanel value={mainTabVal} index={1} classNameRoot='Dashboard-tabPanel'>
|
||||
{!_.isUndefined(preferences) && preferences.show_activity && (
|
||||
<Fragment>
|
||||
<CustomRefresh refresh={refresh} setRefresh={setRefresh}/>
|
||||
<SectionContainer title={gettext('Sessions')} style={{height: 'auto', minHeight: '200px', paddingBottom: '20px'}}
|
||||
>
|
||||
<PgTable
|
||||
@@ -1094,7 +1095,6 @@ function Dashboard({
|
||||
</SectionContainer>
|
||||
<SectionContainer title={gettext('Locks')} style={{height: 'auto', minHeight: '200px', paddingBottom: '20px'}}>
|
||||
<PgTable
|
||||
customHeader={<CustomRefresh refresh={refresh} setRefresh={setRefresh}/>}
|
||||
caveTable={false}
|
||||
tableNoBorder={false}
|
||||
columns={databaseLocksColumns}
|
||||
@@ -1103,7 +1103,6 @@ function Dashboard({
|
||||
</SectionContainer>
|
||||
<SectionContainer title={gettext('Prepared Transactions')} style={{height: 'auto', minHeight: '200px', paddingBottom: '20px'}}>
|
||||
<PgTable
|
||||
customHeader={<CustomRefresh refresh={refresh} setRefresh={setRefresh}/>}
|
||||
caveTable={false}
|
||||
tableNoBorder={false}
|
||||
columns={databasePreparedColumns}
|
||||
|
||||
@@ -23,11 +23,11 @@ const StyledPgIconButton = styled(PgIconButton)(({theme}) => ({
|
||||
}
|
||||
}));
|
||||
|
||||
export default function RefreshButton({onClick}) {
|
||||
export default function RefreshButton({onClick, noBorder=true}) {
|
||||
return (
|
||||
<StyledPgIconButton
|
||||
size="xs"
|
||||
noBorder
|
||||
noBorder={noBorder}
|
||||
className='RefreshButtons'
|
||||
icon={<CachedOutlinedIcon />}
|
||||
onClick={onClick}
|
||||
@@ -39,5 +39,6 @@ export default function RefreshButton({onClick}) {
|
||||
}
|
||||
|
||||
RefreshButton.propTypes = {
|
||||
onClick: PropTypes.func
|
||||
onClick: PropTypes.func,
|
||||
noBorder: PropTypes.bool
|
||||
};
|
||||
|
||||
@@ -676,7 +676,7 @@ export const InputToggle = forwardRef(({ cid, value, onChange, options, disabled
|
||||
const isDisabled = disabled || option.disabled || (readonly && !isSelected);
|
||||
|
||||
return <ToggleCheckButton ref={i == 0 ? ref : null} key={option.label} label={option.label}
|
||||
selected={isSelected} value={option.value} disabled={isDisabled}
|
||||
selected={isSelected} value={option.value} disabled={isDisabled} title={option.tooltip}
|
||||
/>;
|
||||
})
|
||||
}
|
||||
|
||||
@@ -118,46 +118,44 @@ export function Table({ columns, data, hasSelectRow, schema, sortOptions, tableP
|
||||
let totalFetched = 0;
|
||||
let totalDBRowCount = 0;
|
||||
|
||||
if (loadNextPage) {
|
||||
//Infinite scrolling
|
||||
const { _data, fetchNextPage, isFetching } =
|
||||
useInfiniteQuery({
|
||||
queryKey: ['logs'],
|
||||
queryFn: async () => {
|
||||
const fetchedData = await loadNextPage();
|
||||
return fetchedData;
|
||||
},
|
||||
initialPageParam: 0,
|
||||
getNextPageParam: (_lastGroup, groups) => groups.length,
|
||||
refetchOnWindowFocus: false,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
flatData = _data || [];
|
||||
totalFetched = flatData.length;
|
||||
|
||||
//called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table
|
||||
fetchMoreOnBottomReached = React.useCallback(
|
||||
(containerRefElement = HTMLDivElement | null) => {
|
||||
if (containerRefElement) {
|
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
|
||||
//once the user has scrolled within 500px of the bottom of the table, fetch more data if we can
|
||||
if (
|
||||
scrollHeight - scrollTop - clientHeight < 500 &&
|
||||
!isFetching
|
||||
) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}
|
||||
//Infinite scrolling
|
||||
const { _data, fetchNextPage, isFetching } =
|
||||
useInfiniteQuery({
|
||||
queryKey: ['logs'],
|
||||
queryFn: async () => {
|
||||
const fetchedData = await loadNextPage();
|
||||
return fetchedData;
|
||||
},
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount]
|
||||
);
|
||||
initialPageParam: 0,
|
||||
getNextPageParam: (_lastGroup, groups) => groups.length,
|
||||
refetchOnWindowFocus: false,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
//a check on mount and after a fetch to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
React.useEffect(() => {
|
||||
fetchMoreOnBottomReached(tableRef.current);
|
||||
}, [fetchMoreOnBottomReached]);
|
||||
}
|
||||
flatData = _data || [];
|
||||
totalFetched = flatData.length;
|
||||
|
||||
//called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table
|
||||
fetchMoreOnBottomReached = React.useCallback(
|
||||
(containerRefElement = HTMLDivElement | null) => {
|
||||
if (containerRefElement) {
|
||||
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
|
||||
//once the user has scrolled within 500px of the bottom of the table, fetch more data if we can
|
||||
if (
|
||||
scrollHeight - scrollTop - clientHeight < 500 &&
|
||||
!isFetching
|
||||
) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}
|
||||
},
|
||||
[fetchNextPage, isFetching, totalFetched, totalDBRowCount]
|
||||
);
|
||||
|
||||
//a check on mount and after a fetch to see if the table is already scrolled to the bottom and immediately needs to fetch more data
|
||||
React.useEffect(() => {
|
||||
fetchMoreOnBottomReached(tableRef.current);
|
||||
}, [fetchMoreOnBottomReached]);
|
||||
|
||||
const table = useReactTable({
|
||||
columns: finalColumns,
|
||||
|
||||
Reference in New Issue
Block a user