Day 1: Service insights and agents tab improvements and bug fixes (#20294)

* update the service data insights charts to give percentage data

* fix the quey_cost_record_search_index not found error

* Fix java checkstyle

* Refactor Service Insights Tab and Widgets for Enhanced Data Visualization

- Updated ServiceInsightsTab to utilize new date utility functions for fetching chart data.
- Modified chart data structure to include percentage changes and current percentages.
- Enhanced PlatformInsightsWidget to display percentage values and improved tooltip functionality.
- Added new styles for better layout and responsiveness in TotalDataAssetsWidget.
- Removed unused SERVICE_INSIGHTS_CHART constant and integrated its logic directly into the fetching process.
- Introduced new enums for additional chart types in DataInsight.

This refactor aims to improve the clarity and usability of the service insights data presentation.

* Localization changes

* Fix the platform insights chart colors

* Make the insights tab as default for service details page

* Enhance Ingestion Component and List Table

- Added logic to conditionally render search dropdowns based on the selected sub-tab in the Ingestion component.
- Increased column widths for 'type', 'count', and 'action' in the IngestionListTable for better visibility.
- Adjusted scroll width in the IngestionListTable to accommodate new column sizes.
- Updated styles in metadata-agents-widget.less to ensure vertical alignment of table cells.
- Modified applicationAPI to include agentType in the application list parameters.
- Enhanced router utility to support sub-tab routing.

These changes aim to improve the user experience and layout of the Ingestion settings.

* Fix the playwright failures

* Fix the playwright tests

* fix notification alert flakiness

* Fix metadata agents table header styling

* localization changes

* Fix the flaky test
This commit is contained in:
Aniket Katkar 2025-03-18 15:47:24 +05:30 committed by GitHub
parent 5f3b0b4327
commit e4c10bc401
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 350 additions and 166 deletions

View File

@ -244,7 +244,8 @@ public class MigrationUtil {
new LineChart()
.withMetrics(List.of(new LineChartMetric().withFormula("count(k='id.keyword')")))
.withxAxisField("tags.tagFQN")
.withIncludeXAxisFiled("pii.*"),
.withIncludeXAxisFiled("pii.*")
.withGroupBy("tags.name.keyword"),
DataInsightCustomChart.ChartType.BAR_CHART);
createChart(
@ -252,7 +253,8 @@ public class MigrationUtil {
new LineChart()
.withMetrics(List.of(new LineChartMetric().withFormula("count(k='id.keyword')")))
.withxAxisField("tags.tagFQN")
.withIncludeXAxisFiled("tier.*"),
.withIncludeXAxisFiled("tier.*")
.withGroupBy("tags.name.keyword"),
DataInsightCustomChart.ChartType.BAR_CHART);
createChart(
@ -261,13 +263,17 @@ public class MigrationUtil {
.withMetrics(
List.of(
new LineChartMetric()
.withFormula("count(k='id.keyword',q='hasDescription: 1')"))));
.withFormula(
"(count(k='id.keyword',q='hasDescription: 1')/count(k='id.keyword'))*100"))));
createChart(
"assets_with_owners",
new LineChart()
.withMetrics(
List.of(new LineChartMetric().withFormula("count(k='id.keyword',q='owners: *')"))));
List.of(
new LineChartMetric()
.withFormula(
"(count(k='id.keyword',q='owners.name.keyword: *')/count(k='id.keyword'))*100"))));
createChart(
"assets_with_pii",
@ -276,14 +282,17 @@ public class MigrationUtil {
List.of(
new LineChartMetric()
.withFormula(
"count(q='tags.tagFQN: pii.sensitive OR tags.tagFQN:"
+ " pii.nonsensitive OR tags.tagFQN: pii.none')"))));
"(count(q='tags.tagFQN: pii.sensitive OR tags.tagFQN:"
+ " pii.nonsensitive OR tags.tagFQN: pii.none')/count(k='id.keyword'))*100"))));
createChart(
"assets_with_tier",
new LineChart()
.withMetrics(
List.of(new LineChartMetric().withFormula("count(q='tags.tagFQN: tier.*')"))));
List.of(
new LineChartMetric()
.withFormula(
"(count(q='tags.tagFQN: tier.*')/count(k='id.keyword'))*100"))));
createChart(
"description_source_breakdown",

View File

@ -31,6 +31,7 @@ import org.openmetadata.schema.entity.data.QueryCostSearchResult;
import org.openmetadata.schema.entity.data.QueryDetails;
import org.openmetadata.schema.entity.data.QueryGroup;
import org.openmetadata.schema.entity.data.QueryHolder;
import org.openmetadata.service.Entity;
public class QueryCostRecordsAggregator {
@ -112,7 +113,11 @@ public class QueryCostRecordsAggregator {
}
// Build the search request
searchRequest = searchRequestBuilder.request().indices("query_cost_record_search_index");
searchRequest =
searchRequestBuilder
.request()
.indices(
Entity.getSearchRepository().getIndexOrAliasName("query_cost_record_search_index"));
return searchRequest;
}

View File

@ -10,6 +10,7 @@ import org.openmetadata.schema.entity.data.QueryCostSearchResult;
import org.openmetadata.schema.entity.data.QueryDetails;
import org.openmetadata.schema.entity.data.QueryGroup;
import org.openmetadata.schema.entity.data.QueryHolder;
import org.openmetadata.service.Entity;
import os.org.opensearch.action.search.SearchAction;
import os.org.opensearch.action.search.SearchRequest;
import os.org.opensearch.action.search.SearchRequestBuilder;
@ -112,7 +113,11 @@ public class QueryCostRecordsAggregator {
}
// Build the search request
searchRequest = searchRequestBuilder.request().indices("query_cost_record_search_index");
searchRequest =
searchRequestBuilder
.request()
.indices(
Entity.getSearchRepository().getIndexOrAliasName("query_cost_record_search_index"));
return searchRequest;
}

View File

