mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-20 12:52:43 +00:00
✨ [Feature] : Advance Search (#5427)
Co-authored-by: Vivek Ratnavel Subramanian <vivekratnavel90@gmail.com>
This commit is contained in:
parent
5537db2ab4
commit
f5dbae14da
@ -42,7 +42,7 @@ export const SEARCH_ENTITY_TOPIC = {
|
|||||||
|
|
||||||
export const SEARCH_ENTITY_DASHBOARD = {
|
export const SEARCH_ENTITY_DASHBOARD = {
|
||||||
dashboard_1: {
|
dashboard_1: {
|
||||||
term: 'Sales Dashboard',
|
term: 'Slack Dashboard',
|
||||||
entity: MYDATA_SUMMARY_OPTIONS.dashboards,
|
entity: MYDATA_SUMMARY_OPTIONS.dashboards,
|
||||||
},
|
},
|
||||||
dashboard_2: {
|
dashboard_2: {
|
||||||
@ -52,9 +52,9 @@ export const SEARCH_ENTITY_DASHBOARD = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SEARCH_ENTITY_PIPELINE = {
|
export const SEARCH_ENTITY_PIPELINE = {
|
||||||
pipeline_1: { term: 'Hive ETL', entity: MYDATA_SUMMARY_OPTIONS.pipelines },
|
pipeline_1: { term: 'Snowflake ETL', entity: MYDATA_SUMMARY_OPTIONS.pipelines },
|
||||||
pipeline_2: {
|
pipeline_2: {
|
||||||
term: 'Snowflake ETL',
|
term: 'Hive ETL',
|
||||||
entity: MYDATA_SUMMARY_OPTIONS.pipelines,
|
entity: MYDATA_SUMMARY_OPTIONS.pipelines,
|
||||||
},
|
},
|
||||||
pipeline_3: {
|
pipeline_3: {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ describe('Entity Details Page', () => {
|
|||||||
// click on the 1st result and go to manage tab in entity details page
|
// click on the 1st result and go to manage tab in entity details page
|
||||||
cy.wait(500);
|
cy.wait(500);
|
||||||
cy.get('[data-testid="table-link"]').first().should('be.visible').click();
|
cy.get('[data-testid="table-link"]').first().should('be.visible').click();
|
||||||
cy.get('[data-testid="Manage"]').scrollIntoView().click();
|
cy.get('[data-testid="Manage"]').click();
|
||||||
|
|
||||||
// check for delete section and delete button is available or not
|
// check for delete section and delete button is available or not
|
||||||
cy.get('[data-testid="danger-zone"]').scrollIntoView().should('be.visible');
|
cy.get('[data-testid="danger-zone"]').scrollIntoView().should('be.visible');
|
||||||
|
|||||||
@ -132,9 +132,12 @@ export const getSuggestedTeams = (term: string): Promise<AxiosResponse> => {
|
|||||||
export const getUserSuggestions: Function = (
|
export const getUserSuggestions: Function = (
|
||||||
term: string
|
term: string
|
||||||
): Promise<AxiosResponse> => {
|
): Promise<AxiosResponse> => {
|
||||||
return APIClient.get(
|
const params = {
|
||||||
`/search/suggest?q=${term}&index=${SearchIndex.USER},${SearchIndex.TEAM}`
|
q: term,
|
||||||
);
|
index: `${SearchIndex.USER},${SearchIndex.TEAM}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return APIClient.get(`/search/suggest`, { params });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSearchedUsers = (
|
export const getSearchedUsers = (
|
||||||
@ -193,3 +196,13 @@ export const deleteEntity: Function = (
|
|||||||
|
|
||||||
return APIClient.delete(path);
|
return APIClient.delete(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAdvancedFieldOptions = (
|
||||||
|
q: string,
|
||||||
|
index: string,
|
||||||
|
field: string | undefined
|
||||||
|
): Promise<AxiosResponse> => {
|
||||||
|
const params = { index, field, q };
|
||||||
|
|
||||||
|
return APIClient.get(`/search/suggest`, { params });
|
||||||
|
};
|
||||||
|
|||||||
@ -184,6 +184,10 @@ const ActivityThreadPanel: FC<ActivityThreadPanelProp> = ({
|
|||||||
fetchMoreThread(isInView as boolean, paging, isThreadLoading);
|
fetchMoreThread(isInView as boolean, paging, isThreadLoading);
|
||||||
}, [paging, isThreadLoading, isInView]);
|
}, [paging, isThreadLoading, isInView]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}, []);
|
||||||
|
|
||||||
return ReactDOM.createPortal(
|
return ReactDOM.createPortal(
|
||||||
<div className={classNames('tw-h-full', className)}>
|
<div className={classNames('tw-h-full', className)}>
|
||||||
<FeedPanelOverlay
|
<FeedPanelOverlay
|
||||||
|
|||||||
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
import AdvancedField from './AdvancedField';
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
'metadata-suggest': [
|
||||||
|
{
|
||||||
|
text: 'clou',
|
||||||
|
offset: 0,
|
||||||
|
length: 4,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
text: 'Cloud_Infra',
|
||||||
|
_index: 'team_search_index',
|
||||||
|
_type: '_doc',
|
||||||
|
_id: '267a4dd4-df64-400d-b4d1-3925d6f23885',
|
||||||
|
_score: 10,
|
||||||
|
_source: {
|
||||||
|
suggest: [
|
||||||
|
{
|
||||||
|
input: 'Cloud_Infra',
|
||||||
|
weight: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'Cloud_Infra',
|
||||||
|
weight: 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deleted: false,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
team_id: '267a4dd4-df64-400d-b4d1-3925d6f23885',
|
||||||
|
name: 'Cloud_Infra',
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
display_name: 'Cloud_Infra',
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
entity_type: 'team',
|
||||||
|
users: [],
|
||||||
|
owns: [],
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
default_roles: [],
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
last_updated_timestamp: 1654838173854,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../../axiosAPIs/miscAPI', () => ({
|
||||||
|
getAdvancedFieldOptions: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve()),
|
||||||
|
getUserSuggestions: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve({ data: { suggest: mockData } })),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const index = 'table_search_index';
|
||||||
|
const field = { key: 'owner.name', value: undefined } as AdvanceField;
|
||||||
|
const onFieldRemove = jest.fn();
|
||||||
|
const onFieldValueSelect = jest.fn();
|
||||||
|
|
||||||
|
const mockProps = {
|
||||||
|
index,
|
||||||
|
field,
|
||||||
|
onFieldRemove,
|
||||||
|
onFieldValueSelect,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Test AdvancedField Component', () => {
|
||||||
|
it('Should render advancedfield component', async () => {
|
||||||
|
const { findByTestId } = render(<AdvancedField {...mockProps} />);
|
||||||
|
|
||||||
|
const label = await findByTestId('field-label');
|
||||||
|
|
||||||
|
expect(label).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(label).toHaveTextContent('Owner:');
|
||||||
|
|
||||||
|
const searchSelect = await findByTestId('field-select');
|
||||||
|
|
||||||
|
expect(searchSelect).toBeInTheDocument();
|
||||||
|
|
||||||
|
const removeButton = await findByTestId('field-remove-button');
|
||||||
|
|
||||||
|
expect(removeButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call remove method on click of remove button', async () => {
|
||||||
|
const { findByTestId } = render(<AdvancedField {...mockProps} />);
|
||||||
|
|
||||||
|
const label = await findByTestId('field-label');
|
||||||
|
|
||||||
|
expect(label).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(label).toHaveTextContent('Owner:');
|
||||||
|
|
||||||
|
const searchSelect = await findByTestId('field-select');
|
||||||
|
|
||||||
|
expect(searchSelect).toBeInTheDocument();
|
||||||
|
|
||||||
|
const removeButton = await findByTestId('field-remove-button');
|
||||||
|
|
||||||
|
expect(removeButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(removeButton);
|
||||||
|
|
||||||
|
expect(onFieldRemove).toHaveBeenCalledWith(field.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call select method on click of option', async () => {
|
||||||
|
const { findByTestId, findByRole, findAllByTestId } = render(
|
||||||
|
<AdvancedField {...mockProps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const label = await findByTestId('field-label');
|
||||||
|
|
||||||
|
expect(label).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(label).toHaveTextContent('Owner:');
|
||||||
|
|
||||||
|
const searchSelect = await findByTestId('field-select');
|
||||||
|
|
||||||
|
expect(searchSelect).toBeInTheDocument();
|
||||||
|
|
||||||
|
const removeButton = await findByTestId('field-remove-button');
|
||||||
|
|
||||||
|
expect(removeButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
const searchInput = await findByRole('combobox');
|
||||||
|
|
||||||
|
expect(searchInput).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.change(searchInput, { target: { value: 'cloud' } });
|
||||||
|
|
||||||
|
const fieldOptions = await findAllByTestId('field-option');
|
||||||
|
|
||||||
|
expect(fieldOptions).toHaveLength(
|
||||||
|
mockData['metadata-suggest'][0].options.length
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(fieldOptions[0]);
|
||||||
|
|
||||||
|
expect(onFieldValueSelect).toHaveBeenCalledWith({
|
||||||
|
key: 'owner.name',
|
||||||
|
value: 'Cloud_Infra',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { Select } from 'antd';
|
||||||
|
import { AxiosError, AxiosResponse } from 'axios';
|
||||||
|
import { startCase } from 'lodash';
|
||||||
|
import React, { FC, useState } from 'react';
|
||||||
|
import {
|
||||||
|
getAdvancedFieldOptions,
|
||||||
|
getUserSuggestions,
|
||||||
|
} from '../../axiosAPIs/miscAPI';
|
||||||
|
import { MISC_FIELDS } from '../../constants/advanceSearch.constants';
|
||||||
|
import {
|
||||||
|
getAdvancedField,
|
||||||
|
getItemLabel,
|
||||||
|
} from '../../utils/AdvancedSearchUtils';
|
||||||
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
index: string;
|
||||||
|
field: AdvanceField;
|
||||||
|
onFieldRemove: (value: string) => void;
|
||||||
|
onFieldValueSelect: (field: AdvanceField) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InputProps {
|
||||||
|
options: Option[];
|
||||||
|
value: string | undefined;
|
||||||
|
handleChange: (value: string) => void;
|
||||||
|
handleSearch: (value: string) => void;
|
||||||
|
handleSelect: (value: string) => void;
|
||||||
|
handleClear: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchInput = ({
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
handleChange,
|
||||||
|
handleSearch,
|
||||||
|
handleSelect,
|
||||||
|
handleClear,
|
||||||
|
}: InputProps) => {
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
|
const optionsElement = options.map((d) => (
|
||||||
|
<Option data-testid="field-option" key={d.value}>
|
||||||
|
{d.label}
|
||||||
|
</Option>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
bordered={false}
|
||||||
|
className="ant-advaced-field-select"
|
||||||
|
data-testid="field-select"
|
||||||
|
defaultActiveFirstOption={false}
|
||||||
|
dropdownClassName="ant-suggestion-dropdown"
|
||||||
|
filterOption={false}
|
||||||
|
notFoundContent={null}
|
||||||
|
placeholder="Search to Select"
|
||||||
|
showArrow={false}
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
onClear={handleClear}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
onSelect={handleSelect}>
|
||||||
|
{optionsElement}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const AdvancedField: FC<Props> = ({
|
||||||
|
field,
|
||||||
|
onFieldRemove,
|
||||||
|
index,
|
||||||
|
onFieldValueSelect,
|
||||||
|
}) => {
|
||||||
|
const advancedField = getAdvancedField(field.key);
|
||||||
|
|
||||||
|
const [options, setOptions] = useState<Option[]>([]);
|
||||||
|
const [value, setValue] = useState<string | undefined>(field.value);
|
||||||
|
|
||||||
|
const fetchOptions = (query: string) => {
|
||||||
|
if (!MISC_FIELDS.includes(field.key)) {
|
||||||
|
getAdvancedFieldOptions(query, index, advancedField)
|
||||||
|
.then((res: AxiosResponse) => {
|
||||||
|
const suggestOptions =
|
||||||
|
res.data.suggest['metadata-suggest'][0].options ?? [];
|
||||||
|
const uniqueOptions = [
|
||||||
|
// eslint-disable-next-line
|
||||||
|
...new Set(suggestOptions.map((op: any) => op.text)),
|
||||||
|
];
|
||||||
|
setOptions(
|
||||||
|
uniqueOptions.map((op: unknown) => ({
|
||||||
|
label: op as string,
|
||||||
|
value: op as string,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
} else {
|
||||||
|
getUserSuggestions(query)
|
||||||
|
.then((res: AxiosResponse) => {
|
||||||
|
const suggestOptions =
|
||||||
|
res.data.suggest['metadata-suggest'][0].options ?? [];
|
||||||
|
const uniqueOptions = [
|
||||||
|
// eslint-disable-next-line
|
||||||
|
...new Set(suggestOptions.map((op: any) => op._source.name)),
|
||||||
|
];
|
||||||
|
setOptions(
|
||||||
|
uniqueOptions.map((op: unknown) => ({
|
||||||
|
label: op as string,
|
||||||
|
value: op as string,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (newValue: string) => {
|
||||||
|
if (newValue) {
|
||||||
|
fetchOptions(newValue);
|
||||||
|
} else {
|
||||||
|
setOptions([]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (newValue: string) => {
|
||||||
|
setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnSelect = (newValue: string) => {
|
||||||
|
onFieldValueSelect({ ...field, value: newValue });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnClear = () => {
|
||||||
|
onFieldValueSelect({ ...field, value: undefined });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tw-bg-white tw-border tw-border-main tw-rounded tw-p-1 tw-px-2 tw-flex tw-justify-between">
|
||||||
|
<span className="tw-self-center" data-testid="field-label">
|
||||||
|
{startCase(getItemLabel(field.key))}:
|
||||||
|
</span>
|
||||||
|
<SearchInput
|
||||||
|
handleChange={handleChange}
|
||||||
|
handleClear={handleOnClear}
|
||||||
|
handleSearch={handleSearch}
|
||||||
|
handleSelect={handleOnSelect}
|
||||||
|
options={options}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="tw-cursor-pointer tw-self-center"
|
||||||
|
data-testid="field-remove-button"
|
||||||
|
onClick={() => onFieldRemove(field.key)}>
|
||||||
|
<FontAwesomeIcon className="tw-text-primary" icon="times" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdvancedField;
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
import AdvancedFields from './AdvancedFields';
|
||||||
|
|
||||||
|
jest.mock('./AdvancedField', () =>
|
||||||
|
jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue(<div data-testid="advanced-field">AdvancedField</div>)
|
||||||
|
);
|
||||||
|
|
||||||
|
const index = 'table_search_index';
|
||||||
|
const fields = [
|
||||||
|
{ key: 'owner.name', value: undefined },
|
||||||
|
{ key: 'column_names', value: undefined },
|
||||||
|
] as AdvanceField[];
|
||||||
|
|
||||||
|
const onFieldRemove = jest.fn();
|
||||||
|
const onClear = jest.fn();
|
||||||
|
const onFieldValueSelect = jest.fn();
|
||||||
|
|
||||||
|
const mockProps = {
|
||||||
|
index,
|
||||||
|
fields,
|
||||||
|
onFieldRemove,
|
||||||
|
onClear,
|
||||||
|
onFieldValueSelect,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Test AdvancedFields component', () => {
|
||||||
|
it('Should render AdvancedFields component', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<AdvancedFields {...mockProps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const fields = await findAllByTestId('advanced-field');
|
||||||
|
const clearButton = await findByTestId('clear-all-button');
|
||||||
|
|
||||||
|
expect(fields).toHaveLength(fields.length);
|
||||||
|
|
||||||
|
expect(clearButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call onClear method on click of Clear All button', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<AdvancedFields {...mockProps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const fields = await findAllByTestId('advanced-field');
|
||||||
|
const clearButton = await findByTestId('clear-all-button');
|
||||||
|
|
||||||
|
expect(fields).toHaveLength(fields.length);
|
||||||
|
|
||||||
|
expect(clearButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(clearButton);
|
||||||
|
|
||||||
|
expect(onClear).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { uniqueId } from 'lodash';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
import AdvancedField from './AdvancedField';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
index: string;
|
||||||
|
fields: Array<AdvanceField>;
|
||||||
|
onFieldRemove: (value: string) => void;
|
||||||
|
onClear: () => void;
|
||||||
|
onFieldValueSelect: (field: AdvanceField) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AdvancedFields: FC<Props> = ({
|
||||||
|
fields,
|
||||||
|
onFieldRemove,
|
||||||
|
onClear,
|
||||||
|
index,
|
||||||
|
onFieldValueSelect,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="tw-flex tw-gap-2 tw-mb-3">
|
||||||
|
{fields.map((field) => (
|
||||||
|
<AdvancedField
|
||||||
|
field={field}
|
||||||
|
index={index}
|
||||||
|
key={uniqueId()}
|
||||||
|
onFieldRemove={onFieldRemove}
|
||||||
|
onFieldValueSelect={onFieldValueSelect}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<span
|
||||||
|
className="tw-text-primary tw-self-center tw-cursor-pointer"
|
||||||
|
data-testid="clear-all-button"
|
||||||
|
onClick={onClear}>
|
||||||
|
Clear All
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdvancedFields;
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
COMMON_DROPDOWN_ITEMS,
|
||||||
|
TABLE_DROPDOWN_ITEMS,
|
||||||
|
} from '../../constants/advanceSearch.constants';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
import AdvancedSearchDropDown from './AdvancedSearchDropDown';
|
||||||
|
|
||||||
|
const mockItems = [...COMMON_DROPDOWN_ITEMS, ...TABLE_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
|
jest.mock('../../utils/AdvancedSearchUtils', () => ({
|
||||||
|
getDropDownItems: jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue([...COMMON_DROPDOWN_ITEMS, ...TABLE_DROPDOWN_ITEMS]),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const onSelect = jest.fn();
|
||||||
|
const selectedItems = [] as AdvanceField[];
|
||||||
|
const index = 'table_search_index';
|
||||||
|
|
||||||
|
const mockPorps = {
|
||||||
|
selectedItems,
|
||||||
|
index,
|
||||||
|
onSelect,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Test AdvancedSearch DropDown Component', () => {
|
||||||
|
it('Should render dropdown component', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<AdvancedSearchDropDown {...mockPorps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownLabel = await findByTestId('dropdown-label');
|
||||||
|
|
||||||
|
expect(dropdownLabel).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(dropdownLabel);
|
||||||
|
|
||||||
|
const dropdownMenu = await findByTestId('dropdown-menu');
|
||||||
|
|
||||||
|
expect(dropdownMenu).toBeInTheDocument();
|
||||||
|
|
||||||
|
const menuItems = await findAllByTestId('dropdown-menu-item');
|
||||||
|
|
||||||
|
expect(menuItems).toHaveLength(mockItems.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call onSelect method on onClick option', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<AdvancedSearchDropDown {...mockPorps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownLabel = await findByTestId('dropdown-label');
|
||||||
|
|
||||||
|
expect(dropdownLabel).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(dropdownLabel);
|
||||||
|
|
||||||
|
const dropdownMenu = await findByTestId('dropdown-menu');
|
||||||
|
|
||||||
|
expect(dropdownMenu).toBeInTheDocument();
|
||||||
|
|
||||||
|
const menuItems = await findAllByTestId('dropdown-menu-item');
|
||||||
|
|
||||||
|
expect(menuItems).toHaveLength(mockItems.length);
|
||||||
|
|
||||||
|
fireEvent.click(menuItems[0]);
|
||||||
|
|
||||||
|
expect(onSelect).toHaveBeenCalledWith(mockItems[0].key);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Selected option should be disabled', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<AdvancedSearchDropDown
|
||||||
|
{...mockPorps}
|
||||||
|
selectedItems={[{ key: mockItems[0].key, value: undefined }]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownLabel = await findByTestId('dropdown-label');
|
||||||
|
|
||||||
|
expect(dropdownLabel).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(dropdownLabel);
|
||||||
|
|
||||||
|
const dropdownMenu = await findByTestId('dropdown-menu');
|
||||||
|
|
||||||
|
expect(dropdownMenu).toBeInTheDocument();
|
||||||
|
|
||||||
|
const menuItems = await findAllByTestId('dropdown-menu-item');
|
||||||
|
|
||||||
|
expect(menuItems).toHaveLength(mockItems.length);
|
||||||
|
|
||||||
|
expect(menuItems[0]).toHaveAttribute('aria-disabled', 'true');
|
||||||
|
|
||||||
|
fireEvent.click(menuItems[0]);
|
||||||
|
|
||||||
|
expect(onSelect).not.toHaveBeenCalledWith(mockItems[0].key);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Dropdown, Menu } from 'antd';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import { getDropDownItems } from '../../utils/AdvancedSearchUtils';
|
||||||
|
import { normalLink } from '../../utils/styleconstant';
|
||||||
|
import { dropdownIcon as DropdownIcon } from '../../utils/svgconstant';
|
||||||
|
import { AdvanceField } from '../Explore/explore.interface';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
index: string;
|
||||||
|
selectedItems: Array<AdvanceField>;
|
||||||
|
onSelect: (filter: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AdvancedSearchDropDown: FC<Props> = ({
|
||||||
|
index,
|
||||||
|
onSelect,
|
||||||
|
selectedItems,
|
||||||
|
}) => {
|
||||||
|
const items = getDropDownItems(index).map((item) => ({
|
||||||
|
...item,
|
||||||
|
onClick: () => onSelect(item.key),
|
||||||
|
disabled: selectedItems.some((i) => item.key === i.key),
|
||||||
|
'data-testid': 'dropdown-menu-item',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const menu = <Menu data-testid="dropdown-menu" items={items} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
className="tw-self-center tw-mr-2 tw-cursor-pointer"
|
||||||
|
data-testid="dropdown"
|
||||||
|
overlay={menu}
|
||||||
|
trigger={['click']}>
|
||||||
|
<div className="tw-text-primary" data-testid="dropdown-label">
|
||||||
|
<span className="tw-mr-2">Advanced Search</span>
|
||||||
|
<DropdownIcon style={{ color: normalLink, margin: '0px' }} />
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdvancedSearchDropDown;
|
||||||
@ -36,7 +36,6 @@ import { useHistory, useLocation } from 'react-router-dom';
|
|||||||
import { Button } from '../../components/buttons/Button/Button';
|
import { Button } from '../../components/buttons/Button/Button';
|
||||||
import ErrorPlaceHolderES from '../../components/common/error-with-placeholder/ErrorPlaceHolderES';
|
import ErrorPlaceHolderES from '../../components/common/error-with-placeholder/ErrorPlaceHolderES';
|
||||||
import FacetFilter from '../../components/common/facetfilter/FacetFilter';
|
import FacetFilter from '../../components/common/facetfilter/FacetFilter';
|
||||||
import DropDownList from '../../components/dropdown/DropDownList';
|
|
||||||
import SearchedData from '../../components/searched-data/SearchedData';
|
import SearchedData from '../../components/searched-data/SearchedData';
|
||||||
import {
|
import {
|
||||||
getExplorePathWithSearch,
|
getExplorePathWithSearch,
|
||||||
@ -66,9 +65,11 @@ import {
|
|||||||
import { formatDataResponse } from '../../utils/APIUtils';
|
import { formatDataResponse } from '../../utils/APIUtils';
|
||||||
import { getCountBadge } from '../../utils/CommonUtils';
|
import { getCountBadge } from '../../utils/CommonUtils';
|
||||||
import { getFilterCount, getFilterString } from '../../utils/FilterUtils';
|
import { getFilterCount, getFilterString } from '../../utils/FilterUtils';
|
||||||
import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant';
|
import AdvancedFields from '../AdvancedSearch/AdvancedFields';
|
||||||
|
import AdvancedSearchDropDown from '../AdvancedSearch/AdvancedSearchDropDown';
|
||||||
import PageLayout from '../containers/PageLayout';
|
import PageLayout from '../containers/PageLayout';
|
||||||
import { ExploreProps } from './explore.interface';
|
import { AdvanceField, ExploreProps } from './explore.interface';
|
||||||
|
import SortingDropDown from './SortingDropDown';
|
||||||
|
|
||||||
const Explore: React.FC<ExploreProps> = ({
|
const Explore: React.FC<ExploreProps> = ({
|
||||||
tabCounts,
|
tabCounts,
|
||||||
@ -105,18 +106,16 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
...filterObject,
|
...filterObject,
|
||||||
...searchFilter,
|
...searchFilter,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState<number>(1);
|
const [currentPage, setCurrentPage] = useState<number>(1);
|
||||||
const [totalNumberOfValue, setTotalNumberOfValues] = useState<number>(0);
|
const [totalNumberOfValue, setTotalNumberOfValues] = useState<number>(0);
|
||||||
const [aggregations, setAggregations] = useState<Array<AggregationType>>([]);
|
const [aggregations, setAggregations] = useState<Array<AggregationType>>([]);
|
||||||
const [searchTag, setSearchTag] = useState<string>(location.search);
|
const [searchTag, setSearchTag] = useState<string>(location.search);
|
||||||
|
|
||||||
const [fieldListVisible, setFieldListVisible] = useState<boolean>(false);
|
|
||||||
const [sortField, setSortField] = useState<string>(sortValue);
|
const [sortField, setSortField] = useState<string>(sortValue);
|
||||||
const [sortOrder, setSortOrder] = useState<string>(INITIAL_SORT_ORDER);
|
const [sortOrder, setSortOrder] = useState<string>(INITIAL_SORT_ORDER);
|
||||||
const [searchIndex, setSearchIndex] = useState<string>(getCurrentIndex(tab));
|
const [searchIndex, setSearchIndex] = useState<string>(getCurrentIndex(tab));
|
||||||
const [currentTab, setCurrentTab] = useState<number>(getCurrentTab(tab));
|
const [currentTab, setCurrentTab] = useState<number>(getCurrentTab(tab));
|
||||||
const [fieldList, setFieldList] =
|
|
||||||
useState<Array<{ name: string; value: string }>>(tableSortingFields);
|
|
||||||
const [isEntityLoading, setIsEntityLoading] = useState(true);
|
const [isEntityLoading, setIsEntityLoading] = useState(true);
|
||||||
const [isFilterSet, setIsFilterSet] = useState<boolean>(
|
const [isFilterSet, setIsFilterSet] = useState<boolean>(
|
||||||
!isEmpty(initialFilter)
|
!isEmpty(initialFilter)
|
||||||
@ -125,6 +124,43 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
const isMounting = useRef(true);
|
const isMounting = useRef(true);
|
||||||
const forceSetAgg = useRef(false);
|
const forceSetAgg = useRef(false);
|
||||||
const previsouIndex = usePrevious(searchIndex);
|
const previsouIndex = usePrevious(searchIndex);
|
||||||
|
const [fieldList, setFieldList] =
|
||||||
|
useState<Array<{ name: string; value: string }>>(tableSortingFields);
|
||||||
|
|
||||||
|
const [selectedAdvancedFields, setSelectedAdvancedField] = useState<
|
||||||
|
Array<AdvanceField>
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const onAdvancedFieldSelect = (value: string) => {
|
||||||
|
const flag = selectedAdvancedFields.some((field) => field.key === value);
|
||||||
|
if (!flag) {
|
||||||
|
setSelectedAdvancedField((pre) => [
|
||||||
|
...pre,
|
||||||
|
{ key: value, value: undefined },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onAdvancedFieldRemove = (value: string) => {
|
||||||
|
setSelectedAdvancedField((pre) =>
|
||||||
|
pre.filter((field) => field.key !== value)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAdvancedFieldClear = () => {
|
||||||
|
setSelectedAdvancedField([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAdvancedFieldValueSelect = (field: AdvanceField) => {
|
||||||
|
setSelectedAdvancedField((pre) => {
|
||||||
|
return pre.map((preField) => {
|
||||||
|
if (preField.key === field.key) {
|
||||||
|
return field;
|
||||||
|
} else {
|
||||||
|
return preField;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleSelectedFilter = (
|
const handleSelectedFilter = (
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
@ -160,11 +196,16 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
handleFilterChange(filterData);
|
handleFilterChange(filterData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFieldDropDown = (value: string) => {
|
||||||
|
setSortField(value);
|
||||||
|
};
|
||||||
|
|
||||||
const handleShowDeleted = (checked: boolean) => {
|
const handleShowDeleted = (checked: boolean) => {
|
||||||
onShowDeleted(checked);
|
onShowDeleted(checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClearFilterHandler = (type: string[], isForceClear = false) => {
|
const onClearFilterHandler = (type: string[], isForceClear = false) => {
|
||||||
|
setSelectedAdvancedField([]);
|
||||||
const updatedFilter = type.reduce((filterObj, type) => {
|
const updatedFilter = type.reduce((filterObj, type) => {
|
||||||
return { ...filterObj, [type]: [] };
|
return { ...filterObj, [type]: [] };
|
||||||
}, {});
|
}, {});
|
||||||
@ -335,44 +376,26 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
return facetFilters;
|
return facetFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFieldDropDown = (
|
|
||||||
_e: React.MouseEvent<HTMLElement, MouseEvent>,
|
|
||||||
value?: string
|
|
||||||
) => {
|
|
||||||
setSortField(value || sortField);
|
|
||||||
setFieldListVisible(false);
|
|
||||||
};
|
|
||||||
const handleOrder = (value: string) => {
|
const handleOrder = (value: string) => {
|
||||||
setSortOrder(value);
|
setSortOrder(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSortingElements = () => {
|
const getSortingElements = () => {
|
||||||
return (
|
return (
|
||||||
<div className="tw-flex tw-gap-2">
|
<div className="tw-flex">
|
||||||
<div className="tw-mt-4">
|
<AdvancedSearchDropDown
|
||||||
<span className="tw-mr-2">Sort by:</span>
|
index={searchIndex}
|
||||||
<span className="tw-relative">
|
selectedItems={selectedAdvancedFields}
|
||||||
<Button
|
onSelect={onAdvancedFieldSelect}
|
||||||
className="focus:tw-no-underline"
|
|
||||||
data-testid="sortBy"
|
|
||||||
size="custom"
|
|
||||||
theme="primary"
|
|
||||||
variant="link"
|
|
||||||
onClick={() => setFieldListVisible((visible) => !visible)}>
|
|
||||||
{fieldList.find((field) => field.value === sortField)?.name ||
|
|
||||||
'Relevance'}
|
|
||||||
<DropDownIcon />
|
|
||||||
</Button>
|
|
||||||
{fieldListVisible && (
|
|
||||||
<DropDownList
|
|
||||||
dropDownList={fieldList}
|
|
||||||
value={sortField}
|
|
||||||
onSelect={handleFieldDropDown}
|
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</span>
|
<SortingDropDown
|
||||||
</div>
|
fieldList={fieldList}
|
||||||
<div className="tw-mt-2 tw-flex tw-gap-2">
|
handleFieldDropDown={handleFieldDropDown}
|
||||||
|
sortField={sortField}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="tw-flex">
|
||||||
{sortOrder === 'asc' ? (
|
{sortOrder === 'asc' ? (
|
||||||
<button onClick={() => handleOrder('desc')}>
|
<button onClick={() => handleOrder('desc')}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
@ -486,6 +509,17 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAdvancedSearch = (advancedFields: AdvanceField[]) => {
|
||||||
|
const advancedFilterObject: FilterObject = {};
|
||||||
|
advancedFields.forEach((field) => {
|
||||||
|
if (field.value) {
|
||||||
|
advancedFilterObject[field.key] = [field.value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
handleFilterChange(advancedFilterObject);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSearchText(searchQuery || emptyValue);
|
handleSearchText(searchQuery || emptyValue);
|
||||||
setCurrentPage(1);
|
setCurrentPage(1);
|
||||||
@ -493,11 +527,8 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFieldList(tabsInfo[getCurrentTab(tab) - 1].sortingFields);
|
setFieldList(tabsInfo[getCurrentTab(tab) - 1].sortingFields);
|
||||||
setSortField(
|
// if search text is there then set sortfield as ''(Relevance)
|
||||||
searchQuery
|
setSortField(searchText ? '' : tabsInfo[getCurrentTab(tab) - 1].sortField);
|
||||||
? tabsInfo[getCurrentTab(tab) - 1].sortField
|
|
||||||
: INITIAL_SORT_FIELD
|
|
||||||
);
|
|
||||||
setSortOrder(INITIAL_SORT_ORDER);
|
setSortOrder(INITIAL_SORT_ORDER);
|
||||||
setCurrentTab(getCurrentTab(tab));
|
setCurrentTab(getCurrentTab(tab));
|
||||||
setSearchIndex(getCurrentIndex(tab));
|
setSearchIndex(getCurrentIndex(tab));
|
||||||
@ -525,7 +556,6 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
forceSetAgg.current = true;
|
forceSetAgg.current = true;
|
||||||
if (!isMounting.current) {
|
if (!isMounting.current) {
|
||||||
resetFilters();
|
|
||||||
fetchTableData();
|
fetchTableData();
|
||||||
}
|
}
|
||||||
}, [searchText, searchIndex, showDeleted]);
|
}, [searchText, searchIndex, showDeleted]);
|
||||||
@ -593,6 +623,32 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
}
|
}
|
||||||
}, [filters]);
|
}, [filters]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* on index change clear the filters
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedAdvancedField([]);
|
||||||
|
}, [searchIndex]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if search query is there then make sortfield as empty (Relevance)
|
||||||
|
* otherwise change it to INITIAL_SORT_FIELD (last_updated)
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchText) {
|
||||||
|
setSortField('');
|
||||||
|
} else {
|
||||||
|
setSortField(INITIAL_SORT_FIELD);
|
||||||
|
}
|
||||||
|
}, [searchText]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* on advance field change call handleAdvancedSearch methdod
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
handleAdvancedSearch(selectedAdvancedFields);
|
||||||
|
}, [selectedAdvancedFields]);
|
||||||
|
|
||||||
// alwyas Keep this useEffect at the end...
|
// alwyas Keep this useEffect at the end...
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
isMounting.current = false;
|
isMounting.current = false;
|
||||||
@ -614,12 +670,24 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const advanceFieldCheck =
|
||||||
|
!connectionError && Boolean(selectedAdvancedFields.length);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{!connectionError && getTabs()}
|
{!connectionError && getTabs()}
|
||||||
<PageLayout
|
<PageLayout
|
||||||
leftPanel={Boolean(!error) && fetchLeftPanel()}
|
leftPanel={Boolean(!error) && fetchLeftPanel()}
|
||||||
rightPanel={Boolean(!error) && <></>}>
|
rightPanel={Boolean(!error) && <></>}>
|
||||||
|
{advanceFieldCheck && (
|
||||||
|
<AdvancedFields
|
||||||
|
fields={selectedAdvancedFields}
|
||||||
|
index={searchIndex}
|
||||||
|
onClear={onAdvancedFieldClear}
|
||||||
|
onFieldRemove={onAdvancedFieldRemove}
|
||||||
|
onFieldValueSelect={onAdvancedFieldValueSelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{error ? (
|
{error ? (
|
||||||
<ErrorPlaceHolderES errorMessage={error} type="error" />
|
<ErrorPlaceHolderES errorMessage={error} type="error" />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { tableSortingFields } from '../../constants/constants';
|
||||||
|
import SortingDropDown from './SortingDropDown';
|
||||||
|
|
||||||
|
const handleFieldDropDown = jest.fn();
|
||||||
|
const fieldList = tableSortingFields;
|
||||||
|
const sortField = '';
|
||||||
|
|
||||||
|
const mockPorps = {
|
||||||
|
fieldList,
|
||||||
|
sortField,
|
||||||
|
handleFieldDropDown,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Test Sorting DropDown Component', () => {
|
||||||
|
it('Should render dropdown component', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<SortingDropDown {...mockPorps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownLabel = await findByTestId('dropdown-label');
|
||||||
|
|
||||||
|
expect(dropdownLabel).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(dropdownLabel);
|
||||||
|
|
||||||
|
const dropdownMenu = await findByTestId('dropdown-menu');
|
||||||
|
|
||||||
|
expect(dropdownMenu).toBeInTheDocument();
|
||||||
|
|
||||||
|
const menuItems = await findAllByTestId('dropdown-menu-item');
|
||||||
|
|
||||||
|
expect(menuItems).toHaveLength(fieldList.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should call onSelect method on onClick option', async () => {
|
||||||
|
const { findByTestId, findAllByTestId } = render(
|
||||||
|
<SortingDropDown {...mockPorps} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const dropdownLabel = await findByTestId('dropdown-label');
|
||||||
|
|
||||||
|
expect(dropdownLabel).toBeInTheDocument();
|
||||||
|
|
||||||
|
fireEvent.click(dropdownLabel);
|
||||||
|
|
||||||
|
const dropdownMenu = await findByTestId('dropdown-menu');
|
||||||
|
|
||||||
|
expect(dropdownMenu).toBeInTheDocument();
|
||||||
|
|
||||||
|
const menuItems = await findAllByTestId('dropdown-menu-item');
|
||||||
|
|
||||||
|
expect(menuItems).toHaveLength(fieldList.length);
|
||||||
|
|
||||||
|
fireEvent.click(menuItems[0]);
|
||||||
|
|
||||||
|
expect(handleFieldDropDown).toHaveBeenCalledWith('last_updated_timestamp');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Dropdown, Menu } from 'antd';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import { normalLink } from '../../utils/styleconstant';
|
||||||
|
import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
sortField: string;
|
||||||
|
fieldList: Array<{ name: string; value: string }>;
|
||||||
|
handleFieldDropDown: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SortingDropDown: FC<Props> = ({
|
||||||
|
fieldList,
|
||||||
|
handleFieldDropDown,
|
||||||
|
sortField,
|
||||||
|
}) => {
|
||||||
|
const items = fieldList.map((field) => ({
|
||||||
|
label: field.name,
|
||||||
|
key: field.value,
|
||||||
|
onClick: () => handleFieldDropDown(field.value),
|
||||||
|
'data-testid': 'dropdown-menu-item',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const menu = <Menu data-testid="dropdown-menu" items={items} />;
|
||||||
|
|
||||||
|
const label = fieldList.find((field) => field.value === sortField)?.name;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
className="tw-self-center tw-mr-2 tw-cursor-pointer"
|
||||||
|
data-testid="dropdown"
|
||||||
|
overlay={menu}
|
||||||
|
trigger={['click']}>
|
||||||
|
<div className="tw-text-primary" data-testid="dropdown-label">
|
||||||
|
<span className="tw-mr-2">{label}</span>
|
||||||
|
<DropDownIcon style={{ color: normalLink, margin: '0px' }} />
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SortingDropDown;
|
||||||
@ -60,3 +60,8 @@ export interface ExploreProps {
|
|||||||
fetchData: (value: SearchDataFunctionType[]) => void;
|
fetchData: (value: SearchDataFunctionType[]) => void;
|
||||||
onShowDeleted: (checked: boolean) => void;
|
onShowDeleted: (checked: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AdvanceField {
|
||||||
|
key: string;
|
||||||
|
value: string | undefined;
|
||||||
|
}
|
||||||
|
|||||||
@ -229,15 +229,16 @@ const Appbar: React.FC = (): JSX.Element => {
|
|||||||
const searchHandler = (value: string) => {
|
const searchHandler = (value: string) => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
addToRecentSearched(value);
|
addToRecentSearched(value);
|
||||||
history.push(
|
history.push({
|
||||||
getExplorePathWithSearch(
|
pathname: getExplorePathWithSearch(
|
||||||
value,
|
value,
|
||||||
// this is for if user is searching from another page
|
// this is for if user is searching from another page
|
||||||
location.pathname.startsWith(ROUTES.EXPLORE)
|
location.pathname.startsWith(ROUTES.EXPLORE)
|
||||||
? appState.explorePageTab
|
? appState.explorePageTab
|
||||||
: 'tables'
|
: 'tables'
|
||||||
)
|
),
|
||||||
);
|
search: location.search,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const COMMON_DROPDOWN_ITEMS = [
|
||||||
|
{
|
||||||
|
label: 'Owner',
|
||||||
|
key: 'owner.name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Tag',
|
||||||
|
key: 'tags',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Service',
|
||||||
|
key: 'servicename',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const TABLE_DROPDOWN_ITEMS = [
|
||||||
|
{
|
||||||
|
label: 'Column',
|
||||||
|
key: 'column_names',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Schema',
|
||||||
|
key: 'databaseschema',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Database',
|
||||||
|
key: 'database',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const DASHBOARD_DROPDOWN_ITEMS = [
|
||||||
|
{
|
||||||
|
label: 'Chart',
|
||||||
|
key: 'chart_names',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const PIPELINE_DROPDOWN_ITEMS = [
|
||||||
|
{
|
||||||
|
label: 'Task',
|
||||||
|
key: 'task_names',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ALL_DROPDOWN_ITEMS = [
|
||||||
|
...COMMON_DROPDOWN_ITEMS,
|
||||||
|
...TABLE_DROPDOWN_ITEMS,
|
||||||
|
...DASHBOARD_DROPDOWN_ITEMS,
|
||||||
|
...PIPELINE_DROPDOWN_ITEMS,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const MISC_FIELDS = ['owner.name', 'tags'];
|
||||||
@ -116,15 +116,15 @@ export const tableSortingFields = [
|
|||||||
value: 'last_updated_timestamp',
|
value: 'last_updated_timestamp',
|
||||||
},
|
},
|
||||||
{ name: 'Weekly Usage', value: 'weekly_stats' },
|
{ name: 'Weekly Usage', value: 'weekly_stats' },
|
||||||
// { name: 'Daily Usage', value: 'daily_stats' },
|
{ name: 'Relevance', value: '' },
|
||||||
// { name: 'Monthly Usage', value: 'monthly_stats' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const topicSortingFields = [
|
export const entitySortingFields = [
|
||||||
{
|
{
|
||||||
name: 'Last Updated',
|
name: 'Last Updated',
|
||||||
value: 'last_updated_timestamp',
|
value: 'last_updated_timestamp',
|
||||||
},
|
},
|
||||||
|
{ name: 'Relevance', value: '' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const sortingOrder = [
|
export const sortingOrder = [
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { AggregationType, Bucket, FilterObject } from 'Models';
|
|||||||
import { SearchIndex } from '../enums/search.enum';
|
import { SearchIndex } from '../enums/search.enum';
|
||||||
import { getFilterKey } from '../utils/FilterUtils';
|
import { getFilterKey } from '../utils/FilterUtils';
|
||||||
import { Icons } from '../utils/SvgUtils';
|
import { Icons } from '../utils/SvgUtils';
|
||||||
import { tableSortingFields, tiers, topicSortingFields } from './constants';
|
import { entitySortingFields, tableSortingFields, tiers } from './constants';
|
||||||
|
|
||||||
export const INITIAL_SORT_FIELD = 'last_updated_timestamp';
|
export const INITIAL_SORT_FIELD = 'last_updated_timestamp';
|
||||||
export const INITIAL_SORT_ORDER = 'desc';
|
export const INITIAL_SORT_ORDER = 'desc';
|
||||||
@ -232,7 +232,7 @@ export const tabsInfo = [
|
|||||||
label: 'Tables',
|
label: 'Tables',
|
||||||
index: SearchIndex.TABLE,
|
index: SearchIndex.TABLE,
|
||||||
sortingFields: tableSortingFields,
|
sortingFields: tableSortingFields,
|
||||||
sortField: '',
|
sortField: INITIAL_SORT_FIELD,
|
||||||
tab: 1,
|
tab: 1,
|
||||||
path: 'tables',
|
path: 'tables',
|
||||||
icon: Icons.TABLE_GREY,
|
icon: Icons.TABLE_GREY,
|
||||||
@ -241,8 +241,8 @@ export const tabsInfo = [
|
|||||||
{
|
{
|
||||||
label: 'Topics',
|
label: 'Topics',
|
||||||
index: SearchIndex.TOPIC,
|
index: SearchIndex.TOPIC,
|
||||||
sortingFields: topicSortingFields,
|
sortingFields: entitySortingFields,
|
||||||
sortField: '',
|
sortField: INITIAL_SORT_FIELD,
|
||||||
tab: 2,
|
tab: 2,
|
||||||
path: 'topics',
|
path: 'topics',
|
||||||
icon: Icons.TOPIC_GREY,
|
icon: Icons.TOPIC_GREY,
|
||||||
@ -251,8 +251,8 @@ export const tabsInfo = [
|
|||||||
{
|
{
|
||||||
label: 'Dashboards',
|
label: 'Dashboards',
|
||||||
index: SearchIndex.DASHBOARD,
|
index: SearchIndex.DASHBOARD,
|
||||||
sortingFields: topicSortingFields,
|
sortingFields: entitySortingFields,
|
||||||
sortField: '',
|
sortField: INITIAL_SORT_FIELD,
|
||||||
tab: 3,
|
tab: 3,
|
||||||
path: 'dashboards',
|
path: 'dashboards',
|
||||||
icon: Icons.DASHBOARD_GREY,
|
icon: Icons.DASHBOARD_GREY,
|
||||||
@ -261,8 +261,8 @@ export const tabsInfo = [
|
|||||||
{
|
{
|
||||||
label: 'Pipelines',
|
label: 'Pipelines',
|
||||||
index: SearchIndex.PIPELINE,
|
index: SearchIndex.PIPELINE,
|
||||||
sortingFields: topicSortingFields,
|
sortingFields: entitySortingFields,
|
||||||
sortField: '',
|
sortField: INITIAL_SORT_FIELD,
|
||||||
tab: 4,
|
tab: 4,
|
||||||
path: 'pipelines',
|
path: 'pipelines',
|
||||||
icon: Icons.PIPELINE_GREY,
|
icon: Icons.PIPELINE_GREY,
|
||||||
@ -271,8 +271,8 @@ export const tabsInfo = [
|
|||||||
{
|
{
|
||||||
label: 'ML Models',
|
label: 'ML Models',
|
||||||
index: SearchIndex.MLMODEL,
|
index: SearchIndex.MLMODEL,
|
||||||
sortingFields: topicSortingFields,
|
sortingFields: entitySortingFields,
|
||||||
sortField: '',
|
sortField: INITIAL_SORT_FIELD,
|
||||||
tab: 5,
|
tab: 5,
|
||||||
path: 'mlmodels',
|
path: 'mlmodels',
|
||||||
icon: '',
|
icon: '',
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum AdvancedFields {
|
||||||
|
COLUMN = 'column_suggest',
|
||||||
|
DATABASE = 'database_suggest',
|
||||||
|
SCHEMA = 'schema_suggest',
|
||||||
|
SERVICE = 'service_suggest',
|
||||||
|
CHART = 'chart_suggest',
|
||||||
|
TASK = 'task_suggest',
|
||||||
|
}
|
||||||
@ -45,7 +45,6 @@ import {
|
|||||||
getQueryParam,
|
getQueryParam,
|
||||||
getSearchFilter,
|
getSearchFilter,
|
||||||
INITIAL_FROM,
|
INITIAL_FROM,
|
||||||
INITIAL_SORT_FIELD,
|
|
||||||
INITIAL_SORT_ORDER,
|
INITIAL_SORT_ORDER,
|
||||||
tabsInfo,
|
tabsInfo,
|
||||||
ZERO_SIZE,
|
ZERO_SIZE,
|
||||||
@ -81,9 +80,7 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
const [searchResult, setSearchResult] = useState<ExploreSearchData>();
|
const [searchResult, setSearchResult] = useState<ExploreSearchData>();
|
||||||
const [showDeleted, setShowDeleted] = useState(false);
|
const [showDeleted, setShowDeleted] = useState(false);
|
||||||
const [initialSortField] = useState<string>(
|
const [initialSortField] = useState<string>(
|
||||||
searchQuery
|
tabsInfo[getCurrentTab(tab) - 1].sortField
|
||||||
? tabsInfo[getCurrentTab(tab) - 1].sortField
|
|
||||||
: INITIAL_SORT_FIELD
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSearchText = (text: string) => {
|
const handleSearchText = (text: string) => {
|
||||||
|
|||||||
@ -992,3 +992,22 @@ code {
|
|||||||
.ant-card-extra {
|
.ant-card-extra {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-advaced-field-select {
|
||||||
|
color: #7147e8;
|
||||||
|
min-width: 130px;
|
||||||
|
}
|
||||||
|
.ant-suggestion-dropdown {
|
||||||
|
min-width: 200px !important;
|
||||||
|
}
|
||||||
|
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
|
||||||
|
background-color: #dbd1f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||||
|
padding: 0px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-single .ant-select-selector .ant-select-selection-search {
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { isUndefined } from 'lodash';
|
||||||
|
import {
|
||||||
|
ALL_DROPDOWN_ITEMS,
|
||||||
|
COMMON_DROPDOWN_ITEMS,
|
||||||
|
DASHBOARD_DROPDOWN_ITEMS,
|
||||||
|
PIPELINE_DROPDOWN_ITEMS,
|
||||||
|
TABLE_DROPDOWN_ITEMS,
|
||||||
|
} from '../constants/advanceSearch.constants';
|
||||||
|
import { AdvancedFields } from '../enums/AdvancedSearch.enum';
|
||||||
|
import { SearchIndex } from '../enums/search.enum';
|
||||||
|
|
||||||
|
export const getDropDownItems = (index: string) => {
|
||||||
|
switch (index) {
|
||||||
|
case SearchIndex.TABLE:
|
||||||
|
return [...TABLE_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
|
case SearchIndex.TOPIC:
|
||||||
|
return [...COMMON_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
|
case SearchIndex.DASHBOARD:
|
||||||
|
return [...DASHBOARD_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
|
case SearchIndex.PIPELINE:
|
||||||
|
return [...PIPELINE_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
|
case SearchIndex.MLMODEL:
|
||||||
|
return [
|
||||||
|
...COMMON_DROPDOWN_ITEMS.filter((item) => item.key !== 'service_type'),
|
||||||
|
];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getItemLabel = (key: string) => {
|
||||||
|
const item = ALL_DROPDOWN_ITEMS.find((dItem) => dItem.key === key);
|
||||||
|
|
||||||
|
return !isUndefined(item) ? item.label : 'label';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAdvancedField = (field: string) => {
|
||||||
|
switch (field) {
|
||||||
|
case 'column_names':
|
||||||
|
return AdvancedFields.COLUMN;
|
||||||
|
|
||||||
|
case 'databaseschema':
|
||||||
|
return AdvancedFields.SCHEMA;
|
||||||
|
|
||||||
|
case 'database':
|
||||||
|
return AdvancedFields.DATABASE;
|
||||||
|
|
||||||
|
case 'chart_names':
|
||||||
|
return AdvancedFields.CHART;
|
||||||
|
|
||||||
|
case 'task_names':
|
||||||
|
return AdvancedFields.TASK;
|
||||||
|
|
||||||
|
case 'servicename':
|
||||||
|
return AdvancedFields.SERVICE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -35,7 +35,7 @@ export const getSearchAPIQuery = (
|
|||||||
filters ? ` AND ${filters}` : ''
|
filters ? ` AND ${filters}` : ''
|
||||||
}&from=${start}&size=${size}${onlyDeleted ? '&deleted=true' : ''}${
|
}&from=${start}&size=${size}${onlyDeleted ? '&deleted=true' : ''}${
|
||||||
sortField ? `&sort_field=${sortField}` : ''
|
sortField ? `&sort_field=${sortField}` : ''
|
||||||
}${sortOrder ? `&sort_order=${sortOrder}` : ''}${
|
}${sortOrder && sortField ? `&sort_order=${sortOrder}` : ''}${
|
||||||
searchIndex ? `&index=${searchIndex}` : ''
|
searchIndex ? `&index=${searchIndex}` : ''
|
||||||
}${trackTotalHits ? '&track_total_hits=true' : ''}`;
|
}${trackTotalHits ? '&track_total_hits=true' : ''}`;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user