FE: Design update for log context tab (#4601)

* refactor: initial setup for context view

* refactor: updated design for log context view

* refactor: updated comments and remove commented code

* refactor: updated comments

* refactor: handle hight issue

* refactor: initial setup for context view

* refactor: updated design for log context view

* refactor: updated comments and remove commented code

* refactor: updated comments

* refactor: handle hight issue

* refactor: added api version

* refactor: height set to parent height and remove unnessarry code

* refactor: removed commented code

---------

Co-authored-by: Yunus M <myounis.ar@live.com>
This commit is contained in:
Rajat Dabade 2024-03-13 17:37:48 +05:30 committed by GitHub
parent 3c419677e1
commit 44dc55c5ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 348 additions and 23 deletions

View File

@ -18,6 +18,8 @@
}
.ant-drawer-body {
display: flex;
flex-direction: column;
padding: 16px;
}

View File

@ -163,7 +163,11 @@ function RawLogView({
>
<LogStateIndicator
type={logType}
isActive={activeLog?.id === data.id || activeContextLog?.id === data.id}
isActive={
activeLog?.id === data.id ||
activeContextLog?.id === data.id ||
isActiveLog
}
/>
<RawLogContent

View File

@ -0,0 +1,25 @@
.context-log-renderer {
.virtuoso-list {
overflow-y: hidden !important;
&::-webkit-scrollbar {
width: 0.3rem;
height: 0.3rem;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--bg-slate-300);
}
&::-webkit-scrollbar-thumb:hover {
background: var(--bg-slate-200);
}
.ant-row {
width: fit-content;
}
}
}

View File

@ -0,0 +1,129 @@
import './ContextLogRenderer.styles.scss';
import { Skeleton } from 'antd';
import RawLogView from 'components/Logs/RawLogView';
import ShowButton from 'container/LogsContextList/ShowButton';
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
import { useCallback, useEffect, useState } from 'react';
import { Virtuoso } from 'react-virtuoso';
import { ILog } from 'types/api/logs/log';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { useContextLogData } from './useContextLogData';
function ContextLogRenderer({
isEdit,
query,
log,
filters,
}: ContextLogRendererProps): JSX.Element {
const [prevLogPage, setPrevLogPage] = useState<number>(1);
const [afterLogPage, setAfterLogPage] = useState<number>(1);
const [logs, setLogs] = useState<ILog[]>([log]);
const {
logs: previousLogs,
isFetching: isPreviousLogsFetching,
handleShowNextLines: handlePreviousLogsShowNextLine,
} = useContextLogData({
log,
filters,
isEdit,
query,
order: ORDERBY_FILTERS.ASC,
page: prevLogPage,
setPage: setPrevLogPage,
});
const {
logs: afterLogs,
isFetching: isAfterLogsFetching,
handleShowNextLines: handleAfterLogsShowNextLine,
} = useContextLogData({
log,
filters,
isEdit,
query,
order: ORDERBY_FILTERS.DESC,
page: afterLogPage,
setPage: setAfterLogPage,
});
useEffect(() => {
setLogs((prev) => [...previousLogs, ...prev]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [previousLogs]);
useEffect(() => {
setLogs((prev) => [...prev, ...afterLogs]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [afterLogs]);
useEffect(() => {
setLogs([log]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filters]);
const getItemContent = useCallback(
(_: number, logTorender: ILog): JSX.Element => (
<RawLogView
isActiveLog={logTorender.id === log.id}
isReadOnly
isTextOverflowEllipsisDisabled
key={logTorender.id}
data={logTorender}
linesPerRow={1}
/>
),
[log.id],
);
return (
<div className="context-log-renderer">
<ShowButton
isLoading={isPreviousLogsFetching}
isDisabled={false}
order={ORDERBY_FILTERS.ASC}
onClick={handlePreviousLogsShowNextLine}
/>
{isPreviousLogsFetching && (
<Skeleton
style={{
height: '100%',
padding: '16px',
}}
/>
)}
<Virtuoso
className="virtuoso-list"
initialTopMostItemIndex={0}
data={logs}
itemContent={getItemContent}
style={{ height: `calc(${logs.length} * 32px)` }}
/>
{isAfterLogsFetching && (
<Skeleton
style={{
height: '100%',
padding: '16px',
}}
/>
)}
<ShowButton
isLoading={isAfterLogsFetching}
isDisabled={false}
order={ORDERBY_FILTERS.DESC}
onClick={handleAfterLogsShowNextLine}
/>
</div>
);
}
interface ContextLogRendererProps {
isEdit: boolean;
query: Query;
log: ILog;
filters: TagFilter | null;
}
export default ContextLogRenderer;

View File

@ -1,3 +1,23 @@
.log-context-container {
border: 1px solid var(--bg-slate-400);
}
flex: 1;
position: relative;
overflow: scroll;
overflow-x: hidden;
&::-webkit-scrollbar {
width: 0.3rem;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: var(--bg-slate-300);
}
&::-webkit-scrollbar-thumb:hover {
background: var(--bg-slate-200);
}
}

View File

@ -1,11 +1,10 @@
import './ContextView.styles.scss';
import RawLogView from 'components/Logs/RawLogView';
import LogsContextList from 'container/LogsContextList';
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
import { ILog } from 'types/api/logs/log';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import ContextLogRenderer from './ContextLogRenderer';
interface LogContextProps {
log: ILog;
contextQuery: Query | undefined;
@ -24,28 +23,11 @@ function ContextView({
return (
<div className="log-context-container">
<LogsContextList
className="logs-context-list-asc"
order={ORDERBY_FILTERS.ASC}
<ContextLogRenderer
filters={filters}
isEdit={isEdit}
log={log}
query={contextQuery}
/>
<RawLogView
isActiveLog
isReadOnly
isTextOverflowEllipsisDisabled={false}
data={log}
linesPerRow={1}
/>
<LogsContextList
className="logs-context-list-desc"
order={ORDERBY_FILTERS.DESC}
filters={filters}
isEdit={isEdit}
log={log}
query={contextQuery}
/>
</div>
);

View File

@ -0,0 +1,163 @@
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
import { PANEL_TYPES } from 'constants/queryBuilder';
import {
getOrderByTimestamp,
INITIAL_PAGE_SIZE,
LOGS_MORE_PAGE_SIZE,
} from 'container/LogsContextList/configs';
import { getRequestData } from 'container/LogsContextList/utils';
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQueryRange';
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { SuccessResponse } from 'types/api';
import { ILog } from 'types/api/logs/log';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
export const useContextLogData = ({
log,
query,
order,
isEdit,
filters,
page,
setPage,
}: {
log: ILog;
query: Query;
order: string;
isEdit: boolean;
filters: TagFilter | null;
page: number;
setPage: Dispatch<SetStateAction<number>>;
}): {
logs: ILog[];
handleShowNextLines: () => void;
isError: boolean;
isFetching: boolean;
isDisabledFetch: boolean;
} => {
const [logs, setLogs] = useState<ILog[]>([]);
const orderByTimestamp = useMemo(() => getOrderByTimestamp(order), [order]);
const logsMorePageSize = useMemo(() => (page - 1) * LOGS_MORE_PAGE_SIZE, [
page,
]);
const pageSize = useMemo(
() => (page <= 1 ? INITIAL_PAGE_SIZE : logsMorePageSize + INITIAL_PAGE_SIZE),
[page, logsMorePageSize],
);
const isDisabledFetch = useMemo(() => logs.length < pageSize, [
logs.length,
pageSize,
]);
const currentStagedQueryData = useMemo(() => {
if (!query || query.builder.queryData.length !== 1) return null;
return query.builder.queryData[0];
}, [query]);
const initialLogsRequest = useMemo(
() =>
getRequestData({
stagedQueryData: currentStagedQueryData,
query,
log,
orderByTimestamp,
page,
}),
[currentStagedQueryData, page, log, query, orderByTimestamp],
);
const [requestData, setRequestData] = useState<Query | null>(
initialLogsRequest,
);
const handleSuccess = useCallback(
(data: SuccessResponse<MetricRangePayloadProps, unknown>) => {
const currentData = data?.payload.data.newResult.data.result || [];
if (currentData.length > 0 && currentData[0].list) {
const currentLogs: ILog[] = currentData[0].list.map((item) => ({
...item.data,
timestamp: item.timestamp,
}));
if (order === ORDERBY_FILTERS.ASC) {
const reversedCurrentLogs = currentLogs.reverse();
setLogs([...reversedCurrentLogs]);
} else {
setLogs([...currentLogs]);
}
}
},
[order],
);
const { isError, isFetching } = useGetExplorerQueryRange(
requestData,
PANEL_TYPES.LIST,
DEFAULT_ENTITY_VERSION,
{
keepPreviousData: true,
enabled: !!requestData,
onSuccess: handleSuccess,
},
);
const handleShowNextLines = useCallback(() => {
const newRequestData = getRequestData({
stagedQueryData: currentStagedQueryData,
query,
log,
orderByTimestamp,
page: page + 1,
pageSize: LOGS_MORE_PAGE_SIZE,
});
setPage((prevPage) => prevPage + 1);
setRequestData(newRequestData);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
query,
page,
order,
currentStagedQueryData,
isDisabledFetch,
orderByTimestamp,
]);
useEffect(() => {
if (!isEdit) return;
const newRequestData = getRequestData({
stagedQueryData: currentStagedQueryData,
query,
log,
orderByTimestamp,
page: 1,
});
setPage(1);
setLogs([]);
setRequestData(newRequestData);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filters]);
return {
logs,
handleShowNextLines,
isError,
isFetching,
isDisabledFetch,
};
};