Adding dashboard tab on explore page (#398)

* Adding dashboard tab on explore page

* minor fix
This commit is contained in:
Sachin Chaurasiya 2021-09-06 11:23:27 +05:30 committed by GitHub
parent 072c2034ad
commit 1fa033798a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 516 additions and 49 deletions

View File

@ -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 { AxiosResponse } from 'axios';
import { Dashboard } from '../generated/entity/data/dashboard';
import { getURLWithQueryFields } from '../utils/APIUtils';
import APIClient from './index';
export const getDashboards: Function = (
serviceName: string,
paging: string,
arrQueryFields: string
): Promise<AxiosResponse> => {
const url = `${getURLWithQueryFields(
`/dashboards`,
arrQueryFields
)}&service=${serviceName}${paging ? paging : ''}`;
return APIClient.get(url);
};
export const getDashboardByFqn: Function = (
fqn: string,
arrQueryFields: string
): Promise<AxiosResponse> => {
const url = getURLWithQueryFields(`/dashboards/name/${fqn}`, arrQueryFields);
return APIClient.get(url);
};
export const addFollower: Function = (
dashboardID: string,
userId: string
): Promise<AxiosResponse> => {
const configOptions = {
headers: { 'Content-type': 'application/json' },
};
return APIClient.put(
`/dashboards/${dashboardID}/followers`,
userId,
configOptions
);
};
export const removeFollower: Function = (
dashboardID: string,
userId: string
): Promise<AxiosResponse> => {
const configOptions = {
headers: { 'Content-type': 'application/json' },
};
return APIClient.delete(
`/dashboards/${dashboardID}/followers/${userId}`,
configOptions
);
};
export const patchDashboardDetails: Function = (
id: string,
data: Dashboard
): Promise<AxiosResponse> => {
const configOptions = {
headers: { 'Content-type': 'application/json-patch+json' },
};
return APIClient.patch(`/dashboards/${id}`, data, configOptions);
};

View File

@ -44,7 +44,9 @@ const ErrorPlaceHolderES = ({ type }: Props) => {
</div>
<div className="tw-flex tw-flex-col tw-items-center tw-mt-10 tw-text-base tw-font-normal">
<p className="tw-text-lg tw-font-bold tw-mb-1 tw-text-primary">
{`Hi, ${AppState.userDetails.displayName}!`}
{`Hi, ${
AppState.userDetails.displayName || AppState.users[0].displayName
}!`}
</p>
{type === 'noData' && noRecordForES()}
{type === 'error' && (

View File

@ -33,7 +33,6 @@ const FacetFilter: FunctionComponent<FacetProp> = ({
}: FacetProp) => {
const [showAllTags, setShowAllTags] = useState<boolean>(false);
const [showAllServices, setShowAllServices] = useState<boolean>(false);
const [showAllClusters, setShowAllClusters] = useState<boolean>(false);
const [showAllTier, setShowAllTier] = useState<boolean>(false);
const sortAggregations = () => {
return aggregations.sort((a, b) =>
@ -74,8 +73,6 @@ const FacetFilter: FunctionComponent<FacetProp> = ({
return getLinkText(bucketLength, showAllServices, setShowAllServices);
case 'Tags':
return getLinkText(bucketLength, showAllTags, setShowAllTags);
case 'Service Type':
return getLinkText(bucketLength, showAllClusters, setShowAllClusters);
case 'Tier':
return getLinkText(bucketLength, showAllTier, setShowAllTier);
default:
@ -89,8 +86,6 @@ const FacetFilter: FunctionComponent<FacetProp> = ({
return getBuckets(buckets, showAllServices);
case 'Tags':
return getBuckets(buckets, showAllTags);
case 'Service Type':
return getBuckets(buckets, showAllClusters);
case 'Tier':
return getBuckets(buckets, showAllTier);
default:
@ -176,7 +171,7 @@ FacetFilter.propTypes = {
onSelectHandler: PropTypes.func.isRequired,
filters: PropTypes.shape({
tags: PropTypes.array.isRequired,
'service type': PropTypes.array.isRequired,
service: PropTypes.array.isRequired,
tier: PropTypes.array.isRequired,
}).isRequired,
};

View File

@ -121,7 +121,7 @@ const TagsContainer: FunctionComponent<TagsContainerProps> = ({
};
const getTagsContainer = (tag: ColumnTags, index: number) => {
return (
return tag.tagFQN ? (
<Tags
className="tw-bg-gray-200"
editable={editable}
@ -132,7 +132,7 @@ const TagsContainer: FunctionComponent<TagsContainerProps> = ({
}}
tag={`#${tag.tagFQN}`}
/>
);
) : null;
};
const getTagsElement = (tag: ColumnTags, index: number) => {

View File

@ -35,6 +35,7 @@ export const ERROR404 = 'No data found';
export const ERROR500 = 'Something went wrong';
const PLACEHOLDER_ROUTE_DATASET_FQN = ':datasetFQN';
const PLACEHOLDER_ROUTE_TOPIC_FQN = ':topicFQN';
const PLACEHOLDER_ROUTE_DASHBOARD_FQN = ':dashboardFQN';
const PLACEHOLDER_ROUTE_DATABASE_FQN = ':databaseFQN';
const PLACEHOLDER_ROUTE_SERVICE_FQN = ':serviceFQN';
const PLACEHOLDER_ROUTE_SERVICE_TYPE = ':serviceType';
@ -63,7 +64,7 @@ export const tableSortingFields = [
export const topicSortingFields = [
{
name: 'Last Updated Timestamp',
name: 'Last Updated',
value: 'last_updated_timestamp',
},
];
@ -75,7 +76,7 @@ export const sortingOrder = [
export const facetFilterPlaceholder = [
{
name: 'Service Type',
name: 'Service',
value: 'Service',
},
{
@ -113,6 +114,7 @@ export const ROUTES = {
SIGNIN: '/signin',
DATASET_DETAILS: `/dataset/${PLACEHOLDER_ROUTE_DATASET_FQN}`,
TOPIC_DETAILS: `/topic/${PLACEHOLDER_ROUTE_TOPIC_FQN}`,
DASHBOARD_DETAILS: `/dashboard/${PLACEHOLDER_ROUTE_DASHBOARD_FQN}`,
DATABASE_DETAILS: `/database/${PLACEHOLDER_ROUTE_DATABASE_FQN}`,
ONBOARDING: '/onboarding',
};
@ -163,6 +165,12 @@ export const getTopicDetailsPath = (topicFQN: string) => {
return path;
};
export const getDashboardDetailsPath = (dashboardFQN: string) => {
let path = ROUTES.DASHBOARD_DETAILS;
path = path.replace(PLACEHOLDER_ROUTE_DASHBOARD_FQN, dashboardFQN);
return path;
};
export const LIST_TYPES = ['numbered-list', 'bulleted-list'];

View File

@ -24,4 +24,5 @@ export enum FilterType {
export enum SearchIndex {
TABLE = 'table_search_index',
TOPIC = 'topic_search_index',
DASHBOARD = 'dashboard_search_index',
}

View File

@ -0,0 +1,322 @@
import { AxiosResponse } from 'axios';
import { compare } from 'fast-json-patch';
import { isNil } from 'lodash';
import { ColumnTags, TableDetail } from 'Models';
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import {
addFollower,
getDashboardByFqn,
patchDashboardDetails,
removeFollower,
} from '../../axiosAPIs/dashboardAPI';
import { getServiceById } from '../../axiosAPIs/serviceAPI';
import Description from '../../components/common/description/Description';
import EntityPageInfo from '../../components/common/entityPageInfo/EntityPageInfo';
import TabsPane from '../../components/common/TabsPane/TabsPane';
import { TitleBreadcrumbProps } from '../../components/common/title-breadcrumb/title-breadcrumb.interface';
import PageContainer from '../../components/containers/PageContainer';
import Loader from '../../components/Loader/Loader';
import ManageTab from '../../components/my-data-details/ManageTab';
import { getServiceDetailsPath } from '../../constants/constants';
import { Dashboard, TagLabel } from '../../generated/entity/data/dashboard';
import { getCurrentUserId, getUserTeams } from '../../utils/CommonUtils';
import { serviceTypeLogo } from '../../utils/ServiceUtils';
import {
getOwnerFromId,
getTagsWithoutTier,
getTierFromTableTags,
getUsagePercentile,
} from '../../utils/TableUtils';
import { getTagCategories, getTaglist } from '../../utils/TagsUtils';
const MyDashBoardPage = () => {
const USERId = getCurrentUserId();
const [tagList, setTagList] = useState<Array<string>>([]);
const { dashboardFQN } = useParams() as Record<string, string>;
const [dashboardDetails, setDashboardDetails] = useState<Dashboard>(
{} as Dashboard
);
const [dashboardId, setDashboardId] = useState<string>('');
const [isLoading, setLoading] = useState<boolean>(false);
const [description, setDescription] = useState<string>('');
const [followers, setFollowers] = useState<number>(0);
const [isFollowing, setIsFollowing] = useState(false);
const [owner, setOwner] = useState<TableDetail['owner']>();
const [tier, setTier] = useState<string>();
const [tags, setTags] = useState<Array<ColumnTags>>([]);
const [activeTab, setActiveTab] = useState<number>(1);
const [isEdit, setIsEdit] = useState<boolean>(false);
const [usage, setUsage] = useState('');
const [weeklyUsageCount, setWeeklyUsageCount] = useState('');
const [slashedDashboardName, setSlashedDashboardName] = useState<
TitleBreadcrumbProps['titleLinks']
>([]);
const hasEditAccess = () => {
if (owner?.type === 'user') {
return owner.id === getCurrentUserId();
} else {
return getUserTeams().some((team) => team.id === owner?.id);
}
};
const tabs = [
{
name: 'Details',
icon: {
alt: 'schema',
name: 'icon-schema',
title: 'Details',
},
isProtected: false,
position: 1,
},
{
name: 'Manage',
icon: {
alt: 'manage',
name: 'icon-manage',
title: 'Manage',
},
isProtected: true,
protectedState: !owner || hasEditAccess(),
position: 2,
},
];
const extraInfo = [
{ key: 'Owner', value: owner?.name || '' },
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' },
{ key: 'Usage', value: usage },
{ key: 'Queries', value: `${weeklyUsageCount} past week` },
];
const fetchTags = () => {
getTagCategories().then((res) => {
if (res.data) {
setTagList(getTaglist(res.data));
}
});
};
const fetchDashboardDetail = (dashboardFQN: string) => {
setLoading(true);
getDashboardByFqn(dashboardFQN, [
'owner',
'service',
'followers',
'tags',
'usageSummary',
]).then((res: AxiosResponse) => {
const {
id,
description,
followers,
service,
tags,
owner,
usageSummary,
displayName,
} = res.data;
setDashboardDetails(res.data);
setDashboardId(id);
setDescription(description ?? '');
setFollowers(followers?.length);
setOwner(getOwnerFromId(owner?.id));
setTier(getTierFromTableTags(tags));
setTags(getTagsWithoutTier(tags));
setIsFollowing(followers.some(({ id }: { id: string }) => id === USERId));
if (!isNil(usageSummary?.weeklyStats.percentileRank)) {
const percentile = getUsagePercentile(
usageSummary.weeklyStats.percentileRank
);
setUsage(percentile);
} else {
setUsage('--');
}
setWeeklyUsageCount(
usageSummary?.weeklyStats.count.toLocaleString() || '--'
);
getServiceById('dashboardServices', service?.id).then(
(serviceRes: AxiosResponse) => {
setSlashedDashboardName([
{
name: serviceRes.data.name,
url: serviceRes.data.name
? getServiceDetailsPath(
serviceRes.data.name,
serviceRes.data.serviceType
)
: '',
imgSrc: serviceRes.data.serviceType
? serviceTypeLogo(serviceRes.data.serviceType)
: undefined,
},
{
name: displayName,
url: '',
activeTitle: true,
},
]);
}
);
setLoading(false);
});
};
const followDashboard = (): void => {
if (isFollowing) {
removeFollower(dashboardId, USERId).then(() => {
setFollowers((preValu) => preValu - 1);
setIsFollowing(false);
});
} else {
addFollower(dashboardId, USERId).then(() => {
setFollowers((preValu) => preValu + 1);
setIsFollowing(true);
});
}
};
const onDescriptionUpdate = (updatedHTML: string) => {
const updatedDashboard = { ...dashboardDetails, description: updatedHTML };
const jsonPatch = compare(dashboardDetails, updatedDashboard);
patchDashboardDetails(dashboardId, jsonPatch).then((res: AxiosResponse) => {
setDescription(res.data.description);
});
setIsEdit(false);
};
const onDescriptionEdit = (): void => {
setIsEdit(true);
};
const onCancel = () => {
setIsEdit(false);
};
const onSettingsUpdate = (
newOwner?: TableDetail['owner'],
newTier?: TableDetail['tier']
): Promise<void> => {
return new Promise<void>((resolve, reject) => {
if (newOwner || newTier) {
const tierTag: TableDetail['tags'] = newTier
? [
...getTagsWithoutTier(dashboardDetails.tags as ColumnTags[]),
{ tagFQN: newTier, labelType: 'Manual', state: 'Confirmed' },
]
: (dashboardDetails.tags as ColumnTags[]);
const updatedDashboard = {
...dashboardDetails,
owner: newOwner
? { ...dashboardDetails.owner, ...newOwner }
: dashboardDetails.owner,
tags: tierTag,
};
const jsonPatch = compare(dashboardDetails, updatedDashboard);
patchDashboardDetails(dashboardId, jsonPatch)
.then((res: AxiosResponse) => {
setDashboardDetails(res.data);
setOwner(getOwnerFromId(res.data.owner?.id));
setTier(getTierFromTableTags(res.data.tags));
resolve();
})
.catch(() => reject());
} else {
reject();
}
});
};
const onTagUpdate = (selectedTags?: Array<string>) => {
if (selectedTags) {
const prevTags = dashboardDetails?.tags?.filter((tag) =>
selectedTags.includes(tag?.tagFQN as string)
);
const newTags: Array<ColumnTags> = selectedTags
.filter((tag) => {
return !prevTags?.map((prevTag) => prevTag.tagFQN).includes(tag);
})
.map((tag) => ({
labelType: 'Manual',
state: 'Confirmed',
tagFQN: tag,
}));
const updatedTags = [...(prevTags as TagLabel[]), ...newTags];
const updatedDashboard = { ...dashboardDetails, tags: updatedTags };
const jsonPatch = compare(dashboardDetails, updatedDashboard);
patchDashboardDetails(dashboardId, jsonPatch).then(
(res: AxiosResponse) => {
setTier(getTierFromTableTags(res.data.tags));
setTags(getTagsWithoutTier(res.data.tags));
}
);
}
};
useEffect(() => {
fetchDashboardDetail(dashboardFQN);
}, [dashboardFQN]);
useEffect(() => {
fetchTags();
}, []);
return (
<PageContainer>
{isLoading ? (
<Loader />
) : (
<div className="tw-px-4 w-full">
<EntityPageInfo
isTagEditable
extraInfo={extraInfo}
followers={followers}
followHandler={followDashboard}
isFollowing={isFollowing}
tagList={tagList}
tags={tags}
tagsHandler={onTagUpdate}
tier={tier || ''}
titleLinks={slashedDashboardName}
/>
<div className="tw-block tw-mt-1">
<TabsPane
activeTab={activeTab}
setActiveTab={setActiveTab}
tabs={tabs}
/>
<div className="tw-bg-white tw--mx-4 tw-p-4">
{activeTab === 1 && (
<>
<div className="tw-grid tw-grid-cols-4 tw-gap-4 w-full">
<div className="tw-col-span-full">
<Description
description={description}
hasEditAccess={hasEditAccess()}
isEdit={isEdit}
owner={owner}
onCancel={onCancel}
onDescriptionEdit={onDescriptionEdit}
onDescriptionUpdate={onDescriptionUpdate}
/>
</div>
</div>
</>
)}
{activeTab === 2 && (
<ManageTab
currentTier={tier}
currentUser={owner?.id}
hasEditAccess={hasEditAccess()}
onSave={onSettingsUpdate}
/>
)}
</div>
</div>
</div>
)}
</PageContainer>
);
};
export default MyDashBoardPage;

View File

@ -17,7 +17,12 @@
import { lowerCase } from 'lodash';
import { AggregationType, Bucket } from 'Models';
import { tiers } from '../../constants/constants';
import {
tableSortingFields,
tiers,
topicSortingFields,
} from '../../constants/constants';
import { SearchIndex } from '../../enums/search.enum';
export const getBucketList = (buckets: Array<Bucket>) => {
let bucketList: Array<Bucket> = [...tiers];
@ -53,3 +58,27 @@ export const getAggrWithDefaultValue = (
? aggregations
: aggregations.filter((item) => allowedAgg.includes(lowerCase(item.title)));
};
export const tabsInfo = [
{
label: 'Tables',
index: SearchIndex.TABLE,
sortingFields: tableSortingFields,
sortField: tableSortingFields[0].value,
tab: 1,
},
{
label: 'Topics',
index: SearchIndex.TOPIC,
sortingFields: topicSortingFields,
sortField: topicSortingFields[0].value,
tab: 2,
},
{
label: 'Dashboards',
index: SearchIndex.DASHBOARD,
sortingFields: topicSortingFields,
sortField: topicSortingFields[0].value,
tab: 3,
},
];

View File

@ -37,7 +37,6 @@ import {
ERROR500,
PAGE_SIZE,
tableSortingFields,
topicSortingFields,
} from '../../constants/constants';
import { SearchIndex } from '../../enums/search.enum';
import { usePrevious } from '../../hooks/usePrevious';
@ -47,10 +46,10 @@ import { formatDataResponse } from '../../utils/APIUtils';
import { getCountBadge } from '../../utils/CommonUtils';
import { getFilterString } from '../../utils/FilterUtils';
import { dropdownIcon as DropDownIcon } from '../../utils/svgconstant';
import { getAggrWithDefaultValue } from './explore.constants';
import { getAggrWithDefaultValue, tabsInfo } from './explore.constants';
import { Params } from './explore.interface';
const visibleFilters = ['tags', 'service type', 'tier'];
const visibleFilters = ['tags', 'service', 'tier'];
const getQueryParam = (urlSearchQuery = ''): FilterObject => {
const arrSearchQuery = urlSearchQuery
@ -74,7 +73,7 @@ const ExplorePage: React.FC = (): React.ReactElement => {
const location = useLocation();
const filterObject: FilterObject = {
...{ tags: [], 'service type': [], tier: [] },
...{ tags: [], service: [], tier: [] },
...getQueryParam(location.search),
};
const showToast = useToastContext();
@ -95,6 +94,7 @@ const ExplorePage: React.FC = (): React.ReactElement => {
const [currentTab, setCurrentTab] = useState<number>(1);
const [tableCount, setTableCount] = useState<number>(0);
const [topicCount, setTopicCount] = useState<number>(0);
const [dashboardCount, setDashboardCount] = useState<number>(0);
const [fieldList, setFieldList] =
useState<Array<{ name: string; value: string }>>(tableSortingFields);
const isMounting = useRef(true);
@ -198,10 +198,20 @@ const ExplorePage: React.FC = (): React.ReactElement => {
emptyValue,
SearchIndex.TOPIC
);
Promise.all([tableCount, topicCount])
.then(([table, topic]: Array<SearchResponse>) => {
const dashboardCount = searchData(
searchText,
0,
0,
getFilterString(filters),
emptyValue,
emptyValue,
SearchIndex.DASHBOARD
);
Promise.all([tableCount, topicCount, dashboardCount])
.then(([table, topic, dashboard]: Array<SearchResponse>) => {
setTableCount(table.data.hits.total.value);
setTopicCount(topic.data.hits.total.value);
setDashboardCount(dashboard.data.hits.total.value);
})
.catch((err: AxiosError) => {
setError(ERROR404);
@ -228,7 +238,7 @@ const ExplorePage: React.FC = (): React.ReactElement => {
searchText,
currentPage,
0,
getFilterString(filters, ['service type']),
getFilterString(filters, ['service']),
sortField,
sortOrder,
searchIndex
@ -270,7 +280,7 @@ const ExplorePage: React.FC = (): React.ReactElement => {
} else {
const aggServiceType = getAggregationList(
resAggServiceType.data.aggregations,
'service type'
'service'
);
const aggTier = getAggregationList(
resAggTier.data.aggregations,
@ -380,37 +390,42 @@ const ExplorePage: React.FC = (): React.ReactElement => {
});
};
const getTabCount = (index: string) => {
switch (index) {
case SearchIndex.TABLE:
return getCountBadge(tableCount);
case SearchIndex.TOPIC:
return getCountBadge(topicCount);
case SearchIndex.DASHBOARD:
return getCountBadge(dashboardCount);
default:
return getCountBadge();
}
};
const getTabs = () => {
return (
<div className="tw-mb-3 tw--mt-4">
<nav className="tw-flex tw-flex-row tw-gh-tabs-container tw-px-4 tw-justify-between">
<div>
<button
className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(1)}`}
onClick={() => {
setCurrentTab(1);
setSearchIndex(SearchIndex.TABLE);
setFieldList(tableSortingFields);
setSortField(tableSortingFields[0].value);
setCurrentPage(1);
resetFilters();
}}>
Tables
{getCountBadge(tableCount)}
</button>
<button
className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(2)}`}
onClick={() => {
setCurrentTab(2);
setSearchIndex(SearchIndex.TOPIC);
setFieldList(topicSortingFields);
setSortField(topicSortingFields[0].value);
setCurrentPage(1);
resetFilters();
}}>
Topics
{getCountBadge(topicCount)}
</button>
{tabsInfo.map((tab, index) => (
<button
className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(
tab.tab
)}`}
key={index}
onClick={() => {
setCurrentTab(tab.tab);
setSearchIndex(tab.index);
setFieldList(tab.sortingFields);
setSortField(tab.sortField);
setCurrentPage(1);
resetFilters();
}}>
{tab.label}
{getTabCount(tab.index)}
</button>
))}
</div>
{getSortingElements()}
</nav>

View File

@ -139,6 +139,7 @@ const MyDataDetailsPage = () => {
const extraInfo = [
{ key: 'Owner', value: owner?.name || '' },
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' },
{ key: 'Usage', value: usage },
{ key: 'Queries', value: `${weeklyUsageCount} past week` },
];

View File

@ -21,6 +21,7 @@ import { Redirect, Route, Switch } from 'react-router-dom';
import AppState from '../AppState';
import Onboarding from '../components/onboarding/Onboarding'; // Remove this route once Onboarding is added to my-data
import { ROUTES } from '../constants/constants';
import MyDashBoardPage from '../pages/dashboard-details';
import DatabaseDetails from '../pages/database-details/index';
import ExplorePage from '../pages/explore';
import MyDataPage from '../pages/my-data';
@ -64,6 +65,7 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
<Route component={DatabaseDetails} path={ROUTES.DATABASE_DETAILS} />
<Route component={MyDataDetailsPage} path={ROUTES.DATASET_DETAILS} />
<Route component={MyTopicDetailPage} path={ROUTES.TOPIC_DETAILS} />
<Route component={MyDashBoardPage} path={ROUTES.DASHBOARD_DETAILS} />
<Route component={Onboarding} path={ROUTES.ONBOARDING} />
<Redirect to={ROUTES.NOT_FOUND} />
</Switch>

View File

@ -6,8 +6,12 @@ import { getRelativeTime } from './TimeUtils';
export const formatDataResponse = (hits) => {
const formattedData = hits.map((hit) => {
const newData = {};
newData.id = hit._source.table_id || hit._source.topic_id;
newData.name = hit._source.table_name || hit._source.topic_name;
newData.id =
hit._source.table_id || hit._source.topic_id || hit._source.dashboard_id;
newData.name =
hit._source.table_name ||
hit._source.topic_name ||
hit._source.dashboard_name;
newData.description = hit._source.description;
newData.fullyQualifiedName = hit._source.fqdn;
newData.tableType = hit._source.table_type;

View File

@ -7,7 +7,8 @@ export const getFilterString = (filters, excludeFilters = []) => {
const modifiedFilter = [];
const filter = filters[key];
filter.forEach((value) => {
modifiedFilter.push(`${key.split(' ').join('_')}:${value}`);
const modifiedKey = key === 'service' ? 'service type' : key;
modifiedFilter.push(`${modifiedKey.split(' ').join('_')}:${value}`);
});
modifiedFilters[key] = modifiedFilter;
}

View File

@ -3,6 +3,7 @@ import React from 'react';
import AppState from '../AppState';
import PopOver from '../components/common/popover/PopOver';
import {
getDashboardDetailsPath,
getDatasetDetailsPath,
getTopicDetailsPath,
} from '../constants/constants';
@ -156,6 +157,9 @@ export const getEntityLink = (
case SearchIndex.TOPIC:
return getTopicDetailsPath(fullyQualifiedName);
case SearchIndex.DASHBOARD:
return getDashboardDetailsPath(fullyQualifiedName);
case SearchIndex.TABLE:
default:
return getDatasetDetailsPath(fullyQualifiedName);