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.pull/7685/head
parent
6b012193e3
commit
b303693ae8
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue