mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-25 11:30:08 +00:00
* feat: create live logs page and custom top nav * fix: success button color * fix: turn back color * feat: add live logs where clause (#3325) * feat: add live logs where clause * fix: undefined scenario * feat: get live data (#3337) * feat: get live data * fix: change color, change number format * chore: useMemo is updated * feat: add live logs list (#3341) * feat: add live logs list * feat: hide view if error, clear logs * feat: add condition for disable initial loading * fix: double request * fix: render id in the where clause * fix: render where clause and live list * fix: last log padding * fix: list data loading * fix: no logs text * fix: logs list size * fix: small issues * fix: render view with memo --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> * fix: build is fixed --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com> Co-authored-by: Yunus M <myounis.ar@live.com>
163 lines
4.4 KiB
TypeScript
163 lines
4.4 KiB
TypeScript
import { apiV3 } from 'api/apiV1';
|
|
import { ENVIRONMENT } from 'constants/env';
|
|
import { LIVE_TAIL_HEARTBEAT_TIMEOUT } from 'constants/liveTail';
|
|
import { EventListener, EventSourcePolyfill } from 'event-source-polyfill';
|
|
import {
|
|
createContext,
|
|
PropsWithChildren,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
import { useSelector } from 'react-redux';
|
|
import { AppState } from 'store/reducers';
|
|
import AppReducer from 'types/reducer/app';
|
|
|
|
interface IEventSourceContext {
|
|
eventSourceInstance: EventSourcePolyfill | null;
|
|
isConnectionOpen: boolean;
|
|
isConnectionLoading: boolean;
|
|
isConnectionError: boolean;
|
|
initialLoading: boolean;
|
|
handleStartOpenConnection: (urlProps: {
|
|
url?: string;
|
|
queryString: string;
|
|
}) => void;
|
|
handleCloseConnection: () => void;
|
|
handleSetInitialLoading: (value: boolean) => void;
|
|
}
|
|
|
|
const EventSourceContext = createContext<IEventSourceContext>({
|
|
eventSourceInstance: null,
|
|
isConnectionOpen: false,
|
|
isConnectionLoading: false,
|
|
initialLoading: true,
|
|
isConnectionError: false,
|
|
handleStartOpenConnection: () => {},
|
|
handleCloseConnection: () => {},
|
|
handleSetInitialLoading: () => {},
|
|
});
|
|
|
|
export function EventSourceProvider({
|
|
children,
|
|
}: PropsWithChildren): JSX.Element {
|
|
const [isConnectionOpen, setIsConnectionOpen] = useState<boolean>(false);
|
|
const [isConnectionLoading, setIsConnectionLoading] = useState<boolean>(false);
|
|
const [isConnectionError, setIsConnectionError] = useState<boolean>(false);
|
|
|
|
const [initialLoading, setInitialLoading] = useState<boolean>(true);
|
|
|
|
const { user } = useSelector<AppState, AppReducer>((state) => state.app);
|
|
|
|
const eventSourceRef = useRef<EventSourcePolyfill | null>(null);
|
|
|
|
const handleSetInitialLoading = useCallback((value: boolean) => {
|
|
setInitialLoading(value);
|
|
}, []);
|
|
|
|
const handleOpenConnection: EventListener = useCallback(() => {
|
|
setIsConnectionLoading(false);
|
|
setIsConnectionOpen(true);
|
|
setInitialLoading(false);
|
|
}, []);
|
|
|
|
const handleErrorConnection: EventListener = useCallback(() => {
|
|
setIsConnectionOpen(false);
|
|
setIsConnectionLoading(false);
|
|
setIsConnectionError(true);
|
|
setInitialLoading(false);
|
|
|
|
if (!eventSourceRef.current) return;
|
|
|
|
eventSourceRef.current.close();
|
|
}, []);
|
|
|
|
const destroyEventSourceSession = useCallback(() => {
|
|
if (!eventSourceRef.current) return;
|
|
|
|
eventSourceRef.current.close();
|
|
eventSourceRef.current.removeEventListener('error', handleErrorConnection);
|
|
eventSourceRef.current.removeEventListener('open', handleOpenConnection);
|
|
}, [handleErrorConnection, handleOpenConnection]);
|
|
|
|
const handleCloseConnection = useCallback(() => {
|
|
setIsConnectionOpen(false);
|
|
setIsConnectionLoading(false);
|
|
setIsConnectionError(false);
|
|
|
|
destroyEventSourceSession();
|
|
}, [destroyEventSourceSession]);
|
|
|
|
const handleStartOpenConnection = useCallback(
|
|
(urlProps: { url?: string; queryString: string }): void => {
|
|
const { url, queryString } = urlProps;
|
|
|
|
const eventSourceUrl = url
|
|
? `${url}/?${queryString}`
|
|
: `${ENVIRONMENT.baseURL}${apiV3}logs/livetail?${queryString}`;
|
|
|
|
eventSourceRef.current = new EventSourcePolyfill(eventSourceUrl, {
|
|
headers: {
|
|
Authorization: `Bearer ${user?.accessJwt}`,
|
|
},
|
|
heartbeatTimeout: LIVE_TAIL_HEARTBEAT_TIMEOUT,
|
|
});
|
|
|
|
setIsConnectionLoading(true);
|
|
setIsConnectionError(false);
|
|
|
|
eventSourceRef.current.addEventListener('error', handleErrorConnection);
|
|
eventSourceRef.current.addEventListener('open', handleOpenConnection);
|
|
},
|
|
[user, handleErrorConnection, handleOpenConnection],
|
|
);
|
|
|
|
useEffect(
|
|
() => (): void => {
|
|
handleCloseConnection();
|
|
},
|
|
[handleCloseConnection],
|
|
);
|
|
|
|
const contextValue: IEventSourceContext = useMemo(
|
|
() => ({
|
|
eventSourceInstance: eventSourceRef.current,
|
|
isConnectionError,
|
|
isConnectionLoading,
|
|
isConnectionOpen,
|
|
initialLoading,
|
|
handleStartOpenConnection,
|
|
handleCloseConnection,
|
|
handleSetInitialLoading,
|
|
}),
|
|
[
|
|
isConnectionError,
|
|
isConnectionLoading,
|
|
isConnectionOpen,
|
|
initialLoading,
|
|
handleStartOpenConnection,
|
|
handleCloseConnection,
|
|
handleSetInitialLoading,
|
|
],
|
|
);
|
|
|
|
return (
|
|
<EventSourceContext.Provider value={contextValue}>
|
|
{children}
|
|
</EventSourceContext.Provider>
|
|
);
|
|
}
|
|
|
|
export const useEventSource = (): IEventSourceContext => {
|
|
const context = useContext(EventSourceContext);
|
|
|
|
if (!context) {
|
|
throw new Error('Should be used inside the context');
|
|
}
|
|
|
|
return context;
|
|
};
|