@ -166,6 +166,10 @@ test.describe('Bulk Edit Entity', () => {
await toastNotification(page, /details updated successfully/);
await page.click('[data-testid="databases"]');
await page.waitForLoadState('networkidle');
// Verify Details updated
await expect(page.getByTestId('column-name')).toHaveText(
`${table.database.name}${databaseDetails.displayName}`

View File

@ -64,6 +64,7 @@ test.describe('Schema search', { tag: '@ingestion' }, () => {
await databasesResponse;
const schemaResponse = page.waitForResponse('/api/v1/databaseSchemas?**');
await page.click('[data-testid="databases"]');
await page.click(
`[data-testid="table-container"] >> text=${table.database.name}`
);

View File

@ -274,7 +274,6 @@ export const addOwnerFilter = async ({
// Search and select owner
const getSearchResult = page.waitForResponse('/api/v1/search/query?q=*');
await page.waitForSelector('.ant-select-dropdown:visible');
await page.fill(
'[data-testid="owner-name-select"] [role="combobox"]',
ownerName,

View File

@ -1001,6 +1001,10 @@ export const checkForEditActions = async ({
}
if (entityType.startsWith('services/')) {
await page.getByRole('tab').nth(1).click();
await page.waitForLoadState('networkidle');
continue;
}

View File

@ -68,6 +68,8 @@ export const fillOwnerDetails = async (page: Page, owners: string[]) => {
.locator('.InovuaReactDataGrid__cell--cell-active')
.press('Enter', { delay: 100 });
await page.waitForLoadState('networkidle');
const userListResponse = page.waitForResponse(
'/api/v1/search/query?q=*isBot:false*index=user_search_index*'
);

View File

@ -26,7 +26,8 @@ export const searchServiceFromSettingPage = async (
export const visitServiceDetailsPage = async (
page: Page,
service: { type: string; name: string; displayName?: string },
verifyHeader = false
verifyHeader = false,
visitChildrenTab = true
) => {
const serviceResponse = page.waitForResponse('/api/v1/services/*');
await settingClick(page, service.type as SettingOptionsType);
@ -37,6 +38,13 @@ export const visitServiceDetailsPage = async (
// Click on created service
await page.click(`[data-testid="service-name-${service.name}"]`);
if (visitChildrenTab) {
// Click on children tab Ex. DatabaseService -> Databases
await page.getByRole('tab').nth(1).click();
}
await page.waitForLoadState('networkidle');
if (verifyHeader) {
const text = await page.textContent(
`[data-testid="entity-header-display-name"]`

View File

@ -22,9 +22,9 @@ export interface ChartData {
export interface ChartSeriesData {
chartType: SystemChartType;
data: ChartData[];
percentageChange: number;
currentCount: number;
isIncreased: boolean;
percentageChange?: number;
currentPercentage: number;
isIncreased?: boolean;
}
export interface PlatformInsightsWidgetProps

View File

@ -19,6 +19,7 @@ import { ReactComponent as ArrowUp } from '../../../assets/svg/up-full-arrow.svg
import { GREEN_1, RED_1 } from '../../../constants/Color.constants';
import { PLATFORM_INSIGHTS_CHART } from '../../../constants/ServiceInsightsTab.constants';
import { getTitleByChartType } from '../../../utils/ServiceInsightsTabUtils';
import { getReadableCountString } from '../../../utils/ServiceUtils';
import TotalDataAssetsWidget from '../TotalDataAssetsWidget/TotalDataAssetsWidget';
import './platform-insights-widget.less';
import { PlatformInsightsWidgetProps } from './PlatformInsightsWidget.interface';
@ -39,7 +40,7 @@ function PlatformInsightsWidget({
{t('message.platform-insight-description')}
</Typography.Text>
<Row className="m-t-sm" gutter={16}>
<Row className="m-t-lg" gutter={16}>
<Col span={12}>
<TotalDataAssetsWidget serviceName={serviceName} />
</Col>
@ -68,28 +69,35 @@ function PlatformInsightsWidget({
className="flex flex-col justify-between h-full"
span={14}>
<Typography.Title level={3}>
{chart.currentCount}
{`${getReadableCountString(chart.currentPercentage)}%`}
</Typography.Title>
<div className="flex items-center gap-1 flex-wrap">
{chart.isIncreased ? (
<ArrowUp color={GREEN_1} height={11} width={11} />
) : (
<ArrowDown color={RED_1} height={11} width={11} />
)}
<Typography.Text
className="font-medium text-sm"
style={{
color: chart.isIncreased ? GREEN_1 : RED_1,
}}>
{`${chart.percentageChange}%`}
</Typography.Text>
<Typography.Text className="font-medium text-grey-muted text-sm">
{t('label.vs-last-month')}
</Typography.Text>
</div>
{chart.percentageChange && (
<div className="flex items-center gap-1 flex-wrap">
{chart.isIncreased ? (
<ArrowUp color={GREEN_1} height={11} width={11} />
) : (
<ArrowDown color={RED_1} height={11} width={11} />
)}
<Typography.Text
className="font-medium text-sm"
style={{
color: chart.isIncreased ? GREEN_1 : RED_1,
}}>
{`${getReadableCountString(
chart.percentageChange
)}%`}
</Typography.Text>
<Typography.Text className="font-medium text-grey-muted text-sm">
{t('label.vs-last-week-lowercase')}
</Typography.Text>
</div>
)}
</Col>
<Col className="flex items-end h-full" span={10}>
<ResponsiveContainer height={70} width="100%">
<ResponsiveContainer
height="90%"
minHeight={90}
width="100%">
<AreaChart data={chart.data}>
<defs>
{[GREEN_1, RED_1].map((color) => (

View File

@ -13,20 +13,18 @@
import { Col, Row } from 'antd';
import { AxiosError } from 'axios';
import { isUndefined, last, round } from 'lodash';
import { isUndefined, toLower } from 'lodash';
import { ServiceTypes } from 'Models';
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import {
PLATFORM_INSIGHTS_CHART,
SERVICE_INSIGHTS_CHART,
} from '../../constants/ServiceInsightsTab.constants';
import { PLATFORM_INSIGHTS_CHART } from '../../constants/ServiceInsightsTab.constants';
import { SystemChartType } from '../../enums/DataInsight.enum';
import { getMultiChartsPreviewByName } from '../../rest/DataInsightAPI';
import {
getCurrentMillis,
getEpochMillisForPastDays,
getCurrentDayStartGMTinMillis,
getDayAgoStartGMTinMillis,
} from '../../utils/date-time/DateTimeUtils';
import { getPlatformInsightsChartDataFormattingMethod } from '../../utils/ServiceInsightsTabUtils';
import serviceUtilClassBase from '../../utils/ServiceUtilClassBase';
import { showErrorToast } from '../../utils/ToastUtils';
import {
@ -50,51 +48,44 @@ const ServiceInsightsTab = ({ serviceDetails }: ServiceInsightsTabProps) => {
const serviceName = serviceDetails.name;
const widgets = serviceUtilClassBase.getInsightsTabWidgets(serviceCategory);
const fetchChartsData = async () => {
try {
setIsLoading(true);
const currentTimestampInMs = getCurrentMillis();
const sevenDaysAgoTimestampInMs = getEpochMillisForPastDays(7);
const currentTimestampInMs = getCurrentDayStartGMTinMillis();
const sevenDaysAgoTimestampInMs = getDayAgoStartGMTinMillis(7);
const chartsData = await getMultiChartsPreviewByName(
SERVICE_INSIGHTS_CHART,
{
start: sevenDaysAgoTimestampInMs,
end: currentTimestampInMs,
filter: `{"query":{"match":{"service.name.keyword":"${serviceName}"}}}`,
}
);
const chartsList = [
...PLATFORM_INSIGHTS_CHART,
...(widgets.PIIDistributionWidget
? [SystemChartType.PIIDistribution]
: []),
...(widgets.TierDistributionWidget
? [SystemChartType.TierDistribution]
: []),
];
const platformInsightsChart = PLATFORM_INSIGHTS_CHART.map((chartType) => {
const summaryChartData = chartsData[chartType];
const data = summaryChartData.results;
const firstDayValue = data.length > 1 ? data[0]?.count : 0;
const lastDayValue = data[data.length - 1]?.count;
const percentageChange =
((lastDayValue - firstDayValue) /
(firstDayValue === 0 ? lastDayValue : firstDayValue)) *
100;
const isIncreased = lastDayValue >= firstDayValue;
return {
chartType,
data,
isIncreased,
percentageChange: isNaN(percentageChange)
? 0
: round(Math.abs(percentageChange), 2),
currentCount: round(last(summaryChartData.results)?.count ?? 0, 2),
};
const chartsData = await getMultiChartsPreviewByName(chartsList, {
start: sevenDaysAgoTimestampInMs,
end: currentTimestampInMs,
filter: `{"query":{"match":{"service.name.keyword":"${serviceName}"}}}`,
});
const piiDistributionChart =
chartsData[SystemChartType.PIIDistribution].results;
const tierDistributionChart =
chartsData[SystemChartType.TierDistribution].results;
const platformInsightsChart = PLATFORM_INSIGHTS_CHART.map(
getPlatformInsightsChartDataFormattingMethod(
chartsData,
sevenDaysAgoTimestampInMs,
currentTimestampInMs
)
);
const piiDistributionChart = chartsData[
SystemChartType.PIIDistribution
]?.results.filter((item) => item.term.includes(toLower(item.group)));
const tierDistributionChart = chartsData[
SystemChartType.TierDistribution
]?.results.filter((item) => item.term.includes(toLower(item.group)));
setChartsResults({
platformInsightsChart,
@ -112,8 +103,6 @@ const ServiceInsightsTab = ({ serviceDetails }: ServiceInsightsTabProps) => {
fetchChartsData();
}, []);
const widgets = serviceUtilClassBase.getInsightsTabWidgets(serviceCategory);
const arrayOfWidgets = [
{ Widget: widgets.PlatformInsightsWidget, name: 'PlatformInsightsWidget' },
{ Widget: widgets.CollateAIWidget, name: 'CollateAIWidget' },

View File

@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Card, Skeleton, Tooltip, Typography } from 'antd';
import { Card, Skeleton, Typography } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -26,7 +26,10 @@ import { SearchIndex } from '../../../enums/search.enum';
import { searchQuery } from '../../../rest/searchAPI';
import { getEntityNameLabel } from '../../../utils/EntityUtils';
import { getAssetsByServiceType } from '../../../utils/ServiceInsightsTabUtils';
import { getServiceNameQueryFilter } from '../../../utils/ServiceUtils';
import {
getReadableCountString,
getServiceNameQueryFilter,
} from '../../../utils/ServiceUtils';
import { getEntityIcon } from '../../../utils/TableUtils';
import ErrorPlaceHolder from '../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import { ServiceInsightWidgetCommonProps } from '../ServiceInsightsTab.interface';
@ -41,11 +44,18 @@ function TotalDataAssetsWidget({
tab: string;
}>();
const [loadingCount, setLoadingCount] = useState<number>(0);
const [hoveredSegment, setHoveredSegment] = useState<{
name: string;
value: number;
} | null>(null);
const [entityCounts, setEntityCounts] =
useState<
Array<{ name: string; value: number; fill: string; icon: JSX.Element }>
>();
const totalCount =
entityCounts?.reduce((sum, entity) => sum + entity.value, 0) ?? 0;
const getDataAssetsCount = useCallback(async () => {
try {
setLoadingCount((count) => count + 1);
@ -117,14 +127,14 @@ function TotalDataAssetsWidget({
<Typography.Text>{entity.name}</Typography.Text>
</div>
<Typography.Text className="font-semibold">
{entity.value}
<Typography.Text className="font-bold">
{getReadableCountString(entity.value)}
</Typography.Text>
</div>
))}
</div>
<div className="h-full flex-center flex-half">
<ResponsiveContainer height="100%" width="100%">
<div className="chart-container">
<ResponsiveContainer height="100%" minHeight={275} width="100%">
<PieChart>
<Pie
cx="50%"
@ -132,8 +142,8 @@ function TotalDataAssetsWidget({
data={[{ value: 1 }]}
dataKey="value"
fill={WHITE_SMOKE}
innerRadius="75%"
outerRadius="98%">
innerRadius="74%"
outerRadius="99%">
<Cell fill={WHITE_SMOKE} />
</Pie>
<Pie
@ -141,14 +151,36 @@ function TotalDataAssetsWidget({
cy="50%"
data={entityCounts}
dataKey="value"
innerRadius="80%"
innerRadius="79%"
isAnimationActive={false}
nameKey="name"
outerRadius="93%"
outerRadius="94%"
onMouseEnter={(_, index) => {
if (entityCounts?.[index]) {
setHoveredSegment({
name: entityCounts[index].name,
value: entityCounts[index].value,
});
}
}}
onMouseLeave={() => setHoveredSegment(null)}
/>
<Tooltip />
</PieChart>
</ResponsiveContainer>
<div className="tooltip-container">
<Typography.Text strong className="text-md font-bold">
{getReadableCountString(
hoveredSegment ? hoveredSegment.value : totalCount
)}
</Typography.Text>
<Typography.Text className="text-sm text-grey-muted">
{hoveredSegment
? hoveredSegment.name
: t('label.total-entity', {
entity: t('label.asset-plural'),
})}
</Typography.Text>
</div>
</div>
</div>
)}

View File

@ -30,6 +30,15 @@
background-color: @grey-2;
}
.chart-container {
position: relative;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex: 0.6;
}
.assets-list-container {
flex: 0.5;
padding: 16px;
@ -41,6 +50,21 @@
height: fit-content;
}
.tooltip-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 8px;
z-index: 10;
pointer-events: none;
text-align: center;
}
.total-data-assets-info {
display: flex;
align-items: center;

View File

@ -17,7 +17,7 @@
height: 100%;
background-color: @white;
border-radius: @border-radius-sm;
border: none;
border: 1px solid @grey-12;
padding: 20px;
}

View File

@ -76,6 +76,8 @@ const Ingestion: React.FC<IngestionProps> = ({
[CollateAIAgentsWidget]
);
const isCollateSubTabSelected = subTab === ServiceAgentSubTabs.COLLATE_AI;
const { isAirflowAvailable } = useMemo(
() => airflowInformation,
[airflowInformation]
@ -169,43 +171,45 @@ const Ingestion: React.FC<IngestionProps> = ({
/>
)}
</Col>
<Col className="flex items-center gap-2">
<SearchDropdown
hideCounts
label={t('label.status')}
options={statusFilters}
searchKey="status"
selectedKeys={statusFilter ?? []}
triggerButtonSize="large"
onChange={handleStatusFilterChange}
onSearch={handleStatusFilterSearch}
/>
<SearchDropdown
hideCounts
label={t('label.type')}
options={typeFilters}
searchKey="status"
selectedKeys={typeFilter ?? []}
triggerButtonSize="large"
onChange={handleTypeFilterChange}
onSearch={handleTypeFilterSearch}
/>
<div className="search-bar-container">
<Searchbar
removeMargin
inputClassName="p-x-sm p-y-xs border-radius-xs"
placeholder={t('label.search')}
searchValue={searchText}
typingInterval={500}
onSearch={handleSearchChange}
{!isCollateSubTabSelected && (
<Col className="flex items-center gap-2">
<SearchDropdown
hideCounts
label={t('label.status')}
options={statusFilters}
searchKey="status"
selectedKeys={statusFilter ?? []}
triggerButtonSize="large"
onChange={handleStatusFilterChange}
onSearch={handleStatusFilterSearch}
/>
</div>
</Col>
<SearchDropdown
hideCounts
label={t('label.type')}
options={typeFilters}
searchKey="status"
selectedKeys={typeFilter ?? []}
triggerButtonSize="large"
onChange={handleTypeFilterChange}
onSearch={handleTypeFilterSearch}
/>
<div className="search-bar-container">
<Searchbar
removeMargin
inputClassName="p-x-sm p-y-xs border-radius-xs"
placeholder={t('label.search')}
searchValue={searchText}
typingInterval={500}
onSearch={handleSearchChange}
/>
</div>
</Col>
)}
</Row>
</Col>
<Col span={24}>
{subTab === ServiceAgentSubTabs.COLLATE_AI ? (
{isCollateSubTabSelected ? (
<CollateAIAgentsWidget />
) : (
<MetadataAgentsWidget

View File

@ -308,7 +308,6 @@ function IngestionListTable({
dataIndex: 'name',
key: 'name',
fixed: 'left' as FixedType,
width: 250,
render: customRenderNameField ?? renderNameField(searchText),
},
...(showDescriptionCol
@ -338,7 +337,7 @@ function IngestionListTable({
title: t('label.type'),
dataIndex: 'pipelineType',
key: 'pipelineType',
width: 120,
width: 150,
render: renderTypeField(searchText),
},
]),
@ -346,7 +345,7 @@ function IngestionListTable({
title: t('label.count'),
dataIndex: 'count',
key: 'count',
width: 150,
width: 220,
render: (_: string, record: IngestionPipeline) => {
return (
<IngestionStatusCount
@ -360,7 +359,6 @@ function IngestionListTable({
title: t('label.schedule'),
dataIndex: 'schedule',
key: 'schedule',
width: 150,
render: renderScheduleField,
},
{
@ -383,7 +381,7 @@ function IngestionListTable({
title: t('label.status'),
dataIndex: 'status',
key: 'status',
width: 80,
width: 90,
render: renderStatusField,
},
...(enableActions
@ -392,7 +390,7 @@ function IngestionListTable({
title: t('label.action-plural'),
dataIndex: 'actions',
key: 'actions',
width: 180,
width: 220,
fixed: 'right' as FixedType,
render: renderActionsField,
},
@ -450,7 +448,7 @@ function IngestionListTable({
}}
pagination={false}
rowKey="fullyQualifiedName"
scroll={{ x: 1500 }}
scroll={{ x: 1300 }}
size="small"
{...extraTableProps}
/>

View File

@ -58,6 +58,12 @@
tr > td:first-child.name-column {
padding-left: 16px;
}
.ant-table-thead tr > th {
text-transform: none;
}
.ant-table-cell {
vertical-align: middle;
}
}
}
}

View File

@ -17,7 +17,7 @@
height: 100%;
background-color: @white;
border-radius: @border-radius-sm;
border: none;
border: 1px solid @grey-12;
padding: 20px;
}

View File

@ -19,9 +19,3 @@ export const PLATFORM_INSIGHTS_CHART: SystemChartType[] = [
SystemChartType.TierCoverage,
SystemChartType.OwnersCoverage,
];
export const SERVICE_INSIGHTS_CHART: SystemChartType[] = [
...PLATFORM_INSIGHTS_CHART,
SystemChartType.PIIDistribution,
SystemChartType.TierDistribution,
];

View File

@ -33,4 +33,8 @@ export enum SystemChartType {
OwnersCoverage = 'assets_with_owners',
PIIDistribution = 'assets_with_pii_bar',
TierDistribution = 'assets_with_tier_bar',
DescriptionSourceBreakdown = 'description_source_breakdown',
TagSourceBreakdown = 'tag_source_breakdown',
TierSourceBreakdown = 'tier_source_breakdown',
DataQualityTestBreakdown = 'data_quality_test_breakdown',
}

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Datenverhältnisse",
"data-quality": "Datenqualität",
"data-quality-test": "Datenqualitätstest",
"data-quality-test-plural": "Datenqualitätstests",
"data-quartile-plural": "Datenquartile",
"data-range": "Datenbereich",
"data-type": "Datentyp",
@ -1337,6 +1338,7 @@
"thursday": "Donnerstag",
"tier": "Stufe",
"tier-number": "Stufe {{tier}}",
"tier-plural": "Tiers",
"tier-plural-lowercase": "stufen",
"time": "Zeit",
"timeout": "Zeitüberschreitung",
@ -1437,7 +1439,7 @@
"view-plural": "Ansichten",
"visit-developer-website": "Entwicklerwebsite aufrufen",
"volume-change": "Volumenänderung",
"vs-last-month": "vs. letzter Monat",
"vs-last-week-lowercase": "vs letzte Woche",
"wants-to-access-your-account": "möchte auf deinen Account {{username}} zugreifen",
"warning": "Warnung",
"warning-plural": "Warnungen",

View File

@ -123,7 +123,7 @@
"auto-tag-pii-uppercase": "Auto Tag PII",
"automatically-generate": "Automatically Generate",
"average-daily-active-users-on-the-platform": "Average Daily Active Users on the Platform",
"average-entity": "Average {{entity}}",
"average-entity": "Avg. {{entity}}",
"average-session": "Avg. Session Time",
"awaiting-status": "Awaiting status",
"aws-access-key-id": "AWS Access Key ID",
@ -327,6 +327,7 @@
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "Data Quality Test",
"data-quality-test-plural": "Data Quality Tests",
"data-quartile-plural": "Data Quartiles",
"data-range": "Data Range",
"data-type": "Data Type",
@ -1337,6 +1338,7 @@
"thursday": "Thursday",
"tier": "Tier",
"tier-number": "Tier{{tier}}",
"tier-plural": "Tiers",
"tier-plural-lowercase": "tiers",
"time": "Time",
"timeout": "Timeout",
@ -1437,7 +1439,7 @@
"view-plural": "Views",
"visit-developer-website": "Visit developer website",
"volume-change": "Volume Change",
"vs-last-month": "vs last month",
"vs-last-week-lowercase": "vs last week",
"wants-to-access-your-account": "wants to access your {{username}} account",
"warning": "Warning",
"warning-plural": "Warnings",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Proporciones de datos",
"data-quality": "Tests de calidad",
"data-quality-test": "Test de calidad de datos",
"data-quality-test-plural": "Pruebas de Calidad de Datos",
"data-quartile-plural": "cuartiles",
"data-range": "Rango de datos",
"data-type": "Tipo de datos",
@ -1337,6 +1338,7 @@
"thursday": "Jueves",
"tier": "Nivel",
"tier-number": "Nivel {{tier}}",
"tier-plural": "Niveles",
"tier-plural-lowercase": "niveles",
"time": "Tiempo",
"timeout": "Tiempo de espera",
@ -1437,7 +1439,7 @@
"view-plural": "Vistas",
"visit-developer-website": "Visite la web del desarrollador",
"volume-change": "Cambios de volumen",
"vs-last-month": "vs mes anterior",
"vs-last-week-lowercase": "vs semana pasada",
"wants-to-access-your-account": "quiere acceder a su cuenta {{username}}",
"warning": "Advertencia",
"warning-plural": "Advertencias",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Proportions des Données",
"data-quality": "Qualité des Données",
"data-quality-test": "Test de Qualité des Données",
"data-quality-test-plural": "Tests de Qualité des Données",
"data-quartile-plural": "Quartiles des Données",
"data-range": "Plage de Données",
"data-type": "Type de Données",
@ -1337,6 +1338,7 @@
"thursday": "Jeudi",
"tier": "Niveau",
"tier-number": "Niveau {{tier}}",
"tier-plural": "Niveaux",
"tier-plural-lowercase": "niveaux",
"time": "Heure",
"timeout": "Délai d'Attente",
@ -1437,7 +1439,7 @@
"view-plural": "Vues",
"visit-developer-website": "Visiter le site du développeur",
"volume-change": "Changement de Volume",
"vs-last-month": "vs mois dernier",
"vs-last-week-lowercase": "vs semaine dernière",
"wants-to-access-your-account": "souhaite accéder à votre compte {{username}}",
"warning": "Attention",
"warning-plural": "Warnings",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Proporcións de datos",
"data-quality": "Calidade dos datos",
"data-quality-test": "Proba de calidade de datos",
"data-quality-test-plural": "Pruebas de Calidad de Datos",
"data-quartile-plural": "Cuartís de datos",
"data-range": "Rango de datos",
"data-type": "Tipo de datos",
@ -1337,6 +1338,7 @@
"thursday": "Xoves",
"tier": "Nivel",
"tier-number": "Nivel{{tier}}",
"tier-plural": "Niveles",
"tier-plural-lowercase": "niveis",
"time": "Tempo",
"timeout": "Tempo de espera",
@ -1437,7 +1439,7 @@
"view-plural": "Vistas",
"visit-developer-website": "Visitar o sitio web do desenvolvedor",
"volume-change": "Cambio de volume",
"vs-last-month": "vs mes anterior",
"vs-last-week-lowercase": "vs semana pasada",
"wants-to-access-your-account": "quere acceder á túa conta de {{username}}",
"warning": "Advertencia",
"warning-plural": "Advertencias",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "יחסי נתונים",
"data-quality": "איכות נתונים",
"data-quality-test": "בקרת איכות נתונים",
"data-quality-test-plural": "בדיקות איכות נתונים",
"data-quartile-plural": "רביעונים (Quaertiles)",
"data-range": "טווח נתונים",
"data-type": "סוג עמודה",
@ -1337,6 +1338,7 @@
"thursday": "יום חמישי",
"tier": "שכבת מידע",
"tier-number": "שכבת מידע {{tier}}",
"tier-plural": "רמות",
"tier-plural-lowercase": "שכבות",
"time": "זמן",
"timeout": "פסק זמן",
@ -1437,7 +1439,7 @@
"view-plural": "תצוגות",
"visit-developer-website": "בקר באתר המפתח",
"volume-change": "שינוי נפח",
"vs-last-month": "לעומת החודש שעבר",
"vs-last-week-lowercase": "לעומת שבוע שעבר",
"wants-to-access-your-account": "רוצה לגשת לחשבון {{username}} שלך",
"warning": "אזהרה",
"warning-plural": "Warnings",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Data Proportions",
"data-quality": "Data Quality",
"data-quality-test": "データ品質テスト",
"data-quality-test-plural": "データ品質テスト",
"data-quartile-plural": "Data Quartiles",
"data-range": "Data Range",
"data-type": "データ型",
@ -1337,6 +1338,7 @@
"thursday": "木曜日",
"tier": "ティア",
"tier-number": "ティア{{tier}}",
"tier-plural": "階層",
"tier-plural-lowercase": "tiers",
"time": "時間",
"timeout": "タイムアウト",
@ -1437,7 +1439,7 @@
"view-plural": "Views",
"visit-developer-website": "Visit developer website",
"volume-change": "Volume Change",
"vs-last-month": "先月比",
"vs-last-week-lowercase": "vs 先週",
"wants-to-access-your-account": "wants to access your {{username}} account",
"warning": "Warning",
"warning-plural": "Warnings",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "데이터 비율들",
"data-quality": "데이터 품질",
"data-quality-test": "데이터 품질 테스트",
"data-quality-test-plural": "데이터 품질 테스트",
"data-quartile-plural": "데이터 사분위수들",
"data-range": "데이터 범위",
"data-type": "데이터 유형",
@ -1337,6 +1338,7 @@
"thursday": "목요일",
"tier": "티어",
"tier-number": "티어{{tier}}",
"tier-plural": "계층",
"tier-plural-lowercase": "티어들",
"time": "시간",
"timeout": "타임아웃",
@ -1437,7 +1439,7 @@
"view-plural": "보기들",
"visit-developer-website": "개발자 웹사이트 방문",
"volume-change": "볼륨 변화",
"vs-last-month": "지난 달과 비교",
"vs-last-week-lowercase": "vs 지난주",
"wants-to-access-your-account": "{{username}} 계정 접근을 원함",
"warning": "경고",
"warning-plural": "경고들",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "डेटा प्रमाण",
"data-quality": "डेटा गुणवत्ता",
"data-quality-test": "डेटा गुणवत्ता चाचणी",
"data-quality-test-plural": "डेटा गुणवत्ता परीक्षा",
"data-quartile-plural": "डेटा चतुर्थांश",
"data-range": "डेटा श्रेणी",
"data-type": "डेटा प्रकार",
@ -1337,6 +1338,7 @@
"thursday": "गुरुवार",
"tier": "स्तर",
"tier-number": "स्तर{{tier}}",
"tier-plural": "टियर्स",
"tier-plural-lowercase": "स्तर",
"time": "वेळ",
"timeout": "टाइमआउट",
@ -1437,7 +1439,7 @@
"view-plural": "दृश्ये",
"visit-developer-website": "विकसक वेबसाइटला भेट द्या",
"volume-change": "खंड बदल",
"vs-last-month": "गेल्या महिन्याच्या विरुद्ध",
"vs-last-week-lowercase": "मागील आठवड्याच्या तुलनेत",
"wants-to-access-your-account": "तुमच्या {{username}} खात्यात प्रवेश करू इच्छित आहे",
"warning": "इशारा",
"warning-plural": "चेतावण्या",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Dataproporties",
"data-quality": "Datakwaliteit",
"data-quality-test": "Datakwaliteitstest",
"data-quality-test-plural": "Data Qualiteits Tests",
"data-quartile-plural": "Datakwartielen",
"data-range": "Datasbereik",
"data-type": "Datatype",
@ -1337,6 +1338,7 @@
"thursday": "donderdag",
"tier": "Niveau",
"tier-number": "Niveau {{tier}}",
"tier-plural": "Lagen",
"tier-plural-lowercase": "niveaus",
"time": "Tijd",
"timeout": "Time-out",
@ -1437,7 +1439,7 @@
"view-plural": "Views",
"visit-developer-website": "Bezoek ontwikkelaarswebsite",
"volume-change": "Volumeverandering",
"vs-last-month": "vs vorige maand",
"vs-last-week-lowercase": "vs vorige week",
"wants-to-access-your-account": "wil toegang tot je {{username}} account",
"warning": "Waarschuwing",
"warning-plural": "Waarschuwingen",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "نسبت‌های داده",
"data-quality": "کیفیت داده",
"data-quality-test": "آزمون کیفیت داده",
"data-quality-test-plural": "Pruebas de Calidad de Datos",
"data-quartile-plural": "چهارک‌های داده",
"data-range": "محدوده داده",
"data-type": "نوع داده",
@ -1337,6 +1338,7 @@
"thursday": "پنج‌شنبه",
"tier": "سطح",
"tier-number": "سطح {{tier}}",
"tier-plural": "طبقات",
"tier-plural-lowercase": "سطوح",
"time": "زمان",
"timeout": "زمان‌بر",
@ -1437,7 +1439,7 @@
"view-plural": "مشاهدات",
"visit-developer-website": "بازدید از وب‌سایت توسعه‌دهنده",
"volume-change": "تغییر حجم",
"vs-last-month": "در مقایسه با ماه گذشته",
"vs-last-week-lowercase": "در مقابل هفته گذشته",
"wants-to-access-your-account": "می‌خواهد به حساب {{username}} شما دسترسی پیدا کند",
"warning": "هشدار",
"warning-plural": "هشدارها",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Proporções de Dados",
"data-quality": "Qualidade de Dados",
"data-quality-test": "Teste de Qualidade de Dados",
"data-quality-test-plural": "Testes de Qualidade de Dados",
"data-quartile-plural": "Quartis de Dados",
"data-range": "Intervalo de Dados",
"data-type": "Tipo de Dados",
@ -1337,6 +1338,7 @@
"thursday": "Quinta-feira",
"tier": "Camada",
"tier-number": "Camada{{tier}}",
"tier-plural": "Camadas",
"tier-plural-lowercase": "camadas",
"time": "Tempo",
"timeout": "Tempo Limite",
@ -1437,7 +1439,7 @@
"view-plural": "Visualizações",
"visit-developer-website": "Visitar site do desenvolvedor",
"volume-change": "Mudança de Volume",
"vs-last-month": "vs mês anterior",
"vs-last-week-lowercase": "vs última semana",
"wants-to-access-your-account": "quer acessar sua conta {{username}}",
"warning": "Aviso",
"warning-plural": "Avisos",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Proporções de Dados",
"data-quality": "Qualidade de Dados",
"data-quality-test": "Teste de Qualidade de Dados",
"data-quality-test-plural": "Testes de Qualidade de Dados",
"data-quartile-plural": "Quartis de Dados",
"data-range": "Intervalo de Dados",
"data-type": "Tipo de Dados",
@ -1337,6 +1338,7 @@
"thursday": "Quinta-feira",
"tier": "Camada",
"tier-number": "Camada{{tier}}",
"tier-plural": "Camadas",
"tier-plural-lowercase": "camadas",
"time": "Tempo",
"timeout": "Tempo Limite",
@ -1437,7 +1439,7 @@
"view-plural": "Visualizações",
"visit-developer-website": "Visitar site do programador",
"volume-change": "Mudança de Volume",
"vs-last-month": "vs mês anterior",
"vs-last-week-lowercase": "vs última semana",
"wants-to-access-your-account": "quer acessar sua conta {{username}}",
"warning": "Aviso",
"warning-plural": "Avisos",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "Распределение данных",
"data-quality": "Качество данных",
"data-quality-test": "Тест качества данных",
"data-quality-test-plural": "Тесты качества данных",
"data-quartile-plural": "Качество данных",
"data-range": "Временной интервал",
"data-type": "Тип данных",
@ -1337,6 +1338,7 @@
"thursday": "Четверг",
"tier": "Уровень",
"tier-number": "Уровень{{tier}}",
"tier-plural": "Уровни",
"tier-plural-lowercase": "уровни",
"time": "Время",
"timeout": "Тайм-аут",
@ -1437,7 +1439,7 @@
"view-plural": "Просмотры",
"visit-developer-website": "Visit developer website",
"volume-change": "Объем изменений",
"vs-last-month": "против прошлого месяца",
"vs-last-week-lowercase": "против прошлой недели",
"wants-to-access-your-account": "wants to access your {{username}} account",
"warning": "Предупреждение",
"warning-plural": "Warnings",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "สัดส่วนข้อมูล",
"data-quality": "คุณภาพข้อมูล",
"data-quality-test": "การทดสอบคุณภาพข้อมูล",
"data-quality-test-plural": "การทดสอบคุณภาพของข้อมูล",
"data-quartile-plural": "ควอไทล์ข้อมูล",
"data-range": "ช่วงข้อมูล",
"data-type": "ประเภทข้อมูล",
@ -1337,6 +1338,7 @@
"thursday": "วันพฤหัสบดี",
"tier": "ระดับ",
"tier-number": "ระดับ {{tier}}",
"tier-plural": "ชั้น",
"tier-plural-lowercase": "ระดับหลายรายการ",
"time": "เวลา",
"timeout": "หมดเวลา",
@ -1437,7 +1439,7 @@
"view-plural": "การเข้าชม",
"visit-developer-website": "เยี่ยมชมเว็บไซต์นักพัฒนา",
"volume-change": "การเปลี่ยนแปลงปริมาณ",
"vs-last-month": "เทียบกับเดือนที่แล้ว",
"vs-last-week-lowercase": "เทียบกับสัปดาห์ที่แล้ว",
"wants-to-access-your-account": "ต้องการเข้าถึงบัญชี {{username}} ของคุณ",
"warning": "คำเตือน",
"warning-plural": "คำเตือนหลายรายการ",

View File

@ -327,6 +327,7 @@
"data-proportion-plural": "数据比例",
"data-quality": "数据质控",
"data-quality-test": "数据质控测试",
"data-quality-test-plural": "数据质量测试",
"data-quartile-plural": "数据四分位数",
"data-range": "数据范围",
"data-type": "数据类型",
@ -1337,6 +1338,7 @@
"thursday": "星期四",
"tier": "分级",
"tier-number": "{{tier}}级",
"tier-plural": "层",
"tier-plural-lowercase": "分级",
"time": "时间",
"timeout": "超时",
@ -1437,7 +1439,7 @@
"view-plural": "查看",
"visit-developer-website": "Visit developer website",
"volume-change": "数据量变化",
"vs-last-month": "与上个月相比",
"vs-last-week-lowercase": "与上周相比",
"wants-to-access-your-account": "希望访问您的 {{username}} 账号",
"warning": "警告",
"warning-plural": "警告",

View File

@ -239,7 +239,7 @@ const ServiceDetailsPage: FunctionComponent = () => {
return EntityTabs.AGENTS;
}
return getCountLabel(serviceCategory).toLowerCase();
return EntityTabs.INSIGHTS;
}, [tab, serviceCategory, isMetadataService]);
const handleSearchChange = useCallback(

View File

@ -17,7 +17,13 @@ import { ChartAggregateParam } from '../interface/data-insight.interface';
import APIClient from './index';
export interface DataInsightCustomChartResult {
results: Array<{ count: number; day: number; group: string }>;
results: Array<{
count: number;
day: number;
group: string;
term: string;
metric?: string;
}>;
}
export const getAggregateChartData = async (params: ChartAggregateParam) => {

View File

@ -14,7 +14,7 @@ import { AxiosResponse } from 'axios';
import { Operation } from 'fast-json-patch';
import { PagingResponse, RestoreRequestType } from 'Models';
import { DataInsightLatestRun } from '../components/Settings/Applications/AppDetails/AppDetails.interface';
import { App } from '../generated/entity/applications/app';
import { AgentType, App } from '../generated/entity/applications/app';
import { AppRunRecord } from '../generated/entity/applications/appRunRecord';
import { CreateAppRequest } from '../generated/entity/applications/createAppRequest';
import { PipelineStatus } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
@ -25,12 +25,13 @@ import APIClient from './index';
const BASE_URL = '/apps';
type AppListParams = ListParams & {
agentType?: AgentType;
offset?: number;
startTs?: number;
endTs?: number;
};
export const getApplicationList = async (params?: ListParams) => {
export const getApplicationList = async (params?: AppListParams) => {
const response = await APIClient.get<PagingResponse<App[]>>(BASE_URL, {
params,
});

View File

@ -662,6 +662,10 @@ export const getServiceDetailsPath = (
path = path.replace(PLACEHOLDER_ROUTE_TAB, tab);
}
if (subTab) {
path = path.replace(PLACEHOLDER_ROUTE_SUB_TAB, subTab);
}
return path;
};

View File

@ -10,9 +10,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { first, round, sortBy } from 'lodash';
import { ServiceTypes } from 'Models';
import { SystemChartType } from '../enums/DataInsight.enum';
import { EntityType } from '../enums/entity.enum';
import { DataInsightCustomChartResult } from '../rest/DataInsightAPI';
import i18n from '../utils/i18next/LocalUtil';
const { t } = i18n;
@ -71,3 +73,45 @@ export const getTitleByChartType = (chartType: SystemChartType) => {
return '';
}
};
export const getPlatformInsightsChartDataFormattingMethod =
(
chartsData: Record<SystemChartType, DataInsightCustomChartResult>,
startTime: number,
endTime: number
) =>
(chartType: SystemChartType) => {
const summaryChartData = chartsData[chartType];
const data = sortBy(summaryChartData.results, 'day');
// This is the data for the day 7 days ago
const sevenDaysAgoData = data.find((item) => item.day === startTime)?.count;
// This is the data for the current day
const currentData = data.find((item) => item.day === endTime)?.count;
// This is the data for the earliest day
// separating this out because sometimes the data is not available for all the days
const earliestDayData = first(data)?.count;
// This is the percentage change for the last 7 days
// This is undefined if the data is not available for all the days
const percentageChangeInSevenDays =
currentData && sevenDaysAgoData
? round(Math.abs(currentData - sevenDaysAgoData), 2)
: undefined;
// This is true if the current data is greater than the earliest day data
// This is false if the data is not available for more than 1 day
const isIncreased =
currentData && data.length > 1
? currentData > (earliestDayData ?? 0)
: false;
return {
chartType,
data,
isIncreased,
percentageChange: percentageChangeInSevenDays,
currentPercentage: round(currentData ?? 0, 2),
};
};

View File

@ -118,7 +118,6 @@ import {
MlModelServiceTypeSmallCaseType,
PipelineServiceTypeSmallCaseType,
SearchServiceTypeSmallCaseType,
ServiceAgentSubTabs,
StorageServiceTypeSmallCaseType,
} from '../enums/service.enum';
import { StorageServiceType } from '../generated/entity/data/container';
@ -743,10 +742,6 @@ class ServiceUtilClassBase {
return widgets;
}
public getServiceAgentSupportedSubTabs() {
return [ServiceAgentSubTabs.COLLATE_AI, ServiceAgentSubTabs.METADATA];
}
/**
* @param originalEnum will take the enum that should be converted
* @returns object with lowercase value

View File

@ -300,3 +300,9 @@ export const getStartOfDayInMillis = (timestamp: number) =>
export const getEndOfDayInMillis = (timestamp: number) =>
DateTime.fromMillis(timestamp).toUTC().endOf('day').toMillis();
export const getCurrentDayStartGMTinMillis = () =>
DateTime.now().setZone('GMT').startOf('day').toMillis();
export const getDayAgoStartGMTinMillis = (days: number) =>
DateTime.now().setZone('GMT').minus({ days }).startOf('day').toMillis();