diff --git a/package.json b/package.json index 64997678..161efca0 100644 --- a/package.json +++ b/package.json @@ -1,87 +1,87 @@ { - "name": "parseable-console", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --host --port 3001", - "build": "tsc && vite build", - "build:test": "tsc && vite build --mode test", - "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "start": "vite preview --host --port 3002", - "tsCheck": "tsc --noEmit", - "pq": "pretty-quick" - }, - "dependencies": { - "@apache-arrow/ts": "^14.0.2", - "@emotion/react": "^11.11.1", - "@mantine/carousel": "^7.8.1", - "@mantine/charts": "^7.8.1", - "@mantine/code-highlight": "^7.8.1", - "@mantine/core": "^7.8.1", - "@mantine/dates": "^7.8.1", - "@mantine/form": "^7.8.1", - "@mantine/hooks": "^7.8.1", - "@mantine/notifications": "^7.8.1", - "@monaco-editor/react": "^4.5.1", - "@tabler/icons-react": "^3.3.0", - "@types/js-cookie": "^3.0.3", - "axios": "^1.4.0", - "dayjs": "^1.11.10", - "embla-carousel-react": "7.1.0", - "html2canvas": "^1.4.1", - "http-status-codes": "^2.2.0", - "immer": "^10.0.2", - "jq-web": "^0.5.1", - "js-cookie": "^3.0.5", - "just-compare": "^2.3.0", - "lodash": "^4.17.21", - "long": "^5.2.3", - "mantine-react-table": "2.0.0-beta.6", - "moment-timezone": "^0.5.45", - "ms": "^2.1.3", - "nice-grpc-common": "^2.0.2", - "nice-grpc-web": "^3.3.2", - "protobufjs": "^7.2.5", - "react": "^18.2.0", - "react-beautiful-dnd": "^13.1.1", - "react-dom": "^18.2.0", - "react-error-boundary": "^4.0.10", - "react-grid-layout": "^1.4.4", - "react-query": "^3.39.3", - "react-querybuilder": "^6.5.5", - "react-resizable": "^3.0.5", - "react-resizable-panels": "^0.0.53", - "react-router-dom": "^6.14.0", - "react-window": "^1.8.9" - }, - "devDependencies": { - "@playwright/test": "^1.48.2", - "@types/lodash": "^4.17.0", - "@types/ms": "^0.7.31", - "@types/node": "^20.3.2", - "@types/react": "^18.2.14", - "@types/react-beautiful-dnd": "^13.1.4", - "@types/react-dom": "^18.2.6", - "@types/react-grid-layout": "^1.3.5", - "@types/react-resizable": "^3.0.8", - "@types/react-window": "^1.8.5", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "@vitejs/plugin-react-swc": "^3.3.2", - "eslint": "^8.43.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.1", - "postcss": "^8.4.33", - "postcss-preset-mantine": "^1.13.0", - "postcss-simple-vars": "^7.0.1", - "prettier": "^2.8.8", - "pretty-quick": "^3.1.3", - "typescript": "^5.1.6", - "vite": "^4.3.9" - } + "name": "parseable-console", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --host --port 3001", + "build": "tsc && vite build", + "build:test": "tsc && vite build --mode test", + "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "start": "vite preview --host --port 3002", + "tsCheck": "tsc --noEmit", + "pq": "pretty-quick" + }, + "dependencies": { + "@apache-arrow/ts": "^14.0.2", + "@emotion/react": "^11.11.1", + "@mantine/carousel": "^7.8.1", + "@mantine/charts": "^7.8.1", + "@mantine/code-highlight": "^7.8.1", + "@mantine/core": "^7.8.1", + "@mantine/dates": "^7.8.1", + "@mantine/form": "^7.8.1", + "@mantine/hooks": "^7.8.1", + "@mantine/notifications": "^7.8.1", + "@monaco-editor/react": "^4.5.1", + "@tabler/icons-react": "^3.3.0", + "@types/js-cookie": "^3.0.3", + "axios": "^1.4.0", + "dayjs": "^1.11.10", + "embla-carousel-react": "7.1.0", + "html2canvas": "^1.4.1", + "http-status-codes": "^2.2.0", + "immer": "^10.0.2", + "jq-web": "^0.5.1", + "js-cookie": "^3.0.5", + "just-compare": "^2.3.0", + "lodash": "^4.17.21", + "long": "^5.2.3", + "mantine-react-table": "2.0.0-beta.6", + "moment-timezone": "^0.5.45", + "ms": "^2.1.3", + "nice-grpc-common": "^2.0.2", + "nice-grpc-web": "^3.3.2", + "protobufjs": "^7.2.5", + "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", + "react-dom": "^18.2.0", + "react-error-boundary": "^4.0.10", + "react-grid-layout": "^1.4.4", + "react-query": "^3.39.3", + "react-querybuilder": "^6.5.5", + "react-resizable": "^3.0.5", + "react-resizable-panels": "^0.0.53", + "react-router-dom": "^6.14.0", + "react-window": "^1.8.9" + }, + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/lodash": "^4.17.0", + "@types/ms": "^0.7.31", + "@types/node": "^20.3.2", + "@types/react": "^18.2.14", + "@types/react-beautiful-dnd": "^13.1.4", + "@types/react-dom": "^18.2.6", + "@types/react-grid-layout": "^1.3.5", + "@types/react-resizable": "^3.0.8", + "@types/react-window": "^1.8.5", + "@typescript-eslint/eslint-plugin": "^5.60.1", + "@typescript-eslint/parser": "^5.60.1", + "@vitejs/plugin-react-swc": "^3.3.2", + "eslint": "^8.43.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.1", + "postcss": "^8.4.33", + "postcss-preset-mantine": "^1.13.0", + "postcss-simple-vars": "^7.0.1", + "prettier": "^2.8.8", + "pretty-quick": "^3.1.3", + "typescript": "^5.1.6", + "vite": "^4.3.9" + } } diff --git a/src/hooks/useQueryLogs.ts b/src/hooks/useQueryLogs.ts index 75ccdcfd..a931c84b 100644 --- a/src/hooks/useQueryLogs.ts +++ b/src/hooks/useQueryLogs.ts @@ -2,6 +2,7 @@ import { SortOrder, type Log, type LogsData, type LogsSearch } from '@/@types/pa import { getQueryLogsWithHeaders, getQueryResultWithHeaders } from '@/api/query'; import { StatusCodes } from 'http-status-codes'; import useMountedState from './useMountedState'; +import { useQuery } from 'react-query'; import { useCallback, useRef } from 'react'; import { useLogsStore, logsStoreReducers, LOAD_LIMIT, isJqSearch } from '@/pages/Stream/providers/LogsProvider'; import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider'; @@ -25,7 +26,6 @@ export const useQueryLogs = () => { // Only mutate it when data is fetched, otherwise read only const _dataRef = useRef(null); const [error, setError] = useMountedState(null); - const [loading, setLoading] = useMountedState(false); const [pageLogData, setPageLogData] = useMountedState(null); const [querySearch, setQuerySearch] = useMountedState({ search: '', @@ -81,45 +81,50 @@ export const useQueryLogs = () => { pageOffset: currentOffset, timePartitionColumn, }; - const getQueryData = async () => { - try { - setLoading(true); - setError(null); - refetchSchema(); // fetch schema parallelly every time we fetch logs - const logsQueryRes = await (async () => { - if (isQuerySearchActive) { - if (activeMode === 'filters') { - const { parsedQuery } = parseQuery(queryEngine, appliedQuery, currentStream || '', { - startTime: timeRange.startTime, - endTime: timeRange.endTime, - timePartitionColumn, - }); - const queryStrWithOffset = appendOffsetToQuery(parsedQuery, defaultQueryOpts.pageOffset); - return await getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset); - } else { - const queryStrWithOffset = appendOffsetToQuery(custSearchQuery, defaultQueryOpts.pageOffset); - return await getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset); - } + + const { + isLoading: logsLoading, + isRefetching: logsRefetching, + refetch: getQueryData, + } = useQuery( + ['fetch-logs', defaultQueryOpts], + () => { + refetchSchema(); + if (isQuerySearchActive) { + if (activeMode === 'filters') { + const { parsedQuery } = parseQuery(queryEngine, appliedQuery, currentStream || '', { + startTime: timeRange.startTime, + endTime: timeRange.endTime, + timePartitionColumn, + }); + const queryStrWithOffset = appendOffsetToQuery(parsedQuery, defaultQueryOpts.pageOffset); + return getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset); } else { - return await getQueryLogsWithHeaders(defaultQueryOpts); + const queryStrWithOffset = appendOffsetToQuery(custSearchQuery, defaultQueryOpts.pageOffset); + return getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset); } - })(); - const logs = logsQueryRes.data; - const isInvalidResponse = _.isEmpty(logs) || _.isNil(logs) || logsQueryRes.status !== StatusCodes.OK; - if (isInvalidResponse) return setError('Failed to query log'); + } else { + return getQueryLogsWithHeaders(defaultQueryOpts); + } + }, + { + enabled: false, + refetchOnWindowFocus: false, + onSuccess: async (data) => { + const logs = data.data; + const isInvalidResponse = _.isEmpty(logs) || _.isNil(logs) || data.status !== StatusCodes.OK; + if (isInvalidResponse) return setError('Failed to query logs'); - const { records, fields } = logs; - const jqFilteredData = isJqSearch(instantSearchValue) ? await jqSearch(records, instantSearchValue) : []; - return setLogsStore((store) => setLogData(store, records, fields, jqFilteredData)); - } catch (e) { - const axiosError = e as AxiosError; - const errorMessage = axiosError?.response?.data; - setError(_.isString(errorMessage) && !_.isEmpty(errorMessage) ? errorMessage : 'Failed to query log'); - return setLogsStore((store) => setLogData(store, [], [])); - } finally { - setLoading(false); - } - }; + const { records, fields } = logs; + const jqFilteredData = isJqSearch(instantSearchValue) ? await jqSearch(records, instantSearchValue) : []; + setLogsStore((store) => setLogData(store, records, fields, jqFilteredData)); + }, + onError: (data: AxiosError) => { + const errorMessage = data.response?.data as string; + setError(_.isString(errorMessage) && !_.isEmpty(errorMessage) ? errorMessage : 'Failed to query logs'); + }, + }, + ); const resetData = () => { _dataRef.current = null; @@ -133,7 +138,7 @@ export const useQueryLogs = () => { getColumnFilters, sort: querySearch.sort, error, - loading: loading, + loading: logsLoading || logsRefetching, getQueryData, resetData, }; diff --git a/src/pages/Stream/Views/Explore/LogsView.tsx b/src/pages/Stream/Views/Explore/LogsView.tsx index 056370e0..dd765123 100644 --- a/src/pages/Stream/Views/Explore/LogsView.tsx +++ b/src/pages/Stream/Views/Explore/LogsView.tsx @@ -4,6 +4,7 @@ import JsonView from './JSONView'; import LogTable from './StaticLogTable'; import useLogsFetcher from './useLogsFetcher'; import LogsViewConfig from './LogsViewConfig'; +import _ from 'lodash'; const LogsView = (props: { schemaLoading: boolean; infoLoading: boolean }) => { const { schemaLoading, infoLoading } = props; @@ -11,6 +12,7 @@ const LogsView = (props: { schemaLoading: boolean; infoLoading: boolean }) => { schemaLoading, infoLoading, }); + const [viewMode] = useLogsStore((store) => store.viewMode); const viewOpts = { errorMessage, diff --git a/src/pages/Stream/hooks/useParamsController.ts b/src/pages/Stream/hooks/useParamsController.ts index c90d96c7..8e36d66d 100644 --- a/src/pages/Stream/hooks/useParamsController.ts +++ b/src/pages/Stream/hooks/useParamsController.ts @@ -3,6 +3,7 @@ import { TimeRange, useLogsStore, logsStoreReducers } from '@/pages/Stream/provi import { useSearchParams } from 'react-router-dom'; import _ from 'lodash'; import { FIXED_DURATIONS } from '@/constants/timeConstants'; +import { LOG_QUERY_LIMITS } from '@/pages/Stream/providers/LogsProvider'; import dayjs from 'dayjs'; import timeRangeUtils from '@/utils/timeRangeUtils'; import moment from 'moment-timezone'; @@ -14,7 +15,6 @@ const { setTimeRange, onToggleView, setPerPage, setCustQuerySearchState } = logs const { applySavedFilters } = filterStoreReducers; const timeRangeFormat = 'DD-MMM-YYYY_HH-mmz'; const keys = ['view', 'rows', 'interval', 'from', 'to', 'query', 'filterType']; -const FIXED_ROWS = ['50', '100', '150', '200']; const dateToParamString = (date: Date) => { return formatDateWithTimezone(date, timeRangeFormat); @@ -109,7 +109,7 @@ const useParamsController = () => { if (['table', 'json'].includes(presentParams.view) && presentParams.view !== storeAsParams.view) { setLogsStore((store) => onToggleView(store, presentParams.view as 'table' | 'json')); } - if (storeAsParams.rows !== presentParams.rows && FIXED_ROWS.includes(presentParams.rows)) { + if (storeAsParams.rows !== presentParams.rows && LOG_QUERY_LIMITS.includes(_.toNumber(presentParams.rows))) { setLogsStore((store) => setPerPage(store, _.toNumber(presentParams.rows))); } @@ -161,7 +161,7 @@ const useParamsController = () => { if (presentParams.view && presentParams.view !== storeAsParams.view) { setLogsStore((store) => onToggleView(store, presentParams.view as 'table' | 'json')); } - if (storeAsParams.rows !== presentParams.rows && FIXED_ROWS.includes(presentParams.rows)) { + if (storeAsParams.rows !== presentParams.rows && LOG_QUERY_LIMITS.includes(_.toNumber(presentParams.rows))) { setLogsStore((store) => setPerPage(store, _.toNumber(presentParams.rows))); }