mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-31 05:04:39 +00:00
UI: Refector Landing page (#934)
* UI: refactor explore page * rename index to exlore.component for mock file and test file * UI: refactore landing page * Merge Main * re-name test files and my-data folder and miner fix * re-name LandingPage folder to MyData * miner fix
This commit is contained in:
parent
6f46ebbfef
commit
e60986e70a
@ -38,6 +38,10 @@ import {
|
||||
tableSortingFields,
|
||||
visibleFilters,
|
||||
} from '../../constants/constants';
|
||||
import {
|
||||
getAggrWithDefaultValue,
|
||||
tabsInfo,
|
||||
} from '../../constants/explore.constants';
|
||||
import { SearchIndex } from '../../enums/search.enum';
|
||||
import { usePrevious } from '../../hooks/usePrevious';
|
||||
import { getAggregationList } from '../../utils/AggregationUtils';
|
||||
@ -46,7 +50,6 @@ import { getCountBadge } from '../../utils/CommonUtils';
|
||||
import { getFilterString } from '../../utils/FilterUtils';
|
||||
import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant';
|
||||
import SVGIcons from '../../utils/SvgUtils';
|
||||
import { getAggrWithDefaultValue, tabsInfo } from './explore.constants';
|
||||
import { ExploreProps } from './explore.interface';
|
||||
|
||||
const getQueryParam = (urlSearchQuery = ''): FilterObject => {
|
||||
|
@ -15,28 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'Models';
|
||||
import { SearchDataFunctionType, SearchResponse } from 'Models';
|
||||
|
||||
export type Params = {
|
||||
export type UrlParams = {
|
||||
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;
|
||||
@ -44,16 +29,6 @@ export type ExploreSearchData = {
|
||||
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;
|
||||
@ -71,6 +46,6 @@ export interface ExploreProps {
|
||||
updateTopicCount: (count: number) => void;
|
||||
updateDashboardCount: (count: number) => void;
|
||||
updatePipelineCount: (count: number) => void;
|
||||
fetchData: (value: FetchData[]) => void;
|
||||
fetchData: (value: SearchDataFunctionType[]) => void;
|
||||
searchResult: ExploreSearchData | undefined;
|
||||
}
|
||||
|
@ -15,54 +15,50 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AxiosError } from 'axios';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Bucket, FormatedTableData, SearchResponse, Sterm } from 'Models';
|
||||
import { Bucket, FormatedTableData, Sterm } from 'Models';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import AppState from '../../AppState';
|
||||
import { searchData } from '../../axiosAPIs/miscAPI';
|
||||
import ErrorPlaceHolderES from '../../components/common/error-with-placeholder/ErrorPlaceHolderES';
|
||||
import PageContainer from '../../components/containers/PageContainer';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import MyDataHeader from '../../components/my-data/MyDataHeader';
|
||||
import RecentlyViewed from '../../components/recently-viewed/RecentlyViewed';
|
||||
import SearchedData from '../../components/searched-data/SearchedData';
|
||||
import { ERROR500, PAGE_SIZE } from '../../constants/constants';
|
||||
import { Ownership } from '../../enums/mydata.enum';
|
||||
import useToastContext from '../../hooks/useToastContext';
|
||||
import { formatDataResponse } from '../../utils/APIUtils';
|
||||
import { getCurrentUserId } from '../../utils/CommonUtils';
|
||||
import {
|
||||
getAllServices,
|
||||
getEntityCountByService,
|
||||
} from '../../utils/ServiceUtils';
|
||||
import { getEntityCountByService } from '../../utils/ServiceUtils';
|
||||
import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
|
||||
import PageContainer from '../containers/PageContainer';
|
||||
import Loader from '../Loader/Loader';
|
||||
import MyDataHeader from '../my-data/MyDataHeader';
|
||||
import RecentlyViewed from '../recently-viewed/RecentlyViewed';
|
||||
import SearchedData from '../searched-data/SearchedData';
|
||||
import { MyDataProps } from './MyData.interface';
|
||||
|
||||
const MyDataPage: React.FC = (): React.ReactElement => {
|
||||
const showToast = useToastContext();
|
||||
const MyData: React.FC<MyDataProps> = ({
|
||||
countServices,
|
||||
userDetails,
|
||||
searchResult,
|
||||
fetchData,
|
||||
error,
|
||||
}: MyDataProps): React.ReactElement => {
|
||||
const [data, setData] = useState<Array<FormatedTableData>>([]);
|
||||
const [currentPage, setCurrentPage] = useState<number>(1);
|
||||
const [totalNumberOfValue, setTotalNumberOfValues] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [isEntityLoading, setIsEntityLoading] = useState<boolean>(true);
|
||||
const [currentTab, setCurrentTab] = useState<number>(1);
|
||||
const [error, setError] = useState<string>('');
|
||||
const [filter, setFilter] = useState<string>('');
|
||||
const [aggregations, setAggregations] = useState<Record<string, Sterm>>();
|
||||
const [searchIndex] = useState<string>(
|
||||
'dashboard_search_index,topic_search_index,table_search_index,pipeline_search_index'
|
||||
);
|
||||
const [countServices, setCountServices] = useState<number>(0);
|
||||
const isMounted = useRef<boolean>(false);
|
||||
const setAssetCount = useRef<boolean>(true);
|
||||
|
||||
const getActiveTabClass = (tab: number) => {
|
||||
return tab === currentTab ? 'active' : '';
|
||||
};
|
||||
|
||||
const getFilters = (): string => {
|
||||
if (filter === 'owner' && AppState.userDetails.teams) {
|
||||
const userTeams = !isEmpty(AppState.userDetails)
|
||||
? AppState.userDetails.teams.map((team) => `${filter}:${team.id}`)
|
||||
if (filter === 'owner' && userDetails.teams) {
|
||||
const userTeams = !isEmpty(userDetails)
|
||||
? userDetails.teams.map((team) => `${filter}:${team.id}`)
|
||||
: [];
|
||||
const ownerIds = [...userTeams, `${filter}:${getCurrentUserId()}`];
|
||||
|
||||
@ -72,45 +68,19 @@ const MyDataPage: React.FC = (): React.ReactElement => {
|
||||
return `${filter}:${getCurrentUserId()}`;
|
||||
};
|
||||
|
||||
const fetchTableData = (setAssetCount = false) => {
|
||||
const fetchTableData = () => {
|
||||
if (!isEntityLoading) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
searchData(
|
||||
'',
|
||||
currentPage,
|
||||
PAGE_SIZE,
|
||||
filter ? getFilters() : '',
|
||||
'',
|
||||
'',
|
||||
searchIndex
|
||||
)
|
||||
.then((res: SearchResponse) => {
|
||||
const hits = res.data.hits.hits;
|
||||
if (hits.length > 0) {
|
||||
setTotalNumberOfValues(res.data.hits.total.value);
|
||||
setData(formatDataResponse(hits));
|
||||
if (setAssetCount) {
|
||||
setAggregations(res.data.aggregations);
|
||||
}
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
} else {
|
||||
setData([]);
|
||||
setTotalNumberOfValues(0);
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
setError(err.response?.data?.responseMessage);
|
||||
showToast({
|
||||
variant: 'error',
|
||||
body: err.response?.data?.responseMessage ?? ERROR500,
|
||||
});
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
});
|
||||
|
||||
fetchData({
|
||||
queryString: '',
|
||||
from: currentPage,
|
||||
filters: filter ? getFilters() : '',
|
||||
sortField: '',
|
||||
sortOrder: '',
|
||||
searchIndex: searchIndex,
|
||||
});
|
||||
};
|
||||
|
||||
const getTabs = () => {
|
||||
@ -163,14 +133,36 @@ const MyDataPage: React.FC = (): React.ReactElement => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTableData(!isMounted.current);
|
||||
setAssetCount.current = !isMounted.current;
|
||||
fetchTableData();
|
||||
}, [currentPage, filter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchResult) {
|
||||
const hits = searchResult.data.hits.hits;
|
||||
if (hits.length > 0) {
|
||||
setTotalNumberOfValues(searchResult.data.hits.total.value);
|
||||
setData(formatDataResponse(hits));
|
||||
if (setAssetCount.current) {
|
||||
setAggregations(searchResult.data.aggregations);
|
||||
}
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
} else {
|
||||
setData([]);
|
||||
setTotalNumberOfValues(0);
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
setIsEntityLoading(false);
|
||||
}
|
||||
}, [searchResult]);
|
||||
|
||||
useEffect(() => {
|
||||
isMounted.current = true;
|
||||
getAllServices()
|
||||
.then((res) => setCountServices(res.length))
|
||||
.catch(() => setCountServices(0));
|
||||
setAssetCount.current = true;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -212,4 +204,4 @@ const MyDataPage: React.FC = (): React.ReactElement => {
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(MyDataPage);
|
||||
export default MyData;
|
@ -0,0 +1,10 @@
|
||||
import { SearchDataFunctionType, SearchResponse } from 'Models';
|
||||
import { User } from '../../generated/entity/teams/user';
|
||||
|
||||
export interface MyDataProps {
|
||||
countServices: number;
|
||||
userDetails: User;
|
||||
error: string;
|
||||
searchResult: SearchResponse | undefined;
|
||||
fetchData: (value: SearchDataFunctionType) => void;
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
import {
|
||||
findAllByTestId,
|
||||
findByTestId,
|
||||
findByText,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import { SearchResponse } from 'Models';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { User } from '../../generated/entity/teams/user';
|
||||
import MyDataPage from './MyData.component';
|
||||
|
||||
const mockData = {
|
||||
data: {
|
||||
took: 50,
|
||||
timed_out: false,
|
||||
_shards: {
|
||||
total: 1,
|
||||
successful: 1,
|
||||
skipped: 0,
|
||||
failed: 0,
|
||||
},
|
||||
hits: {
|
||||
total: {
|
||||
value: 12,
|
||||
relation: 'eq',
|
||||
},
|
||||
max_score: 5,
|
||||
hits: [
|
||||
{
|
||||
_index: 'table_search_indexcb2cac4c-735e-474e-a968-da8d8e0b218c',
|
||||
_type: '_doc',
|
||||
_id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
_score: 5,
|
||||
_source: {
|
||||
table_id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
database: 'shopify',
|
||||
service: 'bigquery',
|
||||
service_type: 'BigQuery',
|
||||
table_name: 'dim_address',
|
||||
suggest: [
|
||||
{
|
||||
input: ['bigquery.shopify.dim_address'],
|
||||
weight: 5,
|
||||
},
|
||||
{
|
||||
input: ['dim_address'],
|
||||
weight: 10,
|
||||
},
|
||||
],
|
||||
description: 'test description',
|
||||
table_type: null,
|
||||
last_updated_timestamp: 1628498201,
|
||||
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 shops table.',
|
||||
],
|
||||
monthly_stats: 0,
|
||||
weekly_stats: 0,
|
||||
daily_stats: 0,
|
||||
tags: ['User.Phone'],
|
||||
fqdn: 'bigquery.shopify.dim_address',
|
||||
tier: null,
|
||||
schema_description: null,
|
||||
owner: '',
|
||||
followers: [],
|
||||
table_entity: {
|
||||
id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
name: 'dim_address',
|
||||
description: 'test table description',
|
||||
href: 'http://test',
|
||||
tableType: null,
|
||||
fullyQualifiedName: 'bigquery.shopify.dim_address',
|
||||
columns: [
|
||||
{
|
||||
name: 'address_id',
|
||||
columnDataType: 'NUMERIC',
|
||||
description: 'Unique identifier for the address.',
|
||||
fullyQualifiedName: 'bigquery.shopify.dim_address.address_id',
|
||||
tags: [
|
||||
{
|
||||
tagFQN: 'PersonalData.Personal',
|
||||
labelType: 'Derived',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
{
|
||||
tagFQN: 'PII.Sensitive',
|
||||
labelType: 'Derived',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
{
|
||||
tagFQN: 'User.Address',
|
||||
labelType: 'Automated',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
],
|
||||
columnConstraint: 'PRIMARY_KEY',
|
||||
ordinalPosition: 1,
|
||||
},
|
||||
],
|
||||
tableConstraints: null,
|
||||
usageSummary: {
|
||||
dailyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
weeklyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
monthlyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
date: '2021-08-09',
|
||||
},
|
||||
owner: null,
|
||||
followers: [],
|
||||
database: {
|
||||
id: '2d04ddc1-4c9b-43a3-85fb-3de204d67f32',
|
||||
type: 'database',
|
||||
name: 'shopify',
|
||||
description:
|
||||
'This database contains tables related to shopify order and related dimensions',
|
||||
href: 'http://test/test',
|
||||
},
|
||||
tags: [],
|
||||
joins: null,
|
||||
sampleData: null,
|
||||
},
|
||||
},
|
||||
highlight: {
|
||||
description: ['data test'],
|
||||
table_name: ['<b>dim_address</b>'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
aggregations: {
|
||||
'sterms#Tier': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [],
|
||||
},
|
||||
'sterms#Tags': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: 'PII.Sensitive',
|
||||
doc_count: 7,
|
||||
},
|
||||
],
|
||||
},
|
||||
'sterms#Service Type': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: 'BigQuery',
|
||||
doc_count: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockUserDetails = {
|
||||
data: [
|
||||
{
|
||||
id: 'e8672538-d479-4390-b81d-a85eb19c8221',
|
||||
name: 'Cloud_Infra',
|
||||
displayName: 'Cloud Infra',
|
||||
description: '',
|
||||
version: 0.1,
|
||||
updatedAt: 1634886222355,
|
||||
updatedBy: 'anonymous',
|
||||
href: 'http://localhost:8585/api/v1/teams/e8672538-d479-4390-b81d-a85eb19c8221',
|
||||
},
|
||||
{
|
||||
id: '1fffc9a9-33fd-42ca-a605-ab87055bed96',
|
||||
name: 'Customer_Support',
|
||||
displayName: 'Customer Support',
|
||||
description: '',
|
||||
version: 0.1,
|
||||
updatedAt: 1634886221511,
|
||||
updatedBy: 'anonymous',
|
||||
href: 'http://localhost:8585/api/v1/teams/1fffc9a9-33fd-42ca-a605-ab87055bed96',
|
||||
},
|
||||
],
|
||||
paging: {
|
||||
total: 2,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('../../axiosAPIs/miscAPI', () => ({
|
||||
searchData: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ data: mockData })),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/searched-data/SearchedData', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }: { children: React.ReactNode }) => (
|
||||
<div data-testid="search-data">
|
||||
<div data-testid="wrapped-content">{children}</div>
|
||||
</div>
|
||||
));
|
||||
});
|
||||
|
||||
jest.mock('../../components/recently-viewed/RecentlyViewed', () => {
|
||||
return jest.fn().mockReturnValue(<p>RecentlyViewed</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../components/my-data/MyDataHeader', () => {
|
||||
return jest.fn().mockReturnValue(<p>MyDataHeader</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../utils/ServiceUtils', () => ({
|
||||
getAllServices: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(['test', 'test2', 'test3'])),
|
||||
getEntityCountByService: jest
|
||||
.fn()
|
||||
.mockReturnValue({ tableCount: 4, topicCount: 5, dashboardCount: 6 }),
|
||||
getTotalEntityCountByService: jest.fn().mockReturnValue(2),
|
||||
}));
|
||||
|
||||
const fetchData = jest.fn();
|
||||
|
||||
describe('Test MyData page', () => {
|
||||
it('Check if there is an element in the page', async () => {
|
||||
const { container } = render(
|
||||
<MyDataPage
|
||||
countServices={0}
|
||||
error=""
|
||||
fetchData={fetchData}
|
||||
searchResult={mockData as unknown as SearchResponse}
|
||||
userDetails={mockUserDetails as unknown as User}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const pageContainer = await findByTestId(container, 'fluid-container');
|
||||
const searchData = await findByTestId(container, 'search-data');
|
||||
const wrappedContent = await findByTestId(container, 'wrapped-content');
|
||||
const tabs = await findAllByTestId(container, 'tab');
|
||||
const myDataHeader = await findByText(container, /MyDataHeader/i);
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(searchData).toBeInTheDocument();
|
||||
expect(wrappedContent).toBeInTheDocument();
|
||||
expect(myDataHeader).toBeInTheDocument();
|
||||
expect(tabs.length).toBe(3);
|
||||
});
|
||||
});
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { getAllByTestId, getByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { descriptionData } from '../../pages/my-data/index.mock';
|
||||
import { descriptionData } from '../MyData/MyData.mock';
|
||||
import Description from './Description';
|
||||
|
||||
describe('Test Description Component', () => {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { getByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { miscDetailsData } from '../../pages/my-data/index.mock';
|
||||
import { miscDetailsData } from '../MyData/MyData.mock';
|
||||
import MiscDetails from './MiscDetails';
|
||||
|
||||
describe('Test MiscDetails Component', () => {
|
||||
|
@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getDatasetDetailsPath } from '../../constants/constants';
|
||||
import { dummyData } from '../../pages/my-data/index.mock';
|
||||
import { dummyData } from '../MyData/MyData.mock';
|
||||
import Description from './Description';
|
||||
import QueryDetails from './QueryDetails';
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { getByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { dataDetails } from '../../pages/my-data/index.mock';
|
||||
import { dataDetails } from '../MyData/MyData.mock';
|
||||
import MyData from './MyData';
|
||||
|
||||
describe('Test MyData Component', () => {
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { getByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { queryDetailsData } from '../../pages/my-data/index.mock';
|
||||
import { queryDetailsData } from '../MyData/MyData.mock';
|
||||
import QueryDetails from './QueryDetails';
|
||||
|
||||
describe('Test QueryDetails Component', () => {
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { findByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { statData } from '../../pages/my-data/index.mock';
|
||||
import { statData } from '../MyData/MyData.mock';
|
||||
import Stats from './Stats';
|
||||
|
||||
describe('Test Stats Component', () => {
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
|
||||
import { FilterObject } from 'Models';
|
||||
import { getCurrentUserId } from '../../utils/CommonUtils';
|
||||
import { getFilterString } from '../../utils/FilterUtils';
|
||||
import { getCurrentUserId } from '../utils/CommonUtils';
|
||||
import { getFilterString } from '../utils/FilterUtils';
|
||||
|
||||
export const myDataFilterType = [
|
||||
{ key: 'Owned', value: 'owner' },
|
@ -17,13 +17,9 @@
|
||||
|
||||
import { lowerCase } from 'lodash';
|
||||
import { AggregationType, Bucket } from 'Models';
|
||||
import {
|
||||
tableSortingFields,
|
||||
tiers,
|
||||
topicSortingFields,
|
||||
} from '../../constants/constants';
|
||||
import { SearchIndex } from '../../enums/search.enum';
|
||||
import { Icons } from '../../utils/SvgUtils';
|
||||
import { SearchIndex } from '../enums/search.enum';
|
||||
import { Icons } from '../utils/SvgUtils';
|
||||
import { tableSortingFields, tiers, topicSortingFields } from './constants';
|
||||
|
||||
export const getBucketList = (buckets: Array<Bucket>) => {
|
||||
let bucketList: Array<Bucket> = [...tiers];
|
@ -324,6 +324,16 @@ declare module 'Models' {
|
||||
rows: Array<Array<string>>;
|
||||
};
|
||||
|
||||
export type SearchDataFunctionType = {
|
||||
queryString: string;
|
||||
from: number;
|
||||
size?: number;
|
||||
filters: string;
|
||||
sortField: string;
|
||||
sortOrder: string;
|
||||
searchIndex: string;
|
||||
};
|
||||
|
||||
// topic interface start
|
||||
export interface Topic {
|
||||
cleanupPolicies: string[];
|
||||
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 { observer } from 'mobx-react';
|
||||
import { SearchDataFunctionType, SearchResponse } from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import AppState from '../../AppState';
|
||||
import { searchData } from '../../axiosAPIs/miscAPI';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import MyData from '../../components/MyData/MyData.component';
|
||||
import { ERROR500, PAGE_SIZE } from '../../constants/constants';
|
||||
import useToastContext from '../../hooks/useToastContext';
|
||||
import { getAllServices } from '../../utils/ServiceUtils';
|
||||
|
||||
const MyDataPage = () => {
|
||||
const showToast = useToastContext();
|
||||
const [error, setError] = useState<string>('');
|
||||
const [countServices, setCountServices] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [searchResult, setSearchResult] = useState<SearchResponse>();
|
||||
|
||||
const fetchData = (value: SearchDataFunctionType) => {
|
||||
searchData(
|
||||
value.queryString,
|
||||
value.from,
|
||||
PAGE_SIZE,
|
||||
value.filters,
|
||||
value.sortField,
|
||||
value.sortOrder,
|
||||
value.searchIndex
|
||||
)
|
||||
.then((res: SearchResponse) => {
|
||||
setSearchResult(res);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
setError(err.response?.data?.responseMessage);
|
||||
showToast({
|
||||
variant: 'error',
|
||||
body: err.response?.data?.responseMessage ?? ERROR500,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getAllServices()
|
||||
.then((res) => setCountServices(res.length))
|
||||
.catch(() => setCountServices(0));
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div data-testid="my-data-page-conatiner">
|
||||
{isLoading ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<MyData
|
||||
countServices={countServices}
|
||||
error={error}
|
||||
fetchData={fetchData}
|
||||
searchResult={searchResult}
|
||||
userDetails={AppState.userDetails}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(MyDataPage);
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 { findByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import MyDataPageComponent from './MyDataPage.component';
|
||||
|
||||
jest.mock('../../components/LandingPage/MyData.component', () => {
|
||||
return jest.fn().mockReturnValue(<p>Mydata component</p>);
|
||||
});
|
||||
|
||||
describe('Test MyData page component', () => {
|
||||
it('Component should render', async () => {
|
||||
const { container } = render(<MyDataPageComponent />);
|
||||
|
||||
const myDataPageContainer = await findByTestId(
|
||||
container,
|
||||
'my-data-page-conatiner'
|
||||
);
|
||||
|
||||
expect(myDataPageContainer).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -16,15 +16,14 @@
|
||||
*/
|
||||
|
||||
import { AxiosError } from 'axios';
|
||||
import { Bucket, SearchResponse } from 'Models';
|
||||
import { Bucket, SearchDataFunctionType, 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,
|
||||
UrlParams,
|
||||
} from '../../components/Explore/explore.interface';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import { ERROR500 } from '../../constants/constants';
|
||||
@ -36,7 +35,7 @@ const ExplorePage: FunctionComponent = () => {
|
||||
const showToast = useToastContext();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string>('');
|
||||
const { searchQuery, tab } = useParams<Params>();
|
||||
const { searchQuery, tab } = useParams<UrlParams>();
|
||||
const [searchText, setSearchText] = useState<string>(searchQuery || '');
|
||||
const [tableCount, setTableCount] = useState<number>(0);
|
||||
const [topicCount, setTopicCount] = useState<number>(0);
|
||||
@ -151,7 +150,7 @@ const ExplorePage: FunctionComponent = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const fetchData = (value: FetchData[]) => {
|
||||
const fetchData = (value: SearchDataFunctionType[]) => {
|
||||
setIsLoading(true);
|
||||
const promiseValue = value.map((d) => {
|
||||
return searchData(
|
||||
|
@ -1,239 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
import {
|
||||
findAllByTestId,
|
||||
findByTestId,
|
||||
findByText,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import MyDataPage from './index';
|
||||
|
||||
const mockData = {
|
||||
took: 50,
|
||||
timed_out: false,
|
||||
_shards: {
|
||||
total: 1,
|
||||
successful: 1,
|
||||
skipped: 0,
|
||||
failed: 0,
|
||||
},
|
||||
hits: {
|
||||
total: {
|
||||
value: 12,
|
||||
relation: 'eq',
|
||||
},
|
||||
max_score: 5,
|
||||
hits: [
|
||||
{
|
||||
_index: 'table_search_indexcb2cac4c-735e-474e-a968-da8d8e0b218c',
|
||||
_type: '_doc',
|
||||
_id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
_score: 5,
|
||||
_source: {
|
||||
table_id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
database: 'shopify',
|
||||
service: 'bigquery',
|
||||
service_type: 'BigQuery',
|
||||
table_name: 'dim_address',
|
||||
suggest: [
|
||||
{
|
||||
input: ['bigquery.shopify.dim_address'],
|
||||
weight: 5,
|
||||
},
|
||||
{
|
||||
input: ['dim_address'],
|
||||
weight: 10,
|
||||
},
|
||||
],
|
||||
description: 'test description',
|
||||
table_type: null,
|
||||
last_updated_timestamp: 1628498201,
|
||||
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 shops table.',
|
||||
],
|
||||
monthly_stats: 0,
|
||||
weekly_stats: 0,
|
||||
daily_stats: 0,
|
||||
tags: ['User.Phone'],
|
||||
fqdn: 'bigquery.shopify.dim_address',
|
||||
tier: null,
|
||||
schema_description: null,
|
||||
owner: '',
|
||||
followers: [],
|
||||
table_entity: {
|
||||
id: '53761de6-6c41-431f-9c4e-62d39cf4aba9',
|
||||
name: 'dim_address',
|
||||
description: 'test table description',
|
||||
href: 'http://test',
|
||||
tableType: null,
|
||||
fullyQualifiedName: 'bigquery.shopify.dim_address',
|
||||
columns: [
|
||||
{
|
||||
name: 'address_id',
|
||||
columnDataType: 'NUMERIC',
|
||||
description: 'Unique identifier for the address.',
|
||||
fullyQualifiedName: 'bigquery.shopify.dim_address.address_id',
|
||||
tags: [
|
||||
{
|
||||
tagFQN: 'PersonalData.Personal',
|
||||
labelType: 'Derived',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
{
|
||||
tagFQN: 'PII.Sensitive',
|
||||
labelType: 'Derived',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
{
|
||||
tagFQN: 'User.Address',
|
||||
labelType: 'Automated',
|
||||
state: 'Suggested',
|
||||
href: null,
|
||||
},
|
||||
],
|
||||
columnConstraint: 'PRIMARY_KEY',
|
||||
ordinalPosition: 1,
|
||||
},
|
||||
],
|
||||
tableConstraints: null,
|
||||
usageSummary: {
|
||||
dailyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
weeklyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
monthlyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
date: '2021-08-09',
|
||||
},
|
||||
owner: null,
|
||||
followers: [],
|
||||
database: {
|
||||
id: '2d04ddc1-4c9b-43a3-85fb-3de204d67f32',
|
||||
type: 'database',
|
||||
name: 'shopify',
|
||||
description:
|
||||
'This database contains tables related to shopify order and related dimensions',
|
||||
href: 'http://test/test',
|
||||
},
|
||||
tags: [],
|
||||
joins: null,
|
||||
sampleData: null,
|
||||
},
|
||||
},
|
||||
highlight: {
|
||||
description: ['data test'],
|
||||
table_name: ['<b>dim_address</b>'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
aggregations: {
|
||||
'sterms#Tier': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [],
|
||||
},
|
||||
'sterms#Tags': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: 'PII.Sensitive',
|
||||
doc_count: 7,
|
||||
},
|
||||
],
|
||||
},
|
||||
'sterms#Service Type': {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: 'BigQuery',
|
||||
doc_count: 12,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('../../axiosAPIs/miscAPI', () => ({
|
||||
searchData: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ data: mockData })),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/searched-data/SearchedData', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }: { children: React.ReactNode }) => (
|
||||
<div data-testid="search-data">
|
||||
<div data-testid="wrapped-content">{children}</div>
|
||||
</div>
|
||||
));
|
||||
});
|
||||
|
||||
jest.mock('../../components/recently-viewed/RecentlyViewed', () => {
|
||||
return jest.fn().mockReturnValue(<p>RecentlyViewed</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../components/my-data/MyDataHeader', () => {
|
||||
return jest.fn().mockReturnValue(<p>MyDataHeader</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../utils/ServiceUtils', () => ({
|
||||
getAllServices: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(['test', 'test2', 'test3'])),
|
||||
getEntityCountByService: jest
|
||||
.fn()
|
||||
.mockReturnValue({ tableCount: 4, topicCount: 5, dashboardCount: 6 }),
|
||||
getTotalEntityCountByService: jest.fn().mockReturnValue(2),
|
||||
}));
|
||||
|
||||
describe('Test MyData page', () => {
|
||||
it('Check if there is an element in the page', async () => {
|
||||
const { container } = render(<MyDataPage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const pageContainer = await findByTestId(container, 'fluid-container');
|
||||
const searchData = await findByTestId(container, 'search-data');
|
||||
const wrappedContent = await findByTestId(container, 'wrapped-content');
|
||||
const tabs = await findAllByTestId(container, 'tab');
|
||||
const myDataHeader = await findByText(container, /MyDataHeader/i);
|
||||
|
||||
expect(pageContainer).toBeInTheDocument();
|
||||
expect(searchData).toBeInTheDocument();
|
||||
expect(wrappedContent).toBeInTheDocument();
|
||||
expect(myDataHeader).toBeInTheDocument();
|
||||
expect(tabs.length).toBe(3);
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FirstTimeUserModal } from '../../components/Modals/FirstTimeUserModal/FirstTimeUserModal';
|
||||
import { useTour } from '../../hooks/useTour';
|
||||
import MyDataPage from '../my-data';
|
||||
// import MyDataPage from '../../components/LandingPage/MyData.component';
|
||||
|
||||
const TourPage = () => {
|
||||
const [showFirstTimeUserModal, setShowFirstTimeUserModal] = useState(true);
|
||||
@ -17,7 +17,7 @@ const TourPage = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<MyDataPage />
|
||||
{/* <MyDataPage /> */}
|
||||
{showFirstTimeUserModal && (
|
||||
<FirstTimeUserModal
|
||||
onCancel={() => setShowFirstTimeUserModal(true)}
|
||||
|
@ -25,7 +25,7 @@ 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/ExplorePage.component';
|
||||
import MyDataPage from '../pages/my-data';
|
||||
import MyDataPage from '../pages/MyDataPage/MyDataPage.component';
|
||||
import MyPipelinePage from '../pages/Pipeline-details';
|
||||
import ReportsPage from '../pages/reports';
|
||||
import Scorecard from '../pages/scorecard';
|
||||
|
Loading…
x
Reference in New Issue
Block a user