Skip to content

Commit

Permalink
feat: added global search on table panel (#5893)
Browse files Browse the repository at this point in the history
* feat: added global search on table panel

* feat: added global search on table panel

* feat: added global search conditionally and with new design

* feat: removed state from datasource

* feat: added global search in full view

* feat: added lightMode styles

* feat: added test cases for querytable and widgetHeader - global search
  • Loading branch information
SagarRajput-7 committed Sep 20, 2024
1 parent ced72f8 commit cb1cd35
Show file tree
Hide file tree
Showing 13 changed files with 1,056 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
box-sizing: border-box;
margin: 16px 0;
border-radius: 3px;

.global-search {
.ant-input-group-addon {
border: none;
background-color: var(--bg-ink-300);
}
}
}

.height-widget {
Expand Down Expand Up @@ -55,3 +62,15 @@
}
}
}

.lightMode {
.full-view-container {
.graph-container {
.global-search {
.ant-input-group-addon {
background-color: var(--bg-vanilla-200);
}
}
}
}
}
25 changes: 23 additions & 2 deletions frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import './WidgetFullView.styles.scss';

import { LoadingOutlined, SyncOutlined } from '@ant-design/icons';
import { Button, Spin } from 'antd';
import {
LoadingOutlined,
SearchOutlined,
SyncOutlined,
} from '@ant-design/icons';
import { Button, Input, Spin } from 'antd';
import cx from 'classnames';
import { ToggleGraphProps } from 'components/Graph/types';
import Spinner from 'components/Spinner';
Expand Down Expand Up @@ -172,6 +176,10 @@ function FullView({

const isListView = widget.panelTypes === PANEL_TYPES.LIST;

const isTablePanel = widget.panelTypes === PANEL_TYPES.TABLE;

const [searchTerm, setSearchTerm] = useState<string>('');

if (response.isLoading && widget.panelTypes !== PANEL_TYPES.LIST) {
return <Spinner height="100%" size="large" tip="Loading..." />;
}
Expand Down Expand Up @@ -216,6 +224,18 @@ function FullView({
}}
isGraphLegendToggleAvailable={canModifyChart}
>
{isTablePanel && (
<Input
addonBefore={<SearchOutlined size={14} />}
className="global-search"
placeholder="Search..."
allowClear
key={widget.id}
onChange={(e): void => {
setSearchTerm(e.target.value || '');
}}
/>
)}
<PanelWrapper
queryResponse={response}
widget={widget}
Expand All @@ -226,6 +246,7 @@ function FullView({
graphVisibility={graphsVisibilityStates}
onDragSelect={onDragSelect}
tableProcessedDataRef={tableProcessedDataRef}
searchTerm={searchTerm}
/>
</GraphContainer>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ function WidgetGraphComponent({
});
};

const [searchTerm, setSearchTerm] = useState<string>('');

const loadingState =
(queryResponse.isLoading || queryResponse.status === 'idle') &&
widget.panelTypes !== PANEL_TYPES.LIST;
Expand Down Expand Up @@ -317,6 +319,7 @@ function WidgetGraphComponent({
isWarning={isWarning}
isFetchingResponse={isFetchingResponse}
tableProcessedDataRef={tableProcessedDataRef}
setSearchTerm={setSearchTerm}
/>
</div>
{queryResponse.isLoading && widget.panelTypes !== PANEL_TYPES.LIST && (
Expand All @@ -337,6 +340,7 @@ function WidgetGraphComponent({
onDragSelect={onDragSelect}
tableProcessedDataRef={tableProcessedDataRef}
customTooltipElement={customTooltipElement}
searchTerm={searchTerm}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@
display: flex;
justify-content: space-between;
align-items: center;
height: 30px;
height: 36px;
width: 100%;
padding: 0.5rem;
box-sizing: border-box;
font-size: 14px;
font-weight: 600;

cursor: move;

.ant-input-group-addon {
border: none;
background-color: var(--bg-ink-500);
}
.search-header-icons {
cursor: pointer;
}
}

.widget-header-title {
Expand All @@ -19,6 +27,7 @@
.widget-header-actions {
display: flex;
align-items: center;
gap: 8px;
}
.widget-header-more-options {
visibility: hidden;
Expand All @@ -30,10 +39,22 @@
padding: 8px;
}

.widget-header-more-options-visible {
visibility: visible;
}

.widget-header-hover {
visibility: visible;
}

.widget-api-actions {
padding-right: 0.25rem;
}

.lightMode {
.widget-header-container {
.ant-input-group-addon {
background-color: inherit;
}
}
}
124 changes: 83 additions & 41 deletions frontend/src/container/GridCardLayout/WidgetHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
ExclamationCircleOutlined,
FullscreenOutlined,
MoreOutlined,
SearchOutlined,
WarningOutlined,
} from '@ant-design/icons';
import { Dropdown, MenuProps, Tooltip, Typography } from 'antd';
import { Dropdown, Input, MenuProps, Tooltip, Typography } from 'antd';
import Spinner from 'components/Spinner';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
Expand All @@ -20,8 +21,9 @@ import useComponentPermission from 'hooks/useComponentPermission';
import history from 'lib/history';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { isEmpty } from 'lodash-es';
import { X } from 'lucide-react';
import { unparse } from 'papaparse';
import { ReactNode, useCallback, useMemo } from 'react';
import { ReactNode, useCallback, useMemo, useState } from 'react';
import { UseQueryResult } from 'react-query';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
Expand Down Expand Up @@ -51,6 +53,7 @@ interface IWidgetHeaderProps {
isWarning: boolean;
isFetchingResponse: boolean;
tableProcessedDataRef: React.MutableRefObject<RowData[]>;
setSearchTerm: React.Dispatch<React.SetStateAction<string>>;
}

function WidgetHeader({
Expand All @@ -67,6 +70,7 @@ function WidgetHeader({
isWarning,
isFetchingResponse,
tableProcessedDataRef,
setSearchTerm,
}: IWidgetHeaderProps): JSX.Element | null {
const onEditHandler = useCallback((): void => {
const widgetId = widget.id;
Expand Down Expand Up @@ -187,6 +191,10 @@ function WidgetHeader({

const updatedMenuList = useMemo(() => generateMenuList(actions), [actions]);

const [showGlobalSearch, setShowGlobalSearch] = useState(false);

const globalSearchAvailable = widget.panelTypes === PANEL_TYPES.TABLE;

const menu = useMemo(
() => ({
items: updatedMenuList,
Expand All @@ -201,46 +209,80 @@ function WidgetHeader({

return (
<div className="widget-header-container">
<Typography.Text
ellipsis
data-testid={title}
className="widget-header-title"
>
{title}
</Typography.Text>
<div className="widget-header-actions">
<div className="widget-api-actions">{threshold}</div>
{isFetchingResponse && !queryResponse.isError && (
<Spinner style={{ paddingRight: '0.25rem' }} />
)}
{queryResponse.isError && (
<Tooltip
title={errorMessage}
placement={errorTooltipPosition}
className="widget-api-actions"
{showGlobalSearch ? (
<Input
addonBefore={<SearchOutlined size={14} />}
placeholder="Search..."
bordered={false}
data-testid="widget-header-search-input"
autoFocus
addonAfter={
<X
size={14}
onClick={(e): void => {
e.stopPropagation();
e.preventDefault();
setShowGlobalSearch(false);
}}
className="search-header-icons"
/>
}
key={widget.id}
onChange={(e): void => {
setSearchTerm(e.target.value || '');
}}
/>
) : (
<>
<Typography.Text
ellipsis
data-testid={title}
className="widget-header-title"
>
<ExclamationCircleOutlined />
</Tooltip>
)}

{isWarning && (
<Tooltip
title={WARNING_MESSAGE}
placement={errorTooltipPosition}
className="widget-api-actions"
>
<WarningOutlined />
</Tooltip>
)}
<Dropdown menu={menu} trigger={['hover']} placement="bottomRight">
<MoreOutlined
data-testid="widget-header-options"
className={`widget-header-more-options ${
parentHover ? 'widget-header-hover' : ''
}`}
/>
</Dropdown>
</div>
{title}
</Typography.Text>
<div className="widget-header-actions">
<div className="widget-api-actions">{threshold}</div>
{isFetchingResponse && !queryResponse.isError && (
<Spinner style={{ paddingRight: '0.25rem' }} />
)}
{queryResponse.isError && (
<Tooltip
title={errorMessage}
placement={errorTooltipPosition}
className="widget-api-actions"
>
<ExclamationCircleOutlined />
</Tooltip>
)}

{isWarning && (
<Tooltip
title={WARNING_MESSAGE}
placement={errorTooltipPosition}
className="widget-api-actions"
>
<WarningOutlined />
</Tooltip>
)}
{globalSearchAvailable && (
<SearchOutlined
className="search-header-icons"
onClick={(): void => setShowGlobalSearch(true)}
data-testid="widget-header-search"
/>
)}
<Dropdown menu={menu} trigger={['hover']} placement="bottomRight">
<MoreOutlined
data-testid="widget-header-options"
className={`widget-header-more-options ${
parentHover ? 'widget-header-hover' : ''
} ${globalSearchAvailable ? 'widget-header-more-options-visible' : ''}`}
/>
</Dropdown>
</div>
</>
)}
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/container/GridTableComponent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type GridTableComponentProps = {
columnUnits?: ColumnUnit;
tableProcessedDataRef?: React.MutableRefObject<RowData[]>;
sticky?: TableProps<RowData>['sticky'];
searchTerm?: string;
} & Pick<LogsExplorerTableProps, 'data'> &
Omit<TableProps<RowData>, 'columns' | 'dataSource'>;

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/container/PanelWrapper/PanelWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function PanelWrapper({
selectedGraph,
tableProcessedDataRef,
customTooltipElement,
searchTerm,
}: PanelWrapperProps): JSX.Element {
const Component = PanelTypeVsPanelWrapper[
selectedGraph || widget.panelTypes
Expand All @@ -39,6 +40,7 @@ function PanelWrapper({
selectedGraph={selectedGraph}
tableProcessedDataRef={tableProcessedDataRef}
customTooltipElement={customTooltipElement}
searchTerm={searchTerm}
/>
);
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/container/PanelWrapper/TablePanelWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function TablePanelWrapper({
widget,
queryResponse,
tableProcessedDataRef,
searchTerm,
}: PanelWrapperProps): JSX.Element {
const panelData =
(queryResponse.data?.payload?.data?.result?.[0] as any)?.table || [];
Expand All @@ -20,6 +21,7 @@ function TablePanelWrapper({
columnUnits={widget.columnUnits}
tableProcessedDataRef={tableProcessedDataRef}
sticky={widget.panelTypes === PANEL_TYPES.TABLE}
searchTerm={searchTerm}
// eslint-disable-next-line react/jsx-props-no-spreading
{...GRID_TABLE_CONFIG}
/>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/container/PanelWrapper/panelWrapper.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type PanelWrapperProps = {
onDragSelect: (start: number, end: number) => void;
selectedGraph?: PANEL_TYPES;
tableProcessedDataRef?: React.MutableRefObject<RowData[]>;
searchTerm?: string;
customTooltipElement?: HTMLDivElement;
};

Expand Down
1 change: 1 addition & 0 deletions frontend/src/container/QueryTable/QueryTable.intefaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export type QueryTableProps = Omit<
columns?: ColumnsType<RowData>;
dataSource?: RowData[];
sticky?: TableProps<RowData>['sticky'];
searchTerm?: string;
};
Loading

0 comments on commit cb1cd35

Please sign in to comment.