Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QueryBuilder filters for log pipelines #3587

Merged
merged 10 commits into from
Sep 21, 2023
Merged
2 changes: 1 addition & 1 deletion frontend/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const config: Config.InitialOptions = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
modulePathIgnorePatterns: ['dist'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/cssMock.ts',
'\\.(css|less|scss)$': '<rootDir>/__mocks__/cssMock.ts',
palashgdev marked this conversation as resolved.
Show resolved Hide resolved
},
globals: {
extensionsToTreatAsEsm: ['.ts'],
Expand Down
1 change: 1 addition & 0 deletions frontend/public/locales/en/pipeline.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"delete_processor_description": "Logs are processed sequentially in processors. Deleting a processor may change content of data processed by other processors",
"search_pipeline_placeholder": "Filter Pipelines",
"pipeline_name_placeholder": "Name",
"pipeline_filter_placeholder": "Filter for selecting logs to be processed by this pipeline. Example: service_name = billing",
"pipeline_tags_placeholder": "Tags",
"pipeline_description_placeholder": "Enter description for your pipeline",
"processor_name_placeholder": "Name",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Form } from 'antd';
import { initialQueryBuilderFormValuesMap } from 'constants/queryBuilder';
import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
import isEqual from 'lodash-es/isEqual';
import { useTranslation } from 'react-i18next';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';

import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';
import { FormLabelStyle } from '../styles';

function TagFilterInput({
value,
onChange,
placeholder,
}: TagFilterInputProps): JSX.Element {
const query = { ...initialQueryBuilderFormValuesMap.logs };
if (value) {
query.filters = value;
}

const onQueryChange = (newValue: TagFilter): void => {
// Avoid unnecessary onChange calls
palashgdev marked this conversation as resolved.
Show resolved Hide resolved
if (!isEqual(newValue, query.filters)) {
onChange(newValue);
}
};

return (
<QueryBuilderSearch
query={query}
onChange={onQueryChange}
placeholder={placeholder}
/>
);
}

interface TagFilterInputProps {
onChange: (filter: TagFilter) => void;
value: TagFilter;
placeholder: string;
}

function FilterInput({ fieldData }: FilterInputProps): JSX.Element {
const { t } = useTranslation('pipeline');

return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
key={fieldData.id}
rules={formValidationRules}
name={fieldData.name}
>
{/* Antd form will supply value and onChange to <TagFilterInput /> here.
// @ts-ignore */}
<TagFilterInput placeholder={t(fieldData.placeholder)} />
</Form.Item>
);
}
interface FilterInputProps {
fieldData: ProcessorFormField;
}
export default FilterInput;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import './styles.scss';

import { queryFilterTags } from 'hooks/queryBuilder/useTag';
import { PipelineData } from 'types/api/pipeline/def';

function PipelineFilterPreview({
filter,
}: PipelineFilterPreviewProps): JSX.Element {
return (
<div className="pipeline-filter-preview-container">
{queryFilterTags(filter).map((tag) => (
<div className="pipeline-filter-preview-condition" key={tag}>
{tag}
</div>
))}
</div>
);
}

interface PipelineFilterPreviewProps {
filter: PipelineData['filter'];
}

export default PipelineFilterPreview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.pipeline-filter-preview-condition {
padding: 0 0.2em;
}

.pipeline-filter-preview-container {
display: flex;
flex-wrap: wrap;
gap: 0.4em;
font-size: 0.75rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PipelineData, ProcessorData } from 'types/api/pipeline/def';

import { PipelineIndexIcon } from '../AddNewProcessor/styles';
import { ColumnDataStyle, ListDataStyle, ProcessorIndexIcon } from '../styles';
import PipelineFilterPreview from './PipelineFilterPreview';

const componentMap: ComponentMap = {
orderId: ({ record }) => <PipelineIndexIcon>{record}</PipelineIndexIcon>,
Expand All @@ -14,6 +15,7 @@ const componentMap: ComponentMap = {
),
id: ({ record }) => <ProcessorIndexIcon>{record}</ProcessorIndexIcon>,
name: ({ record }) => <ListDataStyle>{record}</ListDataStyle>,
filter: ({ record }) => <PipelineFilterPreview filter={record} />,
};

