+
{data?.message === errorMessageReceivedFromBackend
@@ -84,10 +87,12 @@ function EditRules(): JSX.Element {
}
return (
-
+
+
+
);
}
diff --git a/frontend/src/pages/LogsExplorer/LogsExplorer.styles.scss b/frontend/src/pages/LogsExplorer/LogsExplorer.styles.scss
index 95d53fe9a4..82d3f5bffc 100644
--- a/frontend/src/pages/LogsExplorer/LogsExplorer.styles.scss
+++ b/frontend/src/pages/LogsExplorer/LogsExplorer.styles.scss
@@ -1,11 +1,35 @@
-.log-explorer-query-container {
- display: flex;
- flex-direction: column;
- flex: 1;
-
- .logs-explorer-views {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
-}
\ No newline at end of file
+.logs-module-page {
+ display: flex;
+ height: 100%;
+ .log-quick-filter-left-section {
+ width: 0%;
+ flex-shrink: 0;
+ }
+
+ .log-module-right-section {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ .log-explorer-query-container {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+
+ .logs-explorer-views {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+ }
+ }
+
+ &.filter-visible {
+ .log-quick-filter-left-section {
+ width: 260px;
+ }
+
+ .log-module-right-section {
+ width: calc(100% - 260px);
+ }
+ }
+}
diff --git a/frontend/src/pages/LogsExplorer/__tests__/LogsExplorer.test.tsx b/frontend/src/pages/LogsExplorer/__tests__/LogsExplorer.test.tsx
index fab08d51a8..4970d6cf17 100644
--- a/frontend/src/pages/LogsExplorer/__tests__/LogsExplorer.test.tsx
+++ b/frontend/src/pages/LogsExplorer/__tests__/LogsExplorer.test.tsx
@@ -189,6 +189,8 @@ describe('Logs Explorer Tests', () => {
initialDataSource: null,
panelType: PANEL_TYPES.TIME_SERIES,
isEnabledQuery: false,
+ lastUsedQuery: 0,
+ setLastUsedQuery: noop,
handleSetQueryData: noop,
handleSetFormulaData: noop,
handleSetQueryItemData: noop,
diff --git a/frontend/src/pages/LogsExplorer/index.tsx b/frontend/src/pages/LogsExplorer/index.tsx
index 8873d04e39..9e23b34c2c 100644
--- a/frontend/src/pages/LogsExplorer/index.tsx
+++ b/frontend/src/pages/LogsExplorer/index.tsx
@@ -1,25 +1,40 @@
import './LogsExplorer.styles.scss';
import * as Sentry from '@sentry/react';
+import getLocalStorageKey from 'api/browser/localstorage/get';
+import setLocalStorageApi from 'api/browser/localstorage/set';
+import cx from 'classnames';
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
+import QuickFilters from 'components/QuickFilters/QuickFilters';
+import { LOCALSTORAGE } from 'constants/localStorage';
import LogExplorerQuerySection from 'container/LogExplorerQuerySection';
import LogsExplorerViews from 'container/LogsExplorerViews';
import LeftToolbarActions from 'container/QueryBuilder/components/ToolbarActions/LeftToolbarActions';
import RightToolbarActions from 'container/QueryBuilder/components/ToolbarActions/RightToolbarActions';
import Toolbar from 'container/Toolbar/Toolbar';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
+import { isNull } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { useEffect, useMemo, useRef, useState } from 'react';
import { DataSource } from 'types/common/queryBuilder';
import { WrapperStyled } from './styles';
-import { SELECTED_VIEWS } from './utils';
+import { LogsQuickFiltersConfig, SELECTED_VIEWS } from './utils';
function LogsExplorer(): JSX.Element {
const [showFrequencyChart, setShowFrequencyChart] = useState(true);
const [selectedView, setSelectedView] = useState(
SELECTED_VIEWS.SEARCH,
);
+ const [showFilters, setShowFilters] = useState(() => {
+ const localStorageValue = getLocalStorageKey(
+ LOCALSTORAGE.SHOW_LOGS_QUICK_FILTERS,
+ );
+ if (!isNull(localStorageValue)) {
+ return localStorageValue === 'true';
+ }
+ return true;
+ });
const { handleRunQuery, currentQuery } = useQueryBuilder();
@@ -37,6 +52,14 @@ function LogsExplorer(): JSX.Element {
setSelectedView(view);
};
+ const handleFilterVisibilityChange = (): void => {
+ setLocalStorageApi(
+ LOCALSTORAGE.SHOW_LOGS_QUICK_FILTERS,
+ String(!showFilters),
+ );
+ setShowFilters((prev) => !prev);
+ };
+
// Switch to query builder view if there are more than 1 queries
useEffect(() => {
if (currentQuery.builder.queryData.length > 1) {
@@ -90,46 +113,60 @@ function LogsExplorer(): JSX.Element {
return (
}>
-
- }
- rightActions={
-
- }
- showOldCTA
- />
-
-
-
-
-
-
-
-
-
-
+ {showFilters && (
+
-
-
+
+ )}
+
+
+ }
+ rightActions={
+
+ }
+ showOldCTA
+ />
+
+
+
+
+
+
);
}
diff --git a/frontend/src/pages/LogsExplorer/utils.ts b/frontend/src/pages/LogsExplorer/utils.ts
deleted file mode 100644
index 0fedaaece4..0000000000
--- a/frontend/src/pages/LogsExplorer/utils.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Query } from 'types/api/queryBuilder/queryBuilderData';
-
-export const prepareQueryWithDefaultTimestamp = (query: Query): Query => ({
- ...query,
- builder: {
- ...query.builder,
- queryData: query.builder.queryData?.map((item) => ({
- ...item,
- orderBy: [{ columnName: 'timestamp', order: 'desc' }],
- })),
- },
-});
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-export enum SELECTED_VIEWS {
- SEARCH = 'search',
- QUERY_BUILDER = 'query-builder',
- CLICKHOUSE = 'clickhouse',
-}
diff --git a/frontend/src/pages/LogsExplorer/utils.tsx b/frontend/src/pages/LogsExplorer/utils.tsx
new file mode 100644
index 0000000000..7a197bd467
--- /dev/null
+++ b/frontend/src/pages/LogsExplorer/utils.tsx
@@ -0,0 +1,113 @@
+import {
+ FiltersType,
+ IQuickFiltersConfig,
+} from 'components/QuickFilters/QuickFilters';
+import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
+import { Query } from 'types/api/queryBuilder/queryBuilderData';
+
+export const prepareQueryWithDefaultTimestamp = (query: Query): Query => ({
+ ...query,
+ builder: {
+ ...query.builder,
+ queryData: query.builder.queryData?.map((item) => ({
+ ...item,
+ orderBy: [{ columnName: 'timestamp', order: 'desc' }],
+ })),
+ },
+});
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export enum SELECTED_VIEWS {
+ SEARCH = 'search',
+ QUERY_BUILDER = 'query-builder',
+ CLICKHOUSE = 'clickhouse',
+}
+
+export const LogsQuickFiltersConfig: IQuickFiltersConfig[] = [
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'Severity Text',
+ attributeKey: {
+ key: 'severity_text',
+ dataType: DataTypes.String,
+ type: '',
+ isColumn: true,
+ isJSON: false,
+ id: 'severity_text--string----true',
+ },
+ defaultOpen: true,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'Environment',
+ attributeKey: {
+ key: 'deployment.environment',
+ dataType: DataTypes.String,
+ type: 'resource',
+ isColumn: false,
+ isJSON: false,
+ },
+ defaultOpen: false,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'Service Name',
+ attributeKey: {
+ key: 'service.name',
+ dataType: DataTypes.String,
+ type: 'resource',
+ isColumn: true,
+ isJSON: false,
+ id: 'service.name--string--resource--true',
+ },
+ defaultOpen: false,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'Hostname',
+ attributeKey: {
+ key: 'hostname',
+ dataType: DataTypes.String,
+ type: 'tag',
+ isColumn: false,
+ isJSON: false,
+ },
+ defaultOpen: false,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'K8s Cluster Name',
+ attributeKey: {
+ key: 'k8s.cluster.name',
+ dataType: DataTypes.String,
+ type: 'resource',
+ isColumn: false,
+ isJSON: false,
+ },
+ defaultOpen: false,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'K8s Deployment Name',
+ attributeKey: {
+ key: 'k8s.deployment.name',
+ dataType: DataTypes.String,
+ type: 'resource',
+ isColumn: false,
+ isJSON: false,
+ },
+ defaultOpen: false,
+ },
+ {
+ type: FiltersType.CHECKBOX,
+ title: 'K8s Namespace Name',
+ attributeKey: {
+ key: 'k8s.namespace.name',
+ dataType: DataTypes.String,
+ type: 'resource',
+ isColumn: true,
+ isJSON: false,
+ },
+ defaultOpen: false,
+ },
+];
diff --git a/frontend/src/pages/TracesExplorer/__test__/TracesExplorer.test.tsx b/frontend/src/pages/TracesExplorer/__test__/TracesExplorer.test.tsx
index a28776f0d0..4a3fa8018e 100644
--- a/frontend/src/pages/TracesExplorer/__test__/TracesExplorer.test.tsx
+++ b/frontend/src/pages/TracesExplorer/__test__/TracesExplorer.test.tsx
@@ -77,6 +77,14 @@ jest.mock(
},
);
+window.ResizeObserver =
+ window.ResizeObserver ||
+ jest.fn().mockImplementation(() => ({
+ disconnect: jest.fn(),
+ observe: jest.fn(),
+ unobserve: jest.fn(),
+ }));
+
const successNotification = jest.fn();
jest.mock('hooks/useNotifications', () => ({
__esModule: true,
diff --git a/frontend/src/pages/TracesExplorer/index.tsx b/frontend/src/pages/TracesExplorer/index.tsx
index bb25a37f86..b865fd02bd 100644
--- a/frontend/src/pages/TracesExplorer/index.tsx
+++ b/frontend/src/pages/TracesExplorer/index.tsx
@@ -259,7 +259,7 @@ function TracesExplorer(): JSX.Element {
)}
-
+