{showLabel && (
-
+
{label ?? t('label.latest')}
-
+
)}
-
+
+
+ {changeInValue && !isNil(changeInValue) ? (
+
+ ) : (
+ ''
+ )}
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DataInsightSummary.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DataInsightSummary.tsx
index 667d98e12a2..30f114799c3 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DataInsightSummary.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DataInsightSummary.tsx
@@ -179,6 +179,7 @@ const DataInsightSummary: FC
= ({ chartFilter, onScrollToChart }) => {
return (
= ({ chartFilter, onScrollToChart }) => {
{summary.label}
-
+
{summary.latest}
{summary.id.startsWith('Percentage') ||
summary.id.includes(DataInsightChartType.TotalEntitiesByTier)
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.test.tsx
index 70f336307d0..78a3aae9aa1 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.test.tsx
@@ -49,6 +49,14 @@ jest.mock('../../utils/DataInsightUtils', () => ({
},
],
entities: ['Table', 'Topic', 'Database', 'Pipeline', 'Messaging'],
+ latestData: {
+ timestamp: '24/Oct',
+ Table: 0.3374,
+ Topic: 0.0353,
+ Database: 0.9774,
+ Pipeline: 0.4482,
+ Messaging: 0.3105,
+ },
})),
}));
@@ -65,6 +73,7 @@ describe('Test DescriptionInsight Component', () => {
);
const card = screen.getByTestId('entity-description-percentage-card');
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.tsx
index 9a40c65e339..d278aae2f07 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/DescriptionInsight.tsx
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-import { Card, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { isEmpty } from 'lodash';
+import { isEmpty, uniqueId } from 'lodash';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -61,9 +61,10 @@ import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
interface Props {
chartFilter: ChartFilter;
kpi: Kpi | undefined;
+ selectedDays: number;
}
-const DescriptionInsight: FC = ({ chartFilter, kpi }) => {
+const DescriptionInsight: FC = ({ chartFilter, kpi, selectedDays }) => {
const [totalEntitiesDescriptionByType, setTotalEntitiesDescriptionByType] =
useState();
@@ -71,7 +72,14 @@ const DescriptionInsight: FC = ({ chartFilter, kpi }) => {
const [activeKeys, setActiveKeys] = useState([]);
const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
- const { data, entities, total } = useMemo(() => {
+ const {
+ data,
+ entities,
+ total,
+ relativePercentage,
+ latestData,
+ isPercentageGraph,
+ } = useMemo(() => {
return getGraphDataByEntityType(
totalEntitiesDescriptionByType?.data ?? [],
DataInsightChartType.PercentageOfEntitiesWithDescriptionByType
@@ -140,56 +148,97 @@ const DescriptionInsight: FC = ({ chartFilter, kpi }) => {
>
}>
-
{data.length ? (
-
-
-
-
- axisTickFormatter(value, '%')}
- />
- } />
-
-
+
+
+
+
+
+
+
+ axisTickFormatter(value, '%')
+ }
+ />
+ } />
+
+
+
+
+
+
+
+ {t('label.completed-description')}
+ {isPercentageGraph ? ' %' : ''}
+
+
+
+ {entities.map((entity) => {
+ const progress = (latestData[entity] / Number(total)) * 100;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
) : (
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChart.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChart.tsx
index 5c717d5c39e..f8d2eee9660 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChart.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChart.tsx
@@ -27,6 +27,8 @@ import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import {
CartesianGrid,
+ Legend,
+ LegendProps,
Line,
LineChart,
ResponsiveContainer,
@@ -35,7 +37,12 @@ import {
YAxis,
} from 'recharts';
import { getLatestKpiResult, getListKpiResult } from '../../axiosAPIs/KpiAPI';
-import { GRAPH_BACKGROUND_COLOR, ROUTES } from '../../constants/constants';
+import {
+ DEFAULT_CHART_OPACITY,
+ GRAPH_BACKGROUND_COLOR,
+ HOVER_CHART_OPACITY,
+ ROUTES,
+} from '../../constants/constants';
import {
BAR_CHART_MARGIN,
DATA_INSIGHT_GRAPH_COLORS,
@@ -51,7 +58,12 @@ import {
ChartFilter,
UIKpiResult,
} from '../../interface/data-insight.interface';
-import { CustomTooltip, getKpiGraphData } from '../../utils/DataInsightUtils';
+import { updateActiveChartFilter } from '../../utils/ChartUtils';
+import {
+ CustomTooltip,
+ getKpiGraphData,
+ renderLegend,
+} from '../../utils/DataInsightUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import './DataInsightDetail.less';
import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
@@ -71,6 +83,8 @@ const KPIChart: FC = ({ chartFilter, kpiList }) => {
const [kpiLatestResults, setKpiLatestResults] =
useState>();
const [isLoading, setIsLoading] = useState(false);
+ const [activeKeys, setActiveKeys] = useState([]);
+ const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
const handleAddKpi = () => history.push(ROUTES.ADD_KPI);
@@ -152,6 +166,18 @@ const KPIChart: FC = ({ chartFilter, kpiList }) => {
return { ...getKpiGraphData(kpiResults, kpiList), kpiTooltipRecord };
}, [kpiResults, kpiList]);
+ const handleLegendClick: LegendProps['onClick'] = (event) => {
+ setActiveKeys((prevActiveKeys) =>
+ updateActiveChartFilter(event.dataKey, prevActiveKeys)
+ );
+ };
+ const handleLegendMouseEnter: LegendProps['onMouseEnter'] = (event) => {
+ setActiveMouseHoverKey(event.dataKey);
+ };
+ const handleLegendMouseLeave: LegendProps['onMouseLeave'] = () => {
+ setActiveMouseHoverKey('');
+ };
+
useEffect(() => {
setKpiResults([]);
setKpiLatestResults(undefined);
@@ -183,16 +209,10 @@ const KPIChart: FC = ({ chartFilter, kpiList }) => {
}>
{kpiList.length ? (
-
+
{graphData.length ? (
<>
- {!isUndefined(kpiLatestResults) && !isEmpty(kpiLatestResults) && (
-
-
-
- )}
-
-
+
= ({ chartFilter, kpiList }) => {
/>
+
+ {!isUndefined(kpiLatestResults) && !isEmpty(kpiLatestResults) && (
+
+
+
+ )}
>
) : (
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPILatestResults.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPILatestResults.tsx
index 1d3188b8d72..302eba04932 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPILatestResults.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPILatestResults.tsx
@@ -46,25 +46,30 @@ const KPILatestResults: FC = ({ kpiLatestResultsRecord }) => {
const isTargetMet = targetResult.targetMet;
return (
-
+
{resultData.displayName ?? name}
+
+
-
-
-
- {getKpiResultFeedback(daysLeft, Boolean(isTargetMet))}
-
+
+ {getKpiResultFeedback(daysLeft, Boolean(isTargetMet))}
+
+
);
})}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/OwnerInsight.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/OwnerInsight.tsx
index 028c8185c15..e69a08d2306 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/OwnerInsight.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/OwnerInsight.tsx
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-import { Card, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { isEmpty } from 'lodash';
+import { isEmpty, uniqueId } from 'lodash';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -61,9 +61,10 @@ import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
interface Props {
chartFilter: ChartFilter;
kpi: Kpi | undefined;
+ selectedDays: number;
}
-const OwnerInsight: FC = ({ chartFilter, kpi }) => {
+const OwnerInsight: FC = ({ chartFilter, kpi, selectedDays }) => {
const [totalEntitiesOwnerByType, setTotalEntitiesOwnerByType] =
useState();
@@ -71,7 +72,14 @@ const OwnerInsight: FC = ({ chartFilter, kpi }) => {
const [activeKeys, setActiveKeys] = useState([]);
const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
- const { data, entities, total } = useMemo(() => {
+ const {
+ data,
+ entities,
+ total,
+ relativePercentage,
+ latestData,
+ isPercentageGraph,
+ } = useMemo(() => {
return getGraphDataByEntityType(
totalEntitiesOwnerByType?.data ?? [],
DataInsightChartType.PercentageOfEntitiesWithOwnerByType
@@ -139,53 +147,96 @@ const OwnerInsight: FC = ({ chartFilter, kpi }) => {
>
}>
-
{data.length ? (
-
-
-
-
- axisTickFormatter(value, '%')}
- />
- } />
-
-
+
+
+
+
+
+
+
+ axisTickFormatter(value, '%')
+ }
+ />
+ } />
+
+
+
+
+
+
+
+ {t('label.assigned-entity', {
+ entity: t('label.owner'),
+ })}
+ {isPercentageGraph ? ' %' : ''}
+
+
+
+ {entities.map((entity) => {
+ const progress = (latestData[entity] / Number(total)) * 100;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
) : (
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/PageViewsByEntitiesChart.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/PageViewsByEntitiesChart.tsx
index 74d3b803b6f..375d6c90d7c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/PageViewsByEntitiesChart.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/PageViewsByEntitiesChart.tsx
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-import { Card, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { isEmpty } from 'lodash';
+import { isEmpty, uniqueId } from 'lodash';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -48,14 +48,17 @@ import {
renderLegend,
} from '../../utils/DataInsightUtils';
import { showErrorToast } from '../../utils/ToastUtils';
+import CustomStatistic from './CustomStatistic';
import './DataInsightDetail.less';
+import DataInsightProgressBar from './DataInsightProgressBar';
import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
interface Props {
chartFilter: ChartFilter;
+ selectedDays: number;
}
-const PageViewsByEntitiesChart: FC = ({ chartFilter }) => {
+const PageViewsByEntitiesChart: FC = ({ chartFilter, selectedDays }) => {
const [pageViewsByEntities, setPageViewsByEntities] =
useState();
@@ -63,12 +66,13 @@ const PageViewsByEntitiesChart: FC = ({ chartFilter }) => {
const [activeKeys, setActiveKeys] = useState([]);
const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
- const { data, entities, total } = useMemo(() => {
- return getGraphDataByEntityType(
- pageViewsByEntities,
- DataInsightChartType.PageViewsByEntities
- );
- }, [pageViewsByEntities]);
+ const { data, entities, total, relativePercentage, latestData } =
+ useMemo(() => {
+ return getGraphDataByEntityType(
+ pageViewsByEntities,
+ DataInsightChartType.PageViewsByEntities
+ );
+ }, [pageViewsByEntities]);
const { t } = useTranslation();
@@ -124,44 +128,79 @@ const PageViewsByEntitiesChart: FC = ({ chartFilter }) => {
>
}>
{data.length ? (
-
-
-
-
-
- } />
-
-
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+
+ {entities.map((entity) => {
+ const progress = (latestData[entity] / Number(total)) * 100;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
) : (
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TierInsight.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TierInsight.tsx
index 5313fd2c859..34b30d10a40 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TierInsight.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TierInsight.tsx
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-import { Card, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { isEmpty } from 'lodash';
+import { isEmpty, uniqueId } from 'lodash';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -56,9 +56,10 @@ import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
interface Props {
chartFilter: ChartFilter;
+ selectedDays: number;
}
-const TierInsight: FC = ({ chartFilter }) => {
+const TierInsight: FC = ({ chartFilter, selectedDays }) => {
const [totalEntitiesByTier, setTotalEntitiesByTier] =
useState();
@@ -66,7 +67,7 @@ const TierInsight: FC = ({ chartFilter }) => {
const [activeKeys, setActiveKeys] = useState([]);
const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
- const { data, tiers, total } = useMemo(() => {
+ const { data, tiers, total, relativePercentage, latestData } = useMemo(() => {
return getGraphDataByTierType(totalEntitiesByTier?.data ?? []);
}, [totalEntitiesByTier]);
@@ -122,50 +123,89 @@ const TierInsight: FC = ({ chartFilter }) => {
>
}>
-
{data.length ? (
-
-
-
-
-
- } />
-
-
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+ {t('label.assigned-entity', {
+ entity: t('label.tier'),
+ })}{' '}
+ %
+
+
+
+ {tiers.map((tiers) => {
+ const progress = (latestData[tiers] / Number(total)) * 100;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
) : (
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TotalEntityInsight.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TotalEntityInsight.tsx
index 7ed8ba53265..7ce052c880c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TotalEntityInsight.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/TotalEntityInsight.tsx
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-import { Card, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { isEmpty } from 'lodash';
+import { isEmpty, uniqueId } from 'lodash';
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -50,14 +50,17 @@ import {
renderLegend,
} from '../../utils/DataInsightUtils';
import { showErrorToast } from '../../utils/ToastUtils';
+import CustomStatistic from './CustomStatistic';
import './DataInsightDetail.less';
+import DataInsightProgressBar from './DataInsightProgressBar';
import { EmptyGraphPlaceholder } from './EmptyGraphPlaceholder';
interface Props {
chartFilter: ChartFilter;
+ selectedDays: number;
}
-const TotalEntityInsight: FC = ({ chartFilter }) => {
+const TotalEntityInsight: FC = ({ chartFilter, selectedDays }) => {
const [totalEntitiesByType, setTotalEntitiesByType] =
useState();
@@ -65,12 +68,13 @@ const TotalEntityInsight: FC = ({ chartFilter }) => {
const [activeKeys, setActiveKeys] = useState([]);
const [activeMouseHoverKey, setActiveMouseHoverKey] = useState('');
- const { data, entities, total } = useMemo(() => {
- return getGraphDataByEntityType(
- totalEntitiesByType?.data ?? [],
- DataInsightChartType.TotalEntitiesByType
- );
- }, [totalEntitiesByType]);
+ const { data, entities, total, relativePercentage, latestData } =
+ useMemo(() => {
+ return getGraphDataByEntityType(
+ totalEntitiesByType?.data ?? [],
+ DataInsightChartType.TotalEntitiesByType
+ );
+ }, [totalEntitiesByType]);
const { t } = useTranslation();
@@ -125,44 +129,81 @@ const TotalEntityInsight: FC = ({ chartFilter }) => {
>
}>
{data.length ? (
-
-
-
-
-
- } />
-
-
+
+
+
+
+
+
+
+ } />
+
+
+
+
+
+
+
+
+ {entities.map((entity) => {
+ const progress = (latestData[entity] / Number(total)) * 100;
+
+ return (
+
+
+
+ );
+ })}
+
+
+
) : (
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/SearchDropdown/SearchDropdown.less b/openmetadata-ui/src/main/resources/ui/src/components/SearchDropdown/SearchDropdown.less
index 23e706e54ac..4f768f3ea68 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/SearchDropdown/SearchDropdown.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/SearchDropdown/SearchDropdown.less
@@ -54,6 +54,8 @@
}
.quick-filter-dropdown-trigger-btn {
+ padding: 4px 8px;
+
.remove-field-icon {
color: @remove-icon-color;
padding-bottom: 2px;
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/DataInsight.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/DataInsight.constants.ts
index 467a82195f2..72d49d26fdb 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/DataInsight.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/DataInsight.constants.ts
@@ -23,8 +23,8 @@ import {
export const BAR_CHART_MARGIN: Margin = {
top: 20,
- right: 30,
- left: 20,
+ right: 20,
+ left: 10,
bottom: 5,
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
index a2159116d09..e98ee58c187 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
@@ -30,7 +30,7 @@ export const GRAPH_BACKGROUND_COLOR = '#f5f5f5';
export const GRAYED_OUT_COLOR = '#CCCCCC';
export const DEFAULT_CHART_OPACITY = 1;
-export const HOVER_CHART_OPACITY = 0.5;
+export const HOVER_CHART_OPACITY = 0.3;
export const SUPPORTED_FIELD_TYPES = ['string', 'markdown', 'integer'];
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
index 82dce2bee13..2d26e646a0f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
@@ -577,7 +577,14 @@
"event-type": "Event Type",
"connection-timeout-plural-optional": "Connection Timeout (s)",
"all-data-assets": "All Data Assets",
- "specific-data-assets": "Specific Data Assets"
+ "specific-data-assets": "Specific Data Assets",
+ "days-change-lowercase": "{{days}}-days change",
+ "total-entity": "Total {{entity}}",
+ "assets": "Assets",
+ "completed-description": "Completed Description",
+ "assigned-entity": "Assigned {{entity}}",
+ "total-assets-view": "Total Assets View",
+ "total-active-user": "Total Active User"
},
"message": {
"service-email-required": "Service account Email is required",
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsight.less b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsight.less
index 9657cb13826..568f963878a 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsight.less
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsight.less
@@ -17,6 +17,8 @@
@box-shadow-color: rgba(0, 0, 0, 0.06);
@icon-color: #515151;
@group-title-color: #76746f;
+@summary-card-bg-hover: #f0f1f3;
+@target-blue-color: #1890ff;
.data-insight-select-dropdown {
min-width: 136px;
@@ -28,6 +30,7 @@
.data-insight-left-panel.ant-menu-root.ant-menu-inline {
background: @white;
border: 0px;
+ margin-top: 16px;
.ant-menu-item::after {
left: 0;
@@ -87,6 +90,7 @@
// library has given height directly via style attribute , so to override need to provide !important
height: 30px !important;
}
+
.ant-progress-outer {
margin-right: 0;
padding-right: 0;
@@ -109,12 +113,48 @@
left: 2px;
padding: 0 16px 0 8px;
font-size: 12px;
+ color: @text-color;
}
.data-insight-kpi-target {
height: 100%;
position: absolute;
left: 0;
- border-right: 2px solid #1890ff;
- border-radius: 4px;
+ border-right: 2px solid @target-blue-color;
+
+ .target-text {
+ position: relative;
+ right: -8px;
+ top: -14px;
+ display: flex;
+ justify-content: flex-end;
+ font-size: 10px;
+ }
+
+ &::after {
+ content: '●';
+ position: absolute;
+ top: -5px;
+ right: -6px;
+ color: @target-blue-color;
+ font-size: 10px;
+ }
+ }
+}
+
+.custom-data-insight-legend {
+ display: flex;
+ gap: 4px;
+
+ .custom-data-insight-legend-item {
+ display: flex;
+ align-items: center;
+ padding: 4px 8px;
+ cursor: pointer;
+ border-radius: 4px;
+ color: @text-grey-muted;
+
+ &:hover {
+ background: @summary-card-bg-hover;
+ }
}
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightPage.component.tsx
index 6655e77ed5b..364850bfa4c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightPage.component.tsx
@@ -94,6 +94,7 @@ const DataInsightPage = () => {
const [chartFilter, setChartFilter] =
useState(INITIAL_CHART_FILTER);
const [kpiList, setKpiList] = useState>([]);
+ const [selectedDaysFilter, setSelectedDaysFilter] = useState(DEFAULT_DAYS);
const [selectedChart, setSelectedChart] = useState();
@@ -127,6 +128,7 @@ const DataInsightPage = () => {
};
const handleDaysChange = (days: number) => {
+ setSelectedDaysFilter(days);
setChartFilter((previous) => ({
...previous,
startTs: getPastDaysDateTimeMillis(days),
@@ -356,19 +358,30 @@ const DataInsightPage = () => {
{activeTab === DataInsightTabs.DATA_ASSETS && (
<>
-
+
-
+
-
+
>
)}
@@ -378,10 +391,16 @@ const DataInsightPage = () => {
-
+
-
+
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/DataInsightUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/DataInsightUtils.tsx
index 06beed559db..46ce21d2a94 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/DataInsightUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/DataInsightUtils.tsx
@@ -15,6 +15,7 @@ import { Card, Typography } from 'antd';
import { RangePickerProps } from 'antd/lib/date-picker';
import { t } from 'i18next';
import {
+ first,
groupBy,
isEmpty,
isInteger,
@@ -52,7 +53,10 @@ import {
KpiDates,
} from '../interface/data-insight.interface';
import { pluralize } from './CommonUtils';
-import { getFormattedDateFromMilliSeconds } from './TimeUtils';
+import {
+ getDateByTimeStamp,
+ getFormattedDateFromMilliSeconds,
+} from './TimeUtils';
const checkIsPercentageGraph = (dataInsightChartType: DataInsightChartType) =>
[
@@ -62,62 +66,46 @@ const checkIsPercentageGraph = (dataInsightChartType: DataInsightChartType) =>
export const renderLegend = (
legendData: LegendProps,
- latest: string | number,
- activeKeys = [] as string[],
- showLatestValue = true
+ activeKeys = [] as string[]
) => {
const { payload = [] } = legendData;
return (
- <>
- {showLatestValue && (
- <>
-
- Latest
-
-
- {latest}
-
- >
- )}
-
- {payload.map((entry, index) => {
- const isActive =
- activeKeys.length === 0 || activeKeys.includes(entry.value);
+
+ {payload.map((entry, index) => {
+ const isActive =
+ activeKeys.length === 0 || activeKeys.includes(entry.value);
- return (
- -
- legendData.onClick && legendData.onClick({ ...entry, ...e })
- }
- onMouseEnter={(e) =>
- legendData.onMouseEnter &&
- legendData.onMouseEnter({ ...entry, ...e })
- }
- onMouseLeave={(e) =>
- legendData.onMouseLeave &&
- legendData.onMouseLeave({ ...entry, ...e })
- }>
-
-
-
-
- {entry.value}
-
-
- );
- })}
-
- >
+ return (
+ -
+ legendData.onClick && legendData.onClick({ ...entry, ...e })
+ }
+ onMouseEnter={(e) =>
+ legendData.onMouseEnter &&
+ legendData.onMouseEnter({ ...entry, ...e })
+ }
+ onMouseLeave={(e) =>
+ legendData.onMouseLeave &&
+ legendData.onMouseLeave({ ...entry, ...e })
+ }>
+
+
+
+
+ {entry.value}
+
+
+ );
+ })}
+
);
};
@@ -157,20 +145,29 @@ const getEntryFormattedValue = (
};
export const CustomTooltip = (props: DataInsightChartTooltipProps) => {
- const { active, payload = [], label, isPercentage, kpiTooltipRecord } = props;
+ const { active, payload = [], isPercentage, kpiTooltipRecord } = props;
if (active && payload && payload.length) {
+ const timestamp = getDateByTimeStamp(
+ payload[0].payload.timestampValue || 0,
+ 'MMM dd, yyyy'
+ );
+
return (
-
- {/* this is a graph tooltip so using the explicit title here */}
- {label}
+ {timestamp}}>
{payload.map((entry, index) => (
-
-
-
-
-
- {entry.dataKey} -{' '}
+
+
+
+
+
+ {entry.dataKey}
+
+
{getEntryFormattedValue(
entry.value,
entry.dataKey,
@@ -226,7 +223,8 @@ const getLatestCount = (latestData = {}) => {
const latestEntries = Object.entries(latestData ?? {});
for (const entry of latestEntries) {
- if (entry[0] !== 'timestamp') {
+ // if key is 'timestamp' or 'timestampValue' skipping its count for total
+ if (!['timestamp', 'timestampValue'].includes(entry[0])) {
total += toNumber(entry[1]);
}
}
@@ -290,6 +288,62 @@ const getLatestPercentage = (
return 0;
};
+/**
+ *
+ * @param rawData raw chart data
+ * @param dataInsightChartType chart type
+ * @returns old percentage for the chart
+ */
+const getOldestPercentage = (
+ rawData: DataInsightChartResult['data'] = [],
+ dataInsightChartType: DataInsightChartType
+) => {
+ let totalEntityCount = 0;
+ let totalEntityWithDescription = 0;
+ let totalEntityWithOwner = 0;
+
+ const modifiedData = rawData
+ .map((raw) => {
+ const timestamp = raw.timestamp;
+ if (timestamp) {
+ return {
+ ...raw,
+ timestamp,
+ };
+ }
+
+ return;
+ })
+ .filter(Boolean);
+
+ const sortedData = sortBy(modifiedData, 'timestamp');
+ const groupDataByTimeStamp = groupBy(sortedData, 'timestamp');
+ const oldestData = first(sortedData);
+ if (oldestData) {
+ const oldestChartRecords = groupDataByTimeStamp[oldestData.timestamp];
+
+ oldestChartRecords.forEach((record) => {
+ totalEntityCount += record?.entityCount ?? 0;
+ totalEntityWithDescription += record?.completedDescription ?? 0;
+ totalEntityWithOwner += record?.hasOwner ?? 0;
+ });
+ switch (dataInsightChartType) {
+ case DataInsightChartType.PercentageOfEntitiesWithDescriptionByType:
+ return ((totalEntityWithDescription / totalEntityCount) * 100).toFixed(
+ 2
+ );
+
+ case DataInsightChartType.PercentageOfEntitiesWithOwnerByType:
+ return ((totalEntityWithOwner / totalEntityCount) * 100).toFixed(2);
+
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+};
+
/**
*
* @param rawData raw chart data
@@ -341,6 +395,7 @@ const getGraphFilteredData = (
return {
timestamp: timestamp,
+ timestampValue: data.timestamp,
[data.entityType]: value,
};
}
@@ -370,7 +425,20 @@ export const getGraphDataByEntityType = (
);
const graphData = prepareGraphData(timestamps, filteredData);
- const latestData = last(graphData);
+ const latestData = last(graphData) as Record;
+ const oldData = first(graphData);
+ const latestPercentage = toNumber(
+ isPercentageGraph
+ ? getLatestPercentage(rawData, dataInsightChartType)
+ : getLatestCount(latestData)
+ );
+ const oldestPercentage = toNumber(
+ isPercentageGraph
+ ? getOldestPercentage(rawData, dataInsightChartType)
+ : getLatestCount(oldData)
+ );
+
+ const relativePercentage = latestPercentage - oldestPercentage;
return {
data: graphData,
@@ -378,6 +446,11 @@ export const getGraphDataByEntityType = (
total: isPercentageGraph
? getLatestPercentage(rawData, dataInsightChartType)
: getLatestCount(latestData),
+ relativePercentage: isPercentageGraph
+ ? relativePercentage
+ : (relativePercentage / oldestPercentage) * 100,
+ latestData,
+ isPercentageGraph,
};
};
@@ -403,6 +476,7 @@ export const getGraphDataByTierType = (rawData: TotalEntitiesByTier[]) => {
}
return {
+ timestampValue: data.timestamp,
timestamp: timestamp,
[tiering]: ((data?.entityCountFraction || 0) * 100).toFixed(2),
};
@@ -412,12 +486,16 @@ export const getGraphDataByTierType = (rawData: TotalEntitiesByTier[]) => {
});
const graphData = prepareGraphData(timestamps, filteredData);
- const latestData = last(graphData);
+ const latestData = getLatestCount(last(graphData));
+ const oldestData = getLatestCount(first(graphData));
+ const relativePercentage = latestData - oldestData;
return {
data: graphData,
tiers,
- total: getLatestCount(latestData),
+ total: latestData,
+ relativePercentage,
+ latestData: last(graphData) as Record,
};
};
@@ -430,14 +508,21 @@ export const getFormattedActiveUsersData = (
) => {
const formattedData = activeUsers.map((user) => ({
...user,
+ timestampValue: user.timestamp,
timestamp: user.timestamp
? getFormattedDateFromMilliSeconds(user.timestamp)
: '',
}));
+ const latestCount = Number(last(formattedData)?.activeUsers);
+ const oldestCount = Number(first(formattedData)?.activeUsers);
+
+ const relativePercentage = ((latestCount - oldestCount) / oldestCount) * 100;
+
return {
data: formattedData,
- total: last(formattedData)?.activeUsers,
+ total: latestCount,
+ relativePercentage,
};
};
@@ -518,6 +603,7 @@ export const getKpiGraphData = (kpiResults: KpiResult[], kpiList: Kpi[]) => {
}
return {
+ timestampValue: kpiResult.timestamp,
timestamp,
[kpiFqn]:
currentKpi?.metricType === KpiTargetType.Percentage