diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.test.tsx b/catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.test.tsx similarity index 60% rename from catalog-rest-service/src/main/resources/ui/src/pages/explore/index.test.tsx rename to catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.test.tsx index ee47cd68a5a..e5af0bfaa42 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.test.tsx +++ b/catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.test.tsx @@ -16,21 +16,16 @@ */ import { findAllByTestId, findByTestId, render } from '@testing-library/react'; +import { SearchResponse } from 'Models'; import React from 'react'; import { MemoryRouter } from 'react-router'; -import ExplorePage from './index'; -import { mockResponse } from './index.mock'; +import { mockResponse } from './exlore.mock'; +import Explore from './Explore.component'; jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), - useParams: jest.fn().mockImplementation(() => ({ searchQuery: '' })), useLocation: jest.fn().mockImplementation(() => ({ search: '' })), })); -jest.mock('../../axiosAPIs/miscAPI', () => ({ - searchData: jest - .fn() - .mockImplementation(() => Promise.resolve({ data: mockResponse })), -})); jest.mock('../../utils/FilterUtils', () => ({ getFilterString: jest.fn().mockImplementation(() => 'user.address'), })); @@ -45,15 +40,47 @@ jest.mock('../../components/searched-data/SearchedData', () => { )); }); -jest.mock('../../hooks/useToastContext', () => { - return () => jest.fn(); -}); +const handleSearchText = jest.fn(); +const updateTableCount = jest.fn(); +const updateTopicCount = jest.fn(); +const updateDashboardCount = jest.fn(); +const updatePipelineCount = jest.fn(); +const fetchData = jest.fn(); -describe('Test Explore page', () => { +const mockSearchResult = { + resSearchResults: mockResponse as unknown as SearchResponse, + resAggServiceType: mockResponse as unknown as SearchResponse, + resAggTier: mockResponse as unknown as SearchResponse, + resAggTag: mockResponse as unknown as SearchResponse, +}; + +describe('Test Explore component', () => { it('Component should render', async () => { - const { container } = render(, { - wrapper: MemoryRouter, - }); + const { container } = render( + , + { + wrapper: MemoryRouter, + } + ); const pageContainer = await findByTestId(container, 'fluid-container'); const searchData = await findByTestId(container, 'search-data'); const wrappedContent = await findByTestId(container, 'wrapped-content'); diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.tsx b/catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.tsx similarity index 68% rename from catalog-rest-service/src/main/resources/ui/src/pages/explore/index.tsx rename to catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.tsx index a9e8f43f132..1addd8321b3 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.tsx +++ b/catalog-rest-service/src/main/resources/ui/src/components/Explore/Explore.component.tsx @@ -15,20 +15,17 @@ * limitations under the License. */ -import { AxiosError } from 'axios'; import classNames from 'classnames'; import { cloneDeep } from 'lodash'; import { AggregationType, - Bucket, FilterObject, FormatedTableData, SearchResponse, } from 'Models'; import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useHistory, useLocation, useParams } from 'react-router-dom'; +import { useHistory, useLocation } from 'react-router-dom'; import AppState from '../../AppState'; -import { searchData } from '../../axiosAPIs/miscAPI'; import { Button } from '../../components/buttons/Button/Button'; import ErrorPlaceHolderES from '../../components/common/error-with-placeholder/ErrorPlaceHolderES'; import FacetFilter from '../../components/common/facetfilter/FacetFilter'; @@ -36,7 +33,6 @@ import PageContainer from '../../components/containers/PageContainer'; import DropDownList from '../../components/dropdown/DropDownList'; import SearchedData from '../../components/searched-data/SearchedData'; import { - ERROR500, getExplorePathWithSearch, PAGE_SIZE, tableSortingFields, @@ -44,16 +40,14 @@ import { } from '../../constants/constants'; import { SearchIndex } from '../../enums/search.enum'; import { usePrevious } from '../../hooks/usePrevious'; -import useToastContext from '../../hooks/useToastContext'; import { getAggregationList } from '../../utils/AggregationUtils'; import { formatDataResponse } from '../../utils/APIUtils'; import { getCountBadge } from '../../utils/CommonUtils'; import { getFilterString } from '../../utils/FilterUtils'; -import { getTotalEntityCountByService } from '../../utils/ServiceUtils'; import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant'; import SVGIcons from '../../utils/SvgUtils'; import { getAggrWithDefaultValue, tabsInfo } from './explore.constants'; -import { Params } from './explore.interface'; +import { ExploreProps } from './explore.interface'; const getQueryParam = (urlSearchQuery = ''): FilterObject => { const arrSearchQuery = urlSearchQuery @@ -125,36 +119,43 @@ const getCurrentIndex = (tab: string) => { return currentIndex; }; -const ExplorePage: React.FC = (): React.ReactElement => { +const Explore: React.FC = ({ + tabCounts, + searchText, + tab, + searchQuery, + searchResult, + error, + isLoading, + handleSearchText, + fetchData, + updateTableCount, + updateTopicCount, + updateDashboardCount, + updatePipelineCount, +}: ExploreProps) => { const location = useLocation(); const history = useHistory(); const filterObject: FilterObject = { ...{ tags: [], service: [], tier: [] }, ...getQueryParam(location.search), }; - const showToast = useToastContext(); - const { searchQuery, tab } = useParams(); - const [searchText, setSearchText] = useState(searchQuery || ''); const [data, setData] = useState>([]); const [filters, setFilters] = useState(filterObject); const [currentPage, setCurrentPage] = useState(1); const [totalNumberOfValue, setTotalNumberOfValues] = useState(0); const [aggregations, setAggregations] = useState>([]); - const [isLoading, setIsLoading] = useState(true); const [searchTag, setSearchTag] = useState(location.search); - const [error, setError] = useState(''); + const [fieldListVisible, setFieldListVisible] = useState(false); const [sortField, setSortField] = useState(''); const [sortOrder, setSortOrder] = useState('desc'); const [searchIndex, setSearchIndex] = useState(getCurrentIndex(tab)); const [currentTab, setCurrentTab] = useState(getCurrentTab(tab)); - const [tableCount, setTableCount] = useState(0); - const [topicCount, setTopicCount] = useState(0); - const [dashboardCount, setDashboardCount] = useState(0); - const [pipelineCount, setPipelineCount] = useState(0); const [fieldList, setFieldList] = useState>(tableSortingFields); const isMounting = useRef(true); + const forceSetAgg = useRef(false); const previsouIndex = usePrevious(searchIndex); const handleSelectedFilter = ( @@ -238,19 +239,19 @@ const ExplorePage: React.FC = (): React.ReactElement => { const setCount = (count = 0) => { switch (searchIndex) { case SearchIndex.TABLE: - setTableCount(count); + updateTableCount(count); break; case SearchIndex.DASHBOARD: - setDashboardCount(count); + updateDashboardCount(count); break; case SearchIndex.TOPIC: - setTopicCount(count); + updateTopicCount(count); break; case SearchIndex.PIPELINE: - setPipelineCount(count); + updatePipelineCount(count); break; default: @@ -258,176 +259,47 @@ const ExplorePage: React.FC = (): React.ReactElement => { } }; - const fetchCounts = () => { - const emptyValue = ''; - const tableCount = searchData( - searchText, - 0, - 0, - emptyValue, - emptyValue, - emptyValue, - SearchIndex.TABLE - ); - const topicCount = searchData( - searchText, - 0, - 0, - emptyValue, - emptyValue, - emptyValue, - SearchIndex.TOPIC - ); - const dashboardCount = searchData( - searchText, - 0, - 0, - emptyValue, - emptyValue, - emptyValue, - SearchIndex.DASHBOARD - ); - const pipelineCount = searchData( - searchText, - 0, - 0, - emptyValue, - emptyValue, - emptyValue, - SearchIndex.PIPELINE - ); - Promise.allSettled([ - tableCount, - topicCount, - dashboardCount, - pipelineCount, - ]).then( - ([ - table, - topic, - dashboard, - pipeline, - ]: PromiseSettledResult[]) => { - setTableCount( - table.status === 'fulfilled' - ? getTotalEntityCountByService( - table.value.data.aggregations?.['sterms#Service'] - ?.buckets as Bucket[] - ) - : 0 - ); - setTopicCount( - topic.status === 'fulfilled' - ? getTotalEntityCountByService( - topic.value.data.aggregations?.['sterms#Service'] - ?.buckets as Bucket[] - ) - : 0 - ); - setDashboardCount( - dashboard.status === 'fulfilled' - ? getTotalEntityCountByService( - dashboard.value.data.aggregations?.['sterms#Service'] - ?.buckets as Bucket[] - ) - : 0 - ); - setPipelineCount( - pipeline.status === 'fulfilled' - ? getTotalEntityCountByService( - pipeline.value.data.aggregations?.['sterms#Service'] - ?.buckets as Bucket[] - ) - : 0 - ); - } - ); - }; + const fetchTableData = () => { + const fetchParams = [ + { + queryString: searchText, + from: currentPage, + size: PAGE_SIZE, + filters: getFilterString(filters), + sortField: sortField, + sortOrder: sortOrder, + searchIndex: searchIndex, + }, + { + queryString: searchText, + from: currentPage, + size: 0, + filters: getFilterString(filters, ['service']), + sortField: sortField, + sortOrder: sortOrder, + searchIndex: searchIndex, + }, + { + queryString: searchText, + from: currentPage, + size: 0, + filters: getFilterString(filters, ['tier']), + sortField: sortField, + sortOrder: sortOrder, + searchIndex: searchIndex, + }, + { + queryString: searchText, + from: currentPage, + size: 0, + filters: getFilterString(filters, ['tags']), + sortField: sortField, + sortOrder: sortOrder, + searchIndex: searchIndex, + }, + ]; - const fetchTableData = (forceSetAgg: boolean) => { - setIsLoading(true); - - const searchResults = searchData( - searchText, - currentPage, - PAGE_SIZE, - getFilterString(filters), - sortField, - sortOrder, - searchIndex - ); - const serviceTypeAgg = searchData( - searchText, - currentPage, - 0, - getFilterString(filters, ['service']), - sortField, - sortOrder, - searchIndex - ); - const tierAgg = searchData( - searchText, - currentPage, - 0, - getFilterString(filters, ['tier']), - sortField, - sortOrder, - searchIndex - ); - const tagAgg = searchData( - searchText, - currentPage, - 0, - getFilterString(filters, ['tags']), - sortField, - sortOrder, - searchIndex - ); - - Promise.all([searchResults, serviceTypeAgg, tierAgg, tagAgg]) - .then( - ([ - resSearchResults, - resAggServiceType, - resAggTier, - resAggTag, - ]: Array) => { - updateSearchResults(resSearchResults); - setCount(resSearchResults.data.hits.total.value); - if (forceSetAgg) { - setAggregations( - resSearchResults.data.hits.hits.length > 0 - ? getAggregationList(resSearchResults.data.aggregations) - : [] - ); - } else { - const aggServiceType = getAggregationList( - resAggServiceType.data.aggregations, - 'service' - ); - const aggTier = getAggregationList( - resAggTier.data.aggregations, - 'tier' - ); - const aggTag = getAggregationList( - resAggTag.data.aggregations, - 'tags' - ); - - updateAggregationCount([...aggServiceType, ...aggTier, ...aggTag]); - } - setIsLoading(false); - } - ) - .catch((err: AxiosError) => { - setError(err.response?.data?.responseMessage); - showToast({ - variant: 'error', - body: err.response?.data?.responseMessage ?? ERROR500, - }); - - setIsLoading(false); - }); + fetchData(fetchParams); }; const getFacetedFilter = () => { @@ -515,13 +387,13 @@ const ExplorePage: React.FC = (): React.ReactElement => { const getTabCount = (index: string) => { switch (index) { case SearchIndex.TABLE: - return getCountBadge(tableCount); + return getCountBadge(tabCounts.table); case SearchIndex.TOPIC: - return getCountBadge(topicCount); + return getCountBadge(tabCounts.topic); case SearchIndex.DASHBOARD: - return getCountBadge(dashboardCount); + return getCountBadge(tabCounts.dashboard); case SearchIndex.PIPELINE: - return getCountBadge(pipelineCount); + return getCountBadge(tabCounts.pipeline); default: return getCountBadge(); } @@ -543,23 +415,23 @@ const ExplorePage: React.FC = (): React.ReactElement => { - {tabsInfo.map((tab, index) => ( + {tabsInfo.map((tabDetail, index) => ( { - onTabChange(tab.tab); + onTabChange(tabDetail.tab); }}> - {tab.label} - {getTabCount(tab.index)} + {tabDetail.label} + {getTabCount(tabDetail.index)} ))} @@ -570,7 +442,7 @@ const ExplorePage: React.FC = (): React.ReactElement => { }; useEffect(() => { - setSearchText(searchQuery || ''); + handleSearchText(searchQuery || ''); setCurrentPage(1); }, [searchQuery]); @@ -579,7 +451,6 @@ const ExplorePage: React.FC = (): React.ReactElement => { setFieldList(tabsInfo[getCurrentTab(tab) - 1].sortingFields); setSortField(tabsInfo[getCurrentTab(tab) - 1].sortField); setSortOrder('desc'); - setError(''); setCurrentTab(getCurrentTab(tab)); setSearchIndex(getCurrentIndex(tab)); setCurrentPage(1); @@ -592,18 +463,47 @@ const ExplorePage: React.FC = (): React.ReactElement => { }, [searchText, filters]); useEffect(() => { - fetchTableData(true); + forceSetAgg.current = true; + fetchTableData(); }, [searchText, searchIndex]); useEffect(() => { - if (!isMounting.current && previsouIndex === getCurrentIndex(tab)) { - fetchTableData(false); + if (searchResult) { + updateSearchResults(searchResult.resSearchResults); + setCount(searchResult.resSearchResults.data.hits.total.value); + if (forceSetAgg.current) { + setAggregations( + searchResult.resSearchResults.data.hits.hits.length > 0 + ? getAggregationList( + searchResult.resSearchResults.data.aggregations + ) + : [] + ); + } else { + const aggServiceType = getAggregationList( + searchResult.resAggServiceType.data.aggregations, + 'service' + ); + const aggTier = getAggregationList( + searchResult.resAggTier.data.aggregations, + 'tier' + ); + const aggTag = getAggregationList( + searchResult.resAggTag.data.aggregations, + 'tags' + ); + + updateAggregationCount([...aggServiceType, ...aggTier, ...aggTag]); + } } - }, [currentPage, filters, sortField, sortOrder]); + }, [searchResult]); useEffect(() => { - fetchCounts(); - }, [searchText]); + if (!isMounting.current && previsouIndex === getCurrentIndex(tab)) { + forceSetAgg.current = false; + fetchTableData(); + } + }, [currentPage, filters, sortField, sortOrder]); // alwyas Keep this useEffect at the end... useEffect(() => { @@ -647,4 +547,4 @@ const ExplorePage: React.FC = (): React.ReactElement => { ); }; -export default ExplorePage; +export default Explore; diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.mock.js b/catalog-rest-service/src/main/resources/ui/src/components/Explore/exlore.mock.js similarity index 69% rename from catalog-rest-service/src/main/resources/ui/src/pages/explore/index.mock.js rename to catalog-rest-service/src/main/resources/ui/src/components/Explore/exlore.mock.js index e9f6acc17b8..264c7b1687a 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/explore/index.mock.js +++ b/catalog-rest-service/src/main/resources/ui/src/components/Explore/exlore.mock.js @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint-disable @typescript-eslint/camelcase */ const todayData = [ { @@ -209,17 +210,75 @@ export const entitiesData = [ export const tiers = ['Tier1', 'Tier2', 'Tier3', 'Tier4', 'Tier5']; export const mockResponse = { - hits: { + data: { hits: { - tableId: '09ac866c-a18d-4470-abc8-52deed3d90d6', - database: 'dwh', - tableName: 'fact_sale', - serviceName: 'MYSQL', - description: 'this is the table to hold data on fact_sale', - tableType: 'null', + total: { + value: 15, + relation: 'eq', + }, + max_score: 5, + hits: [ + { + _index: 'table_search_index', + _type: '_doc', + _id: 'b5860f51-a197-48c8-9506-ee67da190d83', + _score: 5, + _source: { + table_id: 'b5860f51-a197-48c8-9506-ee67da190d83', + database: 'bigquery.shopify', + service: 'bigquery', + service_type: 'BigQuery', + table_name: 'dim_address', + suggest: [ + { + input: ['bigquery.shopify.dim_address'], + weight: 5, + }, + { + input: ['dim_address'], + weight: 10, + }, + ], + description: + 'This dimension table contains the billing and shipping addresses of customers. You can join this table.', + table_type: 'Regular', + last_updated_timestamp: 1634886627, + column_names: ['address_id', 'shop_id'], + column_descriptions: [ + 'Unique identifier for the address.', + 'The ID of the store. This column is a foreign key reference to the shop_id column in the dim_shop table.', + ], + tags: [], + fqdn: 'bigquery.shopify.dim_address', + tier: null, + schema_description: null, + owner: '', + followers: [], + }, + }, + ], }, - total: { - value: 128, + aggregations: { + 'sterms#Tier': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, + 'sterms#Service': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'BigQuery', + doc_count: 15, + }, + ], + }, + 'sterms#Tags': { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, }, }, }; diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/explore.constants.ts b/catalog-rest-service/src/main/resources/ui/src/components/Explore/explore.constants.ts similarity index 100% rename from catalog-rest-service/src/main/resources/ui/src/pages/explore/explore.constants.ts rename to catalog-rest-service/src/main/resources/ui/src/components/Explore/explore.constants.ts diff --git a/catalog-rest-service/src/main/resources/ui/src/components/Explore/explore.interface.ts b/catalog-rest-service/src/main/resources/ui/src/components/Explore/explore.interface.ts new file mode 100644 index 00000000000..478684c8b1b --- /dev/null +++ b/catalog-rest-service/src/main/resources/ui/src/components/Explore/explore.interface.ts @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 { SearchResponse } from 'Models'; + +export type Params = { + searchQuery: string; + tab: string; +}; + +export type Service = { + collection: { + name: string; + documentation: string; + href: string; + }; +}; +export type Team = { + id: string; + name: string; + displayName: string; + description: string; + href: string; +}; + +export type ExploreSearchData = { + resSearchResults: SearchResponse; + resAggServiceType: SearchResponse; + resAggTier: SearchResponse; + resAggTag: SearchResponse; +}; + +export interface FetchData { + queryString: string; + from: number; + size: number; + filters: string; + sortField: string; + sortOrder: string; + searchIndex: string; +} + +export interface ExploreProps { + tabCounts: { + table: number; + topic: number; + dashboard: number; + pipeline: number; + }; + searchText: string; + tab: string; + error: string; + isLoading: boolean; + searchQuery: string; + handleSearchText: (text: string) => void; + updateTableCount: (count: number) => void; + updateTopicCount: (count: number) => void; + updateDashboardCount: (count: number) => void; + updatePipelineCount: (count: number) => void; + fetchData: (value: FetchData[]) => void; + searchResult: ExploreSearchData | undefined; +} diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/explore.interface.ts b/catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.test.tsx similarity index 55% rename from catalog-rest-service/src/main/resources/ui/src/pages/explore/explore.interface.ts rename to catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.test.tsx index 345678712df..8020814c925 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/explore/explore.interface.ts +++ b/catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.test.tsx @@ -15,22 +15,24 @@ * limitations under the License. */ -export type Params = { - searchQuery: string; - tab: string; -}; +import { findByTestId, render } from '@testing-library/react'; +import React from 'react'; +import ExplorePage from './ExplorePage.component'; -export type Service = { - collection: { - name: string; - documentation: string; - href: string; - }; -}; -export type Team = { - id: string; - name: string; - displayName: string; - description: string; - href: string; -}; +jest.mock('react-router-dom', () => ({ + useParams: jest.fn().mockImplementation(() => ({ searchQuery: '' })), +})); + +jest.mock('../../components/Explore/Explore.component', () => { + return jest.fn().mockReturnValue(Explore Component); +}); + +describe('Test Explore page', () => { + it('Page Should render', async () => { + const { container } = render(); + + const explorePage = await findByTestId(container, 'explore-page'); + + expect(explorePage).toBeInTheDocument(); + }); +}); diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.tsx b/catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.tsx new file mode 100644 index 00000000000..723a5ec72b8 --- /dev/null +++ b/catalog-rest-service/src/main/resources/ui/src/pages/explore/ExplorePage.component.tsx @@ -0,0 +1,228 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 { AxiosError } from 'axios'; +import { Bucket, SearchResponse } from 'Models'; +import React, { FunctionComponent, useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { searchData } from '../../axiosAPIs/miscAPI'; +import Explore from '../../components/Explore/Explore.component'; +import { + ExploreSearchData, + FetchData, + Params, +} from '../../components/Explore/explore.interface'; +import Loader from '../../components/Loader/Loader'; +import { ERROR500 } from '../../constants/constants'; +import { SearchIndex } from '../../enums/search.enum'; +import useToastContext from '../../hooks/useToastContext'; +import { getTotalEntityCountByService } from '../../utils/ServiceUtils'; + +const ExplorePage: FunctionComponent = () => { + const showToast = useToastContext(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(''); + const { searchQuery, tab } = useParams(); + const [searchText, setSearchText] = useState(searchQuery || ''); + const [tableCount, setTableCount] = useState(0); + const [topicCount, setTopicCount] = useState(0); + const [dashboardCount, setDashboardCount] = useState(0); + const [pipelineCount, setPipelineCount] = useState(0); + const [searchResult, setSearchResult] = useState(); + + const handleSearchText = (text: string) => { + setSearchText(text); + }; + + const handleTableCount = (count: number) => { + setTableCount(count); + }; + + const handleTopicCount = (count: number) => { + setTopicCount(count); + }; + + const handleDashboardCount = (count: number) => { + setDashboardCount(count); + }; + + const handlePipelineCount = (count: number) => { + setPipelineCount(count); + }; + + const fetchCounts = () => { + const emptyValue = ''; + const tableCount = searchData( + searchText, + 0, + 0, + emptyValue, + emptyValue, + emptyValue, + SearchIndex.TABLE + ); + const topicCount = searchData( + searchText, + 0, + 0, + emptyValue, + emptyValue, + emptyValue, + SearchIndex.TOPIC + ); + const dashboardCount = searchData( + searchText, + 0, + 0, + emptyValue, + emptyValue, + emptyValue, + SearchIndex.DASHBOARD + ); + const pipelineCount = searchData( + searchText, + 0, + 0, + emptyValue, + emptyValue, + emptyValue, + SearchIndex.PIPELINE + ); + + Promise.allSettled([ + tableCount, + topicCount, + dashboardCount, + pipelineCount, + ]).then( + ([ + table, + topic, + dashboard, + pipeline, + ]: PromiseSettledResult[]) => { + setTableCount( + table.status === 'fulfilled' + ? getTotalEntityCountByService( + table.value.data.aggregations?.['sterms#Service'] + ?.buckets as Bucket[] + ) + : 0 + ); + setTopicCount( + topic.status === 'fulfilled' + ? getTotalEntityCountByService( + topic.value.data.aggregations?.['sterms#Service'] + ?.buckets as Bucket[] + ) + : 0 + ); + setDashboardCount( + dashboard.status === 'fulfilled' + ? getTotalEntityCountByService( + dashboard.value.data.aggregations?.['sterms#Service'] + ?.buckets as Bucket[] + ) + : 0 + ); + setPipelineCount( + pipeline.status === 'fulfilled' + ? getTotalEntityCountByService( + pipeline.value.data.aggregations?.['sterms#Service'] + ?.buckets as Bucket[] + ) + : 0 + ); + } + ); + }; + + const fetchData = (value: FetchData[]) => { + setIsLoading(true); + const promiseValue = value.map((d) => { + return searchData( + d.queryString, + d.from, + d.size, + d.filters, + d.sortField, + d.sortOrder, + d.searchIndex + ); + }); + + Promise.all(promiseValue) + .then( + ([ + resSearchResults, + resAggServiceType, + resAggTier, + resAggTag, + ]: Array) => { + setSearchResult({ + resSearchResults, + resAggServiceType, + resAggTier, + resAggTag, + }); + } + ) + .catch((err: AxiosError) => { + setError(err.response?.data?.responseMessage); + showToast({ + variant: 'error', + body: err.response?.data?.responseMessage ?? ERROR500, + }); + }); + setIsLoading(false); + }; + + useEffect(() => { + fetchCounts(); + }, [searchText]); + + return ( + + {isLoading ? ( + + ) : ( + + )} + + ); +}; + +export default ExplorePage; diff --git a/catalog-rest-service/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx b/catalog-rest-service/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx index a693b0b2e30..dab0b264afa 100644 --- a/catalog-rest-service/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx +++ b/catalog-rest-service/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx @@ -24,7 +24,7 @@ import { ROUTES } from '../constants/constants'; import MyDashBoardPage from '../pages/dashboard-details'; import DatabaseDetails from '../pages/database-details/index'; import DatasetDetailsPage from '../pages/DatasetDetailsPage/DatasetDetailsPage.component'; -import ExplorePage from '../pages/explore'; +import ExplorePage from '../pages/explore/ExplorePage.component'; import MyDataPage from '../pages/my-data'; import MyPipelinePage from '../pages/Pipeline-details'; import ReportsPage from '../pages/reports';
Explore Component