function TableComponents({
Expand All @@ -31,7 +33,9 @@ type ComponentMap = {
[key: string]: React.FC<{ record: Record }>;
};

export type Record = PipelineData['orderId'] & ProcessorData;
export type Record = PipelineData['orderId'] &
PipelineData['filter'] &
ProcessorData;

interface TableComponentsProps {
columnKey: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import {
import DeploymentStage from '../Layouts/ChangeHistory/DeploymentStage';
import DeploymentTime from '../Layouts/ChangeHistory/DeploymentTime';
import DescriptionTextArea from './AddNewPipeline/FormFields/DescriptionTextArea';
import FilterInput from './AddNewPipeline/FormFields/FilterInput';
import NameInput from './AddNewPipeline/FormFields/NameInput';

export const pipelineFields = [
{
id: 1,
fieldName: 'Filter',
placeholder: 'search_pipeline_placeholder',
placeholder: 'pipeline_filter_placeholder',
name: 'filter',
component: NameInput,
component: FilterInput,
},
{
id: 2,
Expand Down
30 changes: 28 additions & 2 deletions frontend/src/container/PipelinePage/mocks/pipeline.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
import { Pipeline, PipelineData } from 'types/api/pipeline/def';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';

export const configurationVersion = '1.0';

export function mockPipelineFilter(
key: string,
op: string,
value: string,
): TagFilter {
return {
op: 'AND',
items: [
{
id: `${key}-${value}`,
key: {
key,
dataType: DataTypes.String,
type: '',
isColumn: false,
isJSON: false,
},
op,
value,
},
],
};
}

export const pipelineMockData: Array<PipelineData> = [
{
id: '4453c8b0-c0fd-42bf-bf09-7cc1b04ccdc9',
Expand All @@ -10,7 +36,7 @@ export const pipelineMockData: Array<PipelineData> = [
alias: 'apachecommonparser',
description: 'This is a desc',
enabled: false,
filter: 'attributes.source == nginx',
filter: mockPipelineFilter('source', '=', 'nginx'),
config: [
{
orderId: 1,
Expand Down Expand Up @@ -43,7 +69,7 @@ export const pipelineMockData: Array<PipelineData> = [
alias: 'movingpipelinenew',
description: 'This is a desc of move',
enabled: false,
filter: 'attributes.method == POST',
filter: mockPipelineFilter('method', '=', 'POST'),
config: [
{
orderId: 1,
Expand Down
36 changes: 24 additions & 12 deletions frontend/src/container/PipelinePage/tests/AddNewPipeline.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { render } from '@testing-library/react';
import { I18nextProvider } from 'react-i18next';
import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import i18n from 'ReactI18';
Expand Down Expand Up @@ -27,25 +28,36 @@ beforeAll(() => {
matchMedia();
});

const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
});

describe('PipelinePage container test', () => {
it('should render AddNewPipeline section', () => {
const setActionType = jest.fn();
const selectedPipelineData = pipelineMockData[0];
const isActionType = 'add-pipeline';

const { asFragment } = render(
<MemoryRouter>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<AddNewPipeline
isActionType={isActionType}
setActionType={setActionType}
selectedPipelineData={selectedPipelineData}
setShowSaveButton={jest.fn()}
setCurrPipelineData={jest.fn()}
currPipelineData={pipelineMockData}
/>
</I18nextProvider>
</Provider>
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<AddNewPipeline
isActionType={isActionType}
setActionType={setActionType}
selectedPipelineData={selectedPipelineData}
setShowSaveButton={jest.fn()}
setCurrPipelineData={jest.fn()}
currPipelineData={pipelineMockData}
/>
</I18nextProvider>
</Provider>
</QueryClientProvider>
</MemoryRouter>,
);
expect(asFragment()).toMatchSnapshot();
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/container/PipelinePage/tests/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { pipelineMockData } from '../mocks/pipeline';
import { mockPipelineFilter, pipelineMockData } from '../mocks/pipeline';
import {
processorFields,
processorTypes,
Expand Down Expand Up @@ -68,7 +68,7 @@ describe('Utils testing of Pipeline Page', () => {
...pipelineMockData[findRecordIndex],
name: 'updated name',
description: 'changed description',
filter: 'value == test',
filter: mockPipelineFilter('value', '=', 'test'),
tags: ['test'],
};
const editedData = getEditedDataSource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function QueryBuilderSearch({
onChange,
whereClauseConfig,
className,
placeholder,
}: QueryBuilderSearchProps): JSX.Element {
const {
updateTag,
Expand Down Expand Up @@ -190,7 +191,7 @@ function QueryBuilderSearch({
filterOption={false}
autoClearSearchValue={false}
mode="multiple"
placeholder={PLACEHOLDER}
placeholder={placeholder}
value={queryTags}
searchValue={searchValue}
className={className}
Expand Down Expand Up @@ -218,11 +219,13 @@ interface QueryBuilderSearchProps {
onChange: (value: TagFilter) => void;
whereClauseConfig?: WhereClauseConfig;
className?: string;
placeholder?: string;
}

QueryBuilderSearch.defaultProps = {
whereClauseConfig: undefined,
className: '',
placeholder: PLACEHOLDER,
};

export interface CustomTagProps {
Expand Down
Loading