mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-27 18:36:08 +00:00
Feat #8639 UI : Show charts latest value in data insight overview card and rename datasets to data assets (#8641)
* Fix #8639 UI : Show charts latest value in data insight overview card and rename datasets to data assets * Add data summary for entities chart * Add Percentage symbol for Percentage chart * Add web charts summary data * Address review comments * Change active user index
This commit is contained in:
parent
b2e2d9cff3
commit
2e158237ea
@ -79,6 +79,7 @@ const DailyActiveUsersChart: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-active-user-card"
|
||||
id={DataInsightChartType.DailyActiveUsers}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
@label-color: #37352f90;
|
||||
@summary-card-bg-hover: #f0f1f3;
|
||||
|
||||
.data-insight-card {
|
||||
.ant-card-head {
|
||||
@ -22,3 +23,12 @@
|
||||
.ant-typography.data-insight-label-text {
|
||||
color: @label-color;
|
||||
}
|
||||
|
||||
.summary-card-item {
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
&:hover {
|
||||
background-color: @summary-card-bg-hover;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { act } from 'react-test-renderer';
|
||||
import { DataInsightChartType } from '../../generated/dataInsight/dataInsightChartResult';
|
||||
import DataInsightSummary from './DataInsightSummary';
|
||||
|
||||
jest.mock('react-i18next', () => ({
|
||||
@ -27,6 +28,8 @@ const mockFilter = {
|
||||
endTs: 1668000248671,
|
||||
};
|
||||
|
||||
const mockScrollFunction = jest.fn();
|
||||
|
||||
jest.mock('../../axiosAPIs/DataInsightAPI', () => ({
|
||||
getAggregateChartData: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
}));
|
||||
@ -34,14 +37,21 @@ jest.mock('../../axiosAPIs/DataInsightAPI', () => ({
|
||||
describe('Test DataInsightSummary Component', () => {
|
||||
it('Should render the overview data', async () => {
|
||||
await act(async () => {
|
||||
render(<DataInsightSummary chartFilter={mockFilter} />);
|
||||
render(
|
||||
<DataInsightSummary
|
||||
chartFilter={mockFilter}
|
||||
onScrollToChart={mockScrollFunction}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const summaryCard = screen.getByTestId('summary-card');
|
||||
|
||||
const allEntityCount = screen.getByTestId('summary-item-latest');
|
||||
const totalEntitiesByType = screen.getByTestId(
|
||||
`summary-item-${DataInsightChartType.TotalEntitiesByType}`
|
||||
);
|
||||
|
||||
expect(summaryCard).toBeInTheDocument();
|
||||
expect(allEntityCount).toBeInTheDocument();
|
||||
expect(totalEntitiesByType).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -11,51 +11,138 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Col, Row, Typography } from 'antd';
|
||||
import { Card, Col, Row, Space, Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getAggregateChartData } from '../../axiosAPIs/DataInsightAPI';
|
||||
import { getUserPath } from '../../constants/constants';
|
||||
import {
|
||||
ENTITIES_CHARTS,
|
||||
WEB_CHARTS,
|
||||
} from '../../constants/DataInsight.constants';
|
||||
import { DataReportIndex } from '../../generated/dataInsight/dataInsightChart';
|
||||
import {
|
||||
DataInsightChartResult,
|
||||
DataInsightChartType,
|
||||
} from '../../generated/dataInsight/dataInsightChartResult';
|
||||
import { MostActiveUsers } from '../../generated/dataInsight/type/mostActiveUsers';
|
||||
import { ChartFilter } from '../../interface/data-insight.interface';
|
||||
import { getGraphDataByEntityType } from '../../utils/DataInsightUtils';
|
||||
import {
|
||||
getEntitiesChartSummary,
|
||||
getWebChartSummary,
|
||||
} from '../../utils/DataInsightUtils';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import UserPopOverCard from '../common/PopOverCard/UserPopOverCard';
|
||||
import ProfilePicture from '../common/ProfilePicture/ProfilePicture';
|
||||
import './DataInsightDetail.less';
|
||||
|
||||
interface Props {
|
||||
chartFilter: ChartFilter;
|
||||
onScrollToChart: (chartType: DataInsightChartType) => void;
|
||||
}
|
||||
|
||||
const DataInsightSummary: FC<Props> = ({ chartFilter }) => {
|
||||
const [totalEntitiesByType, setTotalEntitiesByType] =
|
||||
useState<DataInsightChartResult>();
|
||||
|
||||
const DataInsightSummary: FC<Props> = ({ chartFilter, onScrollToChart }) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [entitiesCharts, setEntitiesChart] = useState<
|
||||
(DataInsightChartResult | undefined)[]
|
||||
>([]);
|
||||
const [webCharts, setWebCharts] = useState<
|
||||
(DataInsightChartResult | undefined)[]
|
||||
>([]);
|
||||
|
||||
const { total, latestData = {} } = useMemo(() => {
|
||||
return getGraphDataByEntityType(
|
||||
totalEntitiesByType?.data ?? [],
|
||||
DataInsightChartType.TotalEntitiesByType
|
||||
const [mostActiveUser, setMostActiveUser] = useState<MostActiveUsers>();
|
||||
|
||||
const entitiesSummaryList = useMemo(
|
||||
() => getEntitiesChartSummary(entitiesCharts),
|
||||
[entitiesCharts]
|
||||
);
|
||||
|
||||
const webSummaryList = useMemo(
|
||||
() => getWebChartSummary(webCharts),
|
||||
[webCharts]
|
||||
);
|
||||
}, [totalEntitiesByType]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const fetchTotalEntitiesByType = async () => {
|
||||
const fetchEntitiesChartData = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const promises = ENTITIES_CHARTS.map((chartName) => {
|
||||
const params = {
|
||||
...chartFilter,
|
||||
dataInsightChartName: chartName,
|
||||
dataReportIndex: DataReportIndex.EntityReportDataIndex,
|
||||
};
|
||||
|
||||
return getAggregateChartData(params);
|
||||
});
|
||||
|
||||
const responses = await Promise.allSettled(promises);
|
||||
|
||||
const chartDataList = responses
|
||||
.map((response) => {
|
||||
if (response.status === 'fulfilled') {
|
||||
return response.value;
|
||||
}
|
||||
|
||||
return;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
setEntitiesChart(chartDataList);
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchMostActiveUser = async () => {
|
||||
try {
|
||||
const params = {
|
||||
...chartFilter,
|
||||
dataInsightChartName: DataInsightChartType.TotalEntitiesByType,
|
||||
dataReportIndex: DataReportIndex.EntityReportDataIndex,
|
||||
dataInsightChartName: DataInsightChartType.MostActiveUsers,
|
||||
dataReportIndex: DataReportIndex.WebAnalyticUserActivityReportDataIndex,
|
||||
};
|
||||
const response = await getAggregateChartData(params);
|
||||
if (response.data && response.data.length) {
|
||||
setMostActiveUser(response.data[0]);
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
setTotalEntitiesByType(response);
|
||||
const fetchWebChartData = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const promises = WEB_CHARTS.map((chart) => {
|
||||
const params = {
|
||||
...chartFilter,
|
||||
dataInsightChartName: chart.chart,
|
||||
dataReportIndex: chart.index,
|
||||
};
|
||||
|
||||
return getAggregateChartData(params);
|
||||
});
|
||||
|
||||
const responses = await Promise.allSettled(promises);
|
||||
|
||||
const chartDataList = responses
|
||||
.map((response) => {
|
||||
if (response.status === 'fulfilled') {
|
||||
return response.value;
|
||||
}
|
||||
|
||||
return;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
setWebCharts(chartDataList);
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
@ -64,7 +151,9 @@ const DataInsightSummary: FC<Props> = ({ chartFilter }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTotalEntitiesByType();
|
||||
fetchEntitiesChartData();
|
||||
fetchMostActiveUser();
|
||||
fetchWebChartData();
|
||||
}, [chartFilter]);
|
||||
|
||||
return (
|
||||
@ -78,27 +167,65 @@ const DataInsightSummary: FC<Props> = ({ chartFilter }) => {
|
||||
</Typography.Title>
|
||||
}>
|
||||
<Row data-testid="summary-card-content" gutter={[16, 16]}>
|
||||
<Col data-testid="summary-item-latest" span={4}>
|
||||
{/* summary of entity charts */}
|
||||
{entitiesSummaryList.map((summary) => (
|
||||
<Col
|
||||
className="summary-card-item"
|
||||
data-testid={`summary-item-${summary.id}`}
|
||||
key={summary.id}
|
||||
span={6}
|
||||
onClick={() => onScrollToChart(summary.id)}>
|
||||
<Typography.Text className="data-insight-label-text">
|
||||
Latest
|
||||
{summary.label}
|
||||
</Typography.Text>
|
||||
<Typography className="font-semibold text-2xl">{total}</Typography>
|
||||
</Col>
|
||||
{Object.entries(latestData).map((summary) => {
|
||||
const label = summary[0];
|
||||
const value = summary[1] as number;
|
||||
|
||||
return label !== 'timestamp' ? (
|
||||
<Col data-testid={`summary-item-${label}`} key={label} span={4}>
|
||||
<Typography.Text className="data-insight-label-text">
|
||||
{label}
|
||||
</Typography.Text>
|
||||
<Typography className="font-semibold text-2xl">
|
||||
{value}
|
||||
<Typography className="font-semibold text-2xl m--ml-0.5">
|
||||
{summary.latest}
|
||||
{summary.id.startsWith('Percentage') ? '%' : ''}
|
||||
</Typography>
|
||||
</Col>
|
||||
) : null;
|
||||
})}
|
||||
))}
|
||||
|
||||
{/* summary for web charts */}
|
||||
{webSummaryList.map((summary) => (
|
||||
<Col
|
||||
className="summary-card-item"
|
||||
data-testid={`summary-item-${summary.id}`}
|
||||
key={summary.id}
|
||||
span={6}
|
||||
onClick={() => onScrollToChart(summary.id)}>
|
||||
<Typography.Text className="data-insight-label-text">
|
||||
{summary.label}
|
||||
</Typography.Text>
|
||||
<Typography className="font-semibold text-2xl m--ml-0.5">
|
||||
{summary.latest}
|
||||
{summary.id.startsWith('Percentage') ? '%' : ''}
|
||||
</Typography>
|
||||
</Col>
|
||||
))}
|
||||
|
||||
{/* summary of most active user */}
|
||||
{mostActiveUser && mostActiveUser.userName && (
|
||||
<Col
|
||||
data-testid={`summary-item-${DataInsightChartType.MostActiveUsers}`}
|
||||
key={DataInsightChartType.MostActiveUsers}
|
||||
span={6}>
|
||||
<Typography.Text className="data-insight-label-text d-block">
|
||||
{t('label.most-active-user')}
|
||||
</Typography.Text>
|
||||
<UserPopOverCard userName={mostActiveUser.userName}>
|
||||
<Space>
|
||||
<ProfilePicture
|
||||
id=""
|
||||
name={mostActiveUser.userName}
|
||||
type="circle"
|
||||
/>
|
||||
<Link to={getUserPath(mostActiveUser.userName)}>
|
||||
{mostActiveUser.userName}
|
||||
</Link>
|
||||
</Space>
|
||||
</UserPopOverCard>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
|
@ -93,6 +93,7 @@ const DescriptionInsight: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-description-percentage-card"
|
||||
id={DataInsightChartType.PercentageOfEntitiesWithDescriptionByType}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -93,6 +93,7 @@ const OwnerInsight: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-summary-card-percentage"
|
||||
id={DataInsightChartType.PercentageOfEntitiesWithOwnerByType}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -90,6 +90,7 @@ const PageViewsByEntitiesChart: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-page-views-card"
|
||||
id={DataInsightChartType.PageViewsByEntities}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -89,6 +89,7 @@ const TierInsight: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-summary-card-percentage"
|
||||
id={DataInsightChartType.TotalEntitiesByTier}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -64,9 +64,9 @@ const TopViewEntities: FC<Props> = ({ chartFilter }) => {
|
||||
const columns: ColumnsType<MostViewedEntities> = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t('label.entity-name'),
|
||||
title: t('label.data-asset'),
|
||||
dataIndex: 'entityFqn',
|
||||
key: 'entityName',
|
||||
key: 'dataAsset',
|
||||
render: (entityFqn: string) => (
|
||||
<Typography.Text>{getDecodedFqn(entityFqn)}</Typography.Text>
|
||||
),
|
||||
@ -82,7 +82,7 @@ const TopViewEntities: FC<Props> = ({ chartFilter }) => {
|
||||
<Typography.Text>{owner}</Typography.Text>
|
||||
</Space>
|
||||
) : (
|
||||
<Typography.Text>{t('label.no-owner')}</Typography.Text>
|
||||
<Typography.Text>--</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -107,7 +107,7 @@ const TopViewEntities: FC<Props> = ({ chartFilter }) => {
|
||||
{t('label.data-insight-top-viewed-entity-summary')}
|
||||
</Typography.Title>
|
||||
<Typography.Text className="data-insight-label-text">
|
||||
{t('message.most-viewed-datasets')}
|
||||
{t('message.most-viewed-data-assets')}
|
||||
</Typography.Text>
|
||||
</>
|
||||
}>
|
||||
|
@ -92,6 +92,7 @@ const TotalEntityInsight: FC<Props> = ({ chartFilter }) => {
|
||||
<Card
|
||||
className="data-insight-card"
|
||||
data-testid="entity-summary-card"
|
||||
id={DataInsightChartType.TotalEntitiesByType}
|
||||
loading={isLoading}
|
||||
title={
|
||||
<>
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
import i18n from 'i18next';
|
||||
import { Margin } from 'recharts/types/util/types';
|
||||
import { DataReportIndex } from '../generated/dataInsight/dataInsightChart';
|
||||
import { DataInsightChartType } from '../generated/dataInsight/dataInsightChartResult';
|
||||
import { ChartFilter } from '../interface/data-insight.interface';
|
||||
import {
|
||||
getCurrentDateTimeMillis,
|
||||
@ -67,7 +69,7 @@ export const TIER_BAR_COLOR_MAP: Record<string, string> = {
|
||||
};
|
||||
|
||||
export const DATA_INSIGHT_TAB = {
|
||||
Datasets: 'Datasets',
|
||||
DataAssets: 'Data assets',
|
||||
'Web Analytics': 'Web Analytics',
|
||||
};
|
||||
|
||||
@ -117,3 +119,57 @@ export const INITIAL_CHART_FILTER: ChartFilter = {
|
||||
startTs: getPastDaysDateTimeMillis(DEFAULT_DAYS),
|
||||
endTs: getCurrentDateTimeMillis(),
|
||||
};
|
||||
|
||||
export const ENTITIES_CHARTS = [
|
||||
DataInsightChartType.TotalEntitiesByType,
|
||||
DataInsightChartType.PercentageOfEntitiesWithDescriptionByType,
|
||||
DataInsightChartType.PercentageOfEntitiesWithOwnerByType,
|
||||
DataInsightChartType.TotalEntitiesByTier,
|
||||
];
|
||||
|
||||
export const WEB_CHARTS = [
|
||||
{
|
||||
chart: DataInsightChartType.PageViewsByEntities,
|
||||
index: DataReportIndex.WebAnalyticEntityViewReportDataIndex,
|
||||
},
|
||||
{
|
||||
chart: DataInsightChartType.DailyActiveUsers,
|
||||
index: DataReportIndex.WebAnalyticUserActivityReportDataIndex,
|
||||
},
|
||||
];
|
||||
|
||||
export const WEB_SUMMARY_LIST = [
|
||||
{
|
||||
label: i18n.t('label.page-views-by-entities'),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.PageViewsByEntities,
|
||||
},
|
||||
{
|
||||
label: i18n.t('label.daily-active-user'),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.DailyActiveUsers,
|
||||
},
|
||||
];
|
||||
|
||||
export const ENTITIES_SUMMARY_LIST = [
|
||||
{
|
||||
label: i18n.t('label.total-data-assets'),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.TotalEntitiesByType,
|
||||
},
|
||||
{
|
||||
label: i18n.t('label.data-assets-with-field', { field: 'description' }),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.PercentageOfEntitiesWithDescriptionByType,
|
||||
},
|
||||
{
|
||||
label: i18n.t('label.data-assets-with-field', { field: 'owners' }),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.PercentageOfEntitiesWithOwnerByType,
|
||||
},
|
||||
{
|
||||
label: i18n.t('label.total-data-assets-with-tiers'),
|
||||
latest: 0,
|
||||
id: DataInsightChartType.TotalEntitiesByTier,
|
||||
},
|
||||
];
|
||||
|
@ -175,12 +175,12 @@
|
||||
"scopes-comma-separated": "Scopes value comma separated",
|
||||
"find-in-table": "Find in table",
|
||||
"data-insight-summary": "OpenMetadata health at a glance",
|
||||
"data-insight-description-summary": "Percentage of Datasets With Description",
|
||||
"data-insight-owner-summary": "Percentage of Datasets With Owners",
|
||||
"data-insight-tier-summary": "Total Datasets by Tier",
|
||||
"data-insight-description-summary": "Percentage of Data assets With Description",
|
||||
"data-insight-owner-summary": "Percentage of Data assets With Owners",
|
||||
"data-insight-tier-summary": "Total Data assets by Tier",
|
||||
"data-insight-active-user-summary": "Most Active Users",
|
||||
"data-insight-top-viewed-entity-summary": "Most Viewed Datasets",
|
||||
"data-insight-total-entity-summary": "Total Datasets",
|
||||
"data-insight-top-viewed-entity-summary": "Most Viewed Data assets",
|
||||
"data-insight-total-entity-summary": "Total Data assets",
|
||||
"user": "User",
|
||||
"team": "Team",
|
||||
"most-recent-session": "Most Recent Session",
|
||||
@ -227,12 +227,17 @@
|
||||
"read-more": "read more",
|
||||
"read-less": "read less",
|
||||
"no-owner": "No Owner",
|
||||
"page-views-by-entities": "Page views by datasets",
|
||||
"page-views-by-entities": "Page views by data assets",
|
||||
"daily-active-user": "Daily active users on the platform",
|
||||
"collapse-all": "Collapse All",
|
||||
"expand-all": "Expand All",
|
||||
"search-lineage": "Search Lineage",
|
||||
"edit-lineage": "Edit Lineage"
|
||||
"edit-lineage": "Edit Lineage",
|
||||
"data-asset": "Data asset",
|
||||
"total-data-assets": "Total data assets",
|
||||
"data-assets-with-field": "Data assets with {{field}}",
|
||||
"total-data-assets-with-tiers": "Total Data assets with tiers",
|
||||
"most-active-user": "Most active user"
|
||||
},
|
||||
"message": {
|
||||
"service-email-required": "Service account Email is required",
|
||||
@ -255,11 +260,11 @@
|
||||
"no-ingestion-description": "To view Ingestion Data, run the MetaData Ingestion. Please refer to this doc to schedule the",
|
||||
"fetch-pipeline-status-error": "Error while fetching pipeline status.",
|
||||
"data-insight-page-views": "Displays the number of time an dataset type was viewed.",
|
||||
"field-insight": "Display the percentage of datasets with {{field}} by type.",
|
||||
"total-entity-insight": "Display the total of datasets by type.",
|
||||
"field-insight": "Display the percentage of data assets with {{field}} by type.",
|
||||
"total-entity-insight": "Display the total of data assets by type.",
|
||||
"active-users": "Display the number of users active.",
|
||||
"most-active-users": "Displays the most active users on the platform based on page views.",
|
||||
"most-viewed-datasets": "Displays the most viewed datasets."
|
||||
"most-viewed-data-assets": "Displays the most viewed data assets."
|
||||
},
|
||||
"server": {
|
||||
"no-followed-entities": "You have not followed anything yet.",
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
Space,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { searchQuery } from '../../axiosAPIs/searchAPI';
|
||||
|
||||
import { autocomplete } from '../../components/AdvancedSearch/AdvancedSearch.constants';
|
||||
@ -40,10 +40,12 @@ import {
|
||||
DATA_INSIGHT_TAB,
|
||||
DAY_FILTER,
|
||||
DEFAULT_DAYS,
|
||||
ENTITIES_CHARTS,
|
||||
INITIAL_CHART_FILTER,
|
||||
TIER_FILTER,
|
||||
} from '../../constants/DataInsight.constants';
|
||||
import { SearchIndex } from '../../enums/search.enum';
|
||||
import { DataInsightChartType } from '../../generated/dataInsight/dataInsightChartResult';
|
||||
import { ChartFilter } from '../../interface/data-insight.interface';
|
||||
import { getTeamFilter } from '../../utils/DataInsightUtils';
|
||||
import {
|
||||
@ -57,10 +59,12 @@ const fetchTeamSuggestions = autocomplete(SearchIndex.TEAM);
|
||||
|
||||
const DataInsightPage = () => {
|
||||
const [teamsOptions, setTeamOptions] = useState<SelectProps['options']>([]);
|
||||
const [activeTab, setActiveTab] = useState(DATA_INSIGHT_TAB.Datasets);
|
||||
const [activeTab, setActiveTab] = useState(DATA_INSIGHT_TAB.DataAssets);
|
||||
const [chartFilter, setChartFilter] =
|
||||
useState<ChartFilter>(INITIAL_CHART_FILTER);
|
||||
|
||||
const [selectedChart, setSelectedChart] = useState<DataInsightChartType>();
|
||||
|
||||
useEffect(() => {
|
||||
setChartFilter(INITIAL_CHART_FILTER);
|
||||
}, []);
|
||||
@ -120,6 +124,25 @@ const DataInsightPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleScrollToChart = (chartType: DataInsightChartType) => {
|
||||
if (ENTITIES_CHARTS.includes(chartType)) {
|
||||
setActiveTab(DATA_INSIGHT_TAB.DataAssets);
|
||||
} else {
|
||||
setActiveTab(DATA_INSIGHT_TAB['Web Analytics']);
|
||||
}
|
||||
setSelectedChart(chartType);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (selectedChart) {
|
||||
const element = document.getElementById(selectedChart);
|
||||
if (element) {
|
||||
element.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
||||
setSelectedChart(undefined);
|
||||
}
|
||||
}
|
||||
}, [selectedChart]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchDefaultTeamOptions();
|
||||
}, []);
|
||||
@ -187,7 +210,10 @@ const DataInsightPage = () => {
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<DataInsightSummary chartFilter={chartFilter} />
|
||||
<DataInsightSummary
|
||||
chartFilter={chartFilter}
|
||||
onScrollToChart={handleScrollToChart}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Radio.Group
|
||||
@ -200,7 +226,7 @@ const DataInsightPage = () => {
|
||||
onChange={(e) => setActiveTab(e.target.value)}
|
||||
/>
|
||||
</Col>
|
||||
{activeTab === DATA_INSIGHT_TAB.Datasets && (
|
||||
{activeTab === DATA_INSIGHT_TAB.DataAssets && (
|
||||
<>
|
||||
<Col span={24}>
|
||||
<TotalEntityInsight chartFilter={chartFilter} />
|
||||
@ -225,10 +251,10 @@ const DataInsightPage = () => {
|
||||
<PageViewsByEntitiesChart chartFilter={chartFilter} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<TopActiveUsers chartFilter={chartFilter} />
|
||||
<DailyActiveUsersChart chartFilter={chartFilter} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<DailyActiveUsersChart chartFilter={chartFilter} />
|
||||
<TopActiveUsers chartFilter={chartFilter} />
|
||||
</Col>
|
||||
</>
|
||||
)}
|
||||
|
@ -397,3 +397,7 @@
|
||||
.m--ml-1 {
|
||||
margin-left: -0.25rem /* -4px */;
|
||||
}
|
||||
|
||||
.m--ml-0\.5 {
|
||||
margin-left: -0.125rem /* -2px */;
|
||||
}
|
||||
|
@ -12,10 +12,14 @@
|
||||
*/
|
||||
|
||||
import { Card, Typography } from 'antd';
|
||||
import { isInteger, last, toNumber } from 'lodash';
|
||||
import { isInteger, isUndefined, last, toNumber } from 'lodash';
|
||||
import React from 'react';
|
||||
import { ListItem, ListValues } from 'react-awesome-query-builder';
|
||||
import { LegendProps, Surface } from 'recharts';
|
||||
import {
|
||||
ENTITIES_SUMMARY_LIST,
|
||||
WEB_SUMMARY_LIST,
|
||||
} from '../constants/DataInsight.constants';
|
||||
import {
|
||||
DataInsightChartResult,
|
||||
DataInsightChartType,
|
||||
@ -242,3 +246,62 @@ export const getFormattedActiveUsersData = (activeUsers: DailyActiveUsers[]) =>
|
||||
? getFormattedDateFromMilliSeconds(user.timestamp)
|
||||
: '',
|
||||
}));
|
||||
|
||||
export const getEntitiesChartSummary = (
|
||||
chartResults: (DataInsightChartResult | undefined)[]
|
||||
) => {
|
||||
const updatedSummaryList = ENTITIES_SUMMARY_LIST.map((summary) => {
|
||||
// grab the current chart type
|
||||
const chartData = chartResults.find(
|
||||
(chart) => chart?.chartType === summary.id
|
||||
);
|
||||
|
||||
// return default summary if chart data is undefined else calculate the latest count for chartType
|
||||
if (isUndefined(chartData)) return summary;
|
||||
else {
|
||||
if (chartData.chartType === DataInsightChartType.TotalEntitiesByTier) {
|
||||
const { total } = getGraphDataByTierType(chartData.data ?? []);
|
||||
|
||||
return { ...summary, latest: total };
|
||||
} else {
|
||||
const { total } = getGraphDataByEntityType(
|
||||
chartData.data ?? [],
|
||||
chartData.chartType
|
||||
);
|
||||
|
||||
return { ...summary, latest: total };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return updatedSummaryList;
|
||||
};
|
||||
|
||||
export const getWebChartSummary = (
|
||||
chartResults: (DataInsightChartResult | undefined)[]
|
||||
) => {
|
||||
const updatedSummary = WEB_SUMMARY_LIST.map((summary) => {
|
||||
// grab the current chart type
|
||||
const chartData = chartResults.find(
|
||||
(chart) => chart?.chartType === summary.id
|
||||
);
|
||||
// return default summary if chart data is undefined else calculate the latest count for chartType
|
||||
if (isUndefined(chartData)) return summary;
|
||||
else {
|
||||
if (chartData.chartType === DataInsightChartType.DailyActiveUsers) {
|
||||
const latestData = last(chartData.data);
|
||||
|
||||
return { ...summary, latest: latestData?.activeUsers ?? 0 };
|
||||
} else {
|
||||
const { total } = getGraphDataByEntityType(
|
||||
chartData.data ?? [],
|
||||
chartData.chartType
|
||||
);
|
||||
|
||||
return { ...summary, latest: total };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return updatedSummary;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user