mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-12 11:39:39 +00:00
UI : Data Insight KPI improvements (#9188)
* UI : Data Insight KPI improvements * Remove commented code * Remove time from start and end date * refactor : add logic to generate kpi name * Make insight to insights * Show chart at the top * Fix: breadcrumb spacing * refactor : start date and end date of kpi * test: add unit test for kpi list * test : add unit tests for add and edit kpi forms * chore : minor change * Address review comments * Address review comments
This commit is contained in:
parent
6f12c971e1
commit
fce151c0d4
@ -181,7 +181,7 @@ export const SUPPORTED_CHARTS_FOR_KPI = [
|
||||
DataInsightChartType.PercentageOfEntitiesWithOwnerByType,
|
||||
];
|
||||
|
||||
export const KPI_DATE_PICKER_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
||||
export const KPI_DATE_PICKER_FORMAT = 'YYYY-MM-DD';
|
||||
|
||||
export const KPI_DATES = {
|
||||
startDate: '',
|
||||
|
@ -383,6 +383,7 @@
|
||||
"hide": "Hide",
|
||||
"restore-team": "Restore Team",
|
||||
"remove": "Remove",
|
||||
"data-insight-plural": "Data Insights",
|
||||
"configure-entity": "Configure {{entity}}",
|
||||
"name-lowercase": "name",
|
||||
"field-invalid": "{{field}} is invalid",
|
||||
|
@ -178,7 +178,9 @@ const DataInsightPage = () => {
|
||||
<Col span={24}>
|
||||
<Space className="w-full justify-between">
|
||||
<div data-testid="data-insight-header">
|
||||
<Typography.Title level={5}>Data Insight</Typography.Title>
|
||||
<Typography.Title level={5}>
|
||||
{t('label.data-insight-plural')}
|
||||
</Typography.Title>
|
||||
<Typography.Text className="data-insight-label-text">
|
||||
{t('label.data-insight-subtitle')}
|
||||
</Typography.Text>
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { act } from 'react-test-renderer';
|
||||
import KPIList from './KPIList';
|
||||
import { KPI_DATA } from './mocks/KPIList';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useHistory: jest.fn().mockImplementation(() => ({
|
||||
push: mockPush,
|
||||
})),
|
||||
Link: jest
|
||||
.fn()
|
||||
.mockImplementation(({ children }: { children: React.ReactNode }) => (
|
||||
<span>{children}</span>
|
||||
)),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/common/DeleteWidget/DeleteWidgetModal', () =>
|
||||
jest.fn().mockReturnValue(<div data-testid="delete-modal">Delete Modal</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../components/common/next-previous/NextPrevious', () =>
|
||||
jest
|
||||
.fn()
|
||||
.mockReturnValue(<div data-testid="next-previous">Next Previous</div>)
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'../../components/common/rich-text-editor/RichTextEditorPreviewer',
|
||||
() => jest.fn().mockReturnValue(<div data-testid="editor">Editor</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../components/Loader/Loader', () =>
|
||||
jest.fn().mockReturnValue(<div data-testid="loader">Loader</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../hooks/authHooks', () => ({
|
||||
useAuth: jest.fn().mockReturnValue({ isAdminUser: true }),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/TimeUtils', () => ({
|
||||
formatDateTime: jest.fn().mockReturnValue('7 Dec 2022, 00:00'),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/KpiAPI', () => ({
|
||||
getListKPIs: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ data: KPI_DATA })),
|
||||
}));
|
||||
|
||||
describe('KPI list component', () => {
|
||||
it('Should render the kpi list', async () => {
|
||||
render(<KPIList />, { wrapper: MemoryRouter });
|
||||
|
||||
const container = await screen.findByTestId('kpi-table');
|
||||
const descriptionKPI = await screen.findByText('Description KPI');
|
||||
const ownerKPI = await screen.findByText('Owner KPI');
|
||||
|
||||
expect(container).toBeInTheDocument();
|
||||
|
||||
expect(descriptionKPI).toBeInTheDocument();
|
||||
expect(ownerKPI).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Action button should work', async () => {
|
||||
const KPI = KPI_DATA[0];
|
||||
|
||||
render(<KPIList />, { wrapper: MemoryRouter });
|
||||
|
||||
const editButton = await screen.findByTestId(
|
||||
`edit-action-${KPI.displayName}`
|
||||
);
|
||||
const deleteButton = await screen.findByTestId(
|
||||
`delete-action-${KPI.displayName}`
|
||||
);
|
||||
|
||||
expect(editButton).toBeInTheDocument();
|
||||
expect(deleteButton).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(editButton);
|
||||
});
|
||||
|
||||
expect(mockPush).toBeCalled();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(deleteButton);
|
||||
});
|
||||
|
||||
expect(await screen.findByTestId('delete-modal')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -11,12 +11,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Table, Tooltip, Typography } from 'antd';
|
||||
import { Button, Col, Space, Table, Tooltip, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { isUndefined } from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import { getListKPIs } from '../../axiosAPIs/KpiAPI';
|
||||
import DeleteWidgetModal from '../../components/common/DeleteWidget/DeleteWidgetModal';
|
||||
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
||||
@ -28,7 +28,6 @@ import {
|
||||
PAGE_SIZE_MEDIUM,
|
||||
pagingObject,
|
||||
} from '../../constants/constants';
|
||||
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import { Kpi, KpiTargetType } from '../../generated/dataInsight/kpi/kpi';
|
||||
|
||||
@ -39,6 +38,7 @@ import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import { formatDateTime } from '../../utils/TimeUtils';
|
||||
|
||||
const KPIList = () => {
|
||||
const history = useHistory();
|
||||
const { isAdminUser } = useAuth();
|
||||
const { t } = useTranslation();
|
||||
const [kpiList, setKpiList] = useState<Array<Kpi>>([]);
|
||||
@ -122,10 +122,34 @@ const KPIList = () => {
|
||||
key: 'actions',
|
||||
render: (_, record) => {
|
||||
return (
|
||||
<Space>
|
||||
<Tooltip
|
||||
placement="left"
|
||||
title={
|
||||
isAdminUser ? t('label.delete') : NO_PERMISSION_FOR_ACTION
|
||||
isAdminUser
|
||||
? t('label.edit')
|
||||
: t('message.no-permission-for-action')
|
||||
}>
|
||||
<Button
|
||||
data-testid={`edit-action-${getEntityName(record)}`}
|
||||
disabled={!isAdminUser}
|
||||
icon={
|
||||
<SVGIcons
|
||||
alt={t('label.edit')}
|
||||
icon={Icons.EDIT}
|
||||
width="18px"
|
||||
/>
|
||||
}
|
||||
type="text"
|
||||
onClick={() => history.push(getKpiPath(record.name))}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
placement="left"
|
||||
title={
|
||||
isAdminUser
|
||||
? t('label.delete')
|
||||
: t('message.no-permission-for-action')
|
||||
}>
|
||||
<Button
|
||||
data-testid={`delete-action-${getEntityName(record)}`}
|
||||
@ -137,6 +161,7 @@ const KPIList = () => {
|
||||
onClick={() => setSelectedKpi(record)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
@ -165,6 +190,7 @@ const KPIList = () => {
|
||||
<Table
|
||||
bordered
|
||||
columns={columns}
|
||||
data-testid="kpi-table"
|
||||
dataSource={kpiList}
|
||||
loading={{ spinning: isLoading, indicator: <Loader /> }}
|
||||
pagination={false}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const KPI_DATA = [
|
||||
{
|
||||
id: 'dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
name: 'description-kpi',
|
||||
displayName: 'Description KPI',
|
||||
fullyQualifiedName: 'description-kpi',
|
||||
description: '',
|
||||
metricType: 'PERCENTAGE',
|
||||
targetDefinition: [
|
||||
{
|
||||
name: 'completedDescriptionFraction',
|
||||
value: '0.65',
|
||||
},
|
||||
],
|
||||
startDate: 1670351400000,
|
||||
endDate: 1672165800000,
|
||||
version: 0.2,
|
||||
updatedAt: 1670414685805,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/kpi/dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
changeDescription: {
|
||||
fieldsAdded: [],
|
||||
fieldsUpdated: [
|
||||
{
|
||||
name: 'startDate',
|
||||
oldValue: 1670395661000,
|
||||
newValue: 1670351400000,
|
||||
},
|
||||
{
|
||||
name: 'endDate',
|
||||
oldValue: 1672210072000,
|
||||
newValue: 1672165800000,
|
||||
},
|
||||
],
|
||||
fieldsDeleted: [],
|
||||
previousVersion: 0.1,
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: 'bb71e000-f837-4e3c-8e03-0a0f1fd35667',
|
||||
name: 'owner-kpi-has-owner-fraction',
|
||||
displayName: 'Owner KPI',
|
||||
fullyQualifiedName: 'owner-kpi-has-owner-fraction',
|
||||
description: '',
|
||||
metricType: 'PERCENTAGE',
|
||||
targetDefinition: [
|
||||
{
|
||||
name: 'hasOwnerFraction',
|
||||
value: '0.64',
|
||||
},
|
||||
],
|
||||
startDate: 1670351400000,
|
||||
endDate: 1672511340000,
|
||||
version: 0.2,
|
||||
updatedAt: 1670415195507,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/kpi/bb71e000-f837-4e3c-8e03-0a0f1fd35667',
|
||||
changeDescription: {
|
||||
fieldsAdded: [],
|
||||
fieldsUpdated: [
|
||||
{
|
||||
name: 'endDate',
|
||||
oldValue: 1672252140000,
|
||||
newValue: 1672511340000,
|
||||
},
|
||||
],
|
||||
fieldsDeleted: [],
|
||||
previousVersion: 0.1,
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
];
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
act,
|
||||
findByRole,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitForElement,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import AddKPIPage from './AddKPIPage';
|
||||
|
||||
import { KPI_CHARTS, KPI_DATA, KPI_LIST } from './KPIMock.mock';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useHistory: jest.fn().mockReturnValue({
|
||||
push: mockPush,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/DataInsightAPI', () => ({
|
||||
getListDataInsightCharts: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ data: KPI_CHARTS })),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/common/rich-text-editor/RichTextEditor', () =>
|
||||
jest.fn().mockReturnValue(<div data-testid="editor">Editor</div>)
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'../../components/common/title-breadcrumb/title-breadcrumb.component',
|
||||
() =>
|
||||
jest.fn().mockReturnValue(<div data-testid="breadcrumb">BreadCrumb</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../axiosAPIs/KpiAPI', () => ({
|
||||
getListKPIs: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({ data: KPI_LIST })),
|
||||
postKPI: jest.fn().mockImplementation(() => Promise.resolve(KPI_DATA)),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/CommonUtils', () => ({
|
||||
isUrlFriendlyName: jest.fn().mockReturnValue(true),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/DataInsightUtils', () => ({
|
||||
getKpiTargetValueByMetricType: jest.fn().mockReturnValue(10),
|
||||
getKPIFormattedDates: jest.fn().mockReturnValue({
|
||||
startDate: `2022-12-08 00:00`,
|
||||
endDate: `2022-12-28 23:59`,
|
||||
}),
|
||||
getDisabledDates: jest.fn().mockReturnValue(true),
|
||||
}));
|
||||
|
||||
describe('Add KPI page', () => {
|
||||
it('Should render all the components', async () => {
|
||||
render(<AddKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const container = await screen.findByTestId('add-kpi-container');
|
||||
const breadCrumb = await screen.findByTestId('breadcrumb');
|
||||
const formTitle = await screen.findByTestId('form-title');
|
||||
const rightPanel = await screen.findByTestId('right-panel');
|
||||
|
||||
expect(container).toBeInTheDocument();
|
||||
|
||||
expect(breadCrumb).toBeInTheDocument();
|
||||
|
||||
expect(formTitle).toBeInTheDocument();
|
||||
|
||||
expect(formTitle.textContent).toContain('label.add-new-kpi');
|
||||
|
||||
const formContainer = await screen.findByTestId('kpi-form');
|
||||
|
||||
expect(formContainer).toBeInTheDocument();
|
||||
|
||||
expect(rightPanel).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render all the form fields', async () => {
|
||||
render(<AddKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const formContainer = await screen.findByTestId('kpi-form');
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
const displayName = await screen.findByTestId('displayName');
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
const startDate = await screen.findByTestId('start-date');
|
||||
const endDate = await screen.findByTestId('end-date');
|
||||
const editor = await screen.findByTestId('editor');
|
||||
const cancelButton = await screen.findByTestId('cancel-btn');
|
||||
const submitButton = await screen.findByTestId('submit-btn');
|
||||
|
||||
expect(formContainer).toBeInTheDocument();
|
||||
expect(chart).toBeInTheDocument();
|
||||
expect(displayName).toBeInTheDocument();
|
||||
expect(metricType).toBeInTheDocument();
|
||||
expect(startDate).toBeInTheDocument();
|
||||
expect(endDate).toBeInTheDocument();
|
||||
expect(editor).toBeInTheDocument();
|
||||
expect(cancelButton).toBeInTheDocument();
|
||||
expect(submitButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Metric type input should be disable if chart is not selected', async () => {
|
||||
render(<AddKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
|
||||
expect(chart).toBeInTheDocument();
|
||||
|
||||
expect(metricType).toHaveClass('ant-select-disabled');
|
||||
});
|
||||
|
||||
it('Metric type input should not be disable if chart is selected', async () => {
|
||||
render(<AddKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
|
||||
const chartInput = await findByRole(chart, 'combobox');
|
||||
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
|
||||
act(() => {
|
||||
userEvent.click(chartInput);
|
||||
});
|
||||
|
||||
await waitForElement(() =>
|
||||
screen.getByText('Percentage of Entities With Owner')
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByText('Percentage of Entities With Owner'));
|
||||
});
|
||||
|
||||
expect(chart).toBeInTheDocument();
|
||||
expect(metricType).not.toHaveClass('ant-select-disabled');
|
||||
});
|
||||
|
||||
it('Should render the proper metric input based on metric type', async () => {
|
||||
render(<AddKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
|
||||
const chartInput = await findByRole(chart, 'combobox');
|
||||
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
|
||||
const metricInput = await findByRole(metricType, 'combobox');
|
||||
|
||||
act(() => {
|
||||
userEvent.click(chartInput);
|
||||
});
|
||||
|
||||
await waitForElement(() =>
|
||||
screen.getByText('Percentage of Entities With Owner')
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByText('Percentage of Entities With Owner'));
|
||||
});
|
||||
|
||||
act(() => {
|
||||
userEvent.click(metricInput);
|
||||
});
|
||||
|
||||
// check for percentage type
|
||||
await waitForElement(() =>
|
||||
screen.getByText('hasOwnerFraction (PERCENTAGE)')
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByText('hasOwnerFraction (PERCENTAGE)'));
|
||||
});
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('metric-percentage-input')
|
||||
).toBeInTheDocument();
|
||||
|
||||
// check for number type
|
||||
await waitForElement(() => screen.getByText('hasOwner (NUMBER)'));
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByText('hasOwner (NUMBER)'));
|
||||
});
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('metric-number-input')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -27,7 +27,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { isUndefined, kebabCase } from 'lodash';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
@ -46,7 +46,6 @@ import {
|
||||
VALIDATE_MESSAGES,
|
||||
} from '../../constants/DataInsight.constants';
|
||||
import { ADD_KPI_TEXT } from '../../constants/HelperTextUtil';
|
||||
import { nameWithSpace } from '../../constants/regex.constants';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import {
|
||||
CreateKpiRequest,
|
||||
@ -60,9 +59,9 @@ import {
|
||||
import { DataInsightChartType } from '../../generated/dataInsight/dataInsightChartResult';
|
||||
import { Kpi } from '../../generated/dataInsight/kpi/kpi';
|
||||
import { KpiDate, KpiDates } from '../../interface/data-insight.interface';
|
||||
import { isUrlFriendlyName } from '../../utils/CommonUtils';
|
||||
import {
|
||||
getDisabledDates,
|
||||
getKPIFormattedDates,
|
||||
getKpiTargetValueByMetricType,
|
||||
} from '../../utils/DataInsightUtils';
|
||||
import { getTimeStampByDateTime } from '../../utils/TimeUtils';
|
||||
@ -164,8 +163,10 @@ const AddKPIPage = () => {
|
||||
};
|
||||
|
||||
const handleSubmit: FormProps['onFinish'] = async (values) => {
|
||||
const startDate = getTimeStampByDateTime(kpiDates.startDate);
|
||||
const endDate = getTimeStampByDateTime(kpiDates.endDate);
|
||||
const formattedDates = getKPIFormattedDates(kpiDates);
|
||||
|
||||
const startDate = getTimeStampByDateTime(formattedDates.startDate);
|
||||
const endDate = getTimeStampByDateTime(formattedDates.endDate);
|
||||
const metricType =
|
||||
selectedMetric?.chartDataType as unknown as KpiTargetType;
|
||||
|
||||
@ -177,7 +178,7 @@ const AddKPIPage = () => {
|
||||
type: EntityType.DATA_INSIGHT_CHART,
|
||||
},
|
||||
description,
|
||||
name: values.name,
|
||||
name: kebabCase(`${values.displayName} ${selectedMetric?.name}`),
|
||||
displayName: values.displayName,
|
||||
startDate,
|
||||
endDate,
|
||||
@ -211,8 +212,8 @@ const AddKPIPage = () => {
|
||||
data-testid="add-kpi-container"
|
||||
gutter={[16, 16]}>
|
||||
<Col offset={4} span={12}>
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
<Card className="mt-4">
|
||||
<TitleBreadcrumb className="my-4" titleLinks={breadcrumb} />
|
||||
<Card>
|
||||
<Typography.Paragraph className="text-base" data-testid="form-title">
|
||||
{t('label.add-new-kpi')}
|
||||
</Typography.Paragraph>
|
||||
@ -222,43 +223,6 @@ const AddKPIPage = () => {
|
||||
layout="vertical"
|
||||
validateMessages={VALIDATE_MESSAGES}
|
||||
onFinish={handleSubmit}>
|
||||
<Form.Item
|
||||
label={t('label.name')}
|
||||
name="name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
max: 128,
|
||||
min: 1,
|
||||
validator: (_, value) => {
|
||||
if (
|
||||
!isUrlFriendlyName(value) ||
|
||||
nameWithSpace.test(value)
|
||||
) {
|
||||
return Promise.reject(
|
||||
t('label.special-character-not-allowed')
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}>
|
||||
<Input
|
||||
data-testid="name"
|
||||
placeholder={t('label.kpi-name')}
|
||||
type="text"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('label.display-name')} name="displayName">
|
||||
<Input
|
||||
data-testid="displayName"
|
||||
placeholder={t('label.kpi-display-name')}
|
||||
type="text"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.select-a-chart')}
|
||||
name="dataInsightChart"
|
||||
@ -282,6 +246,14 @@ const AddKPIPage = () => {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('label.display-name')} name="displayName">
|
||||
<Input
|
||||
data-testid="displayName"
|
||||
placeholder={t('label.kpi-display-name')}
|
||||
type="text"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.select-a-metric-type')}
|
||||
name="metricType"
|
||||
@ -324,7 +296,7 @@ const AddKPIPage = () => {
|
||||
<>
|
||||
{selectedMetric.chartDataType ===
|
||||
ChartDataType.Percentage && (
|
||||
<Row gutter={20}>
|
||||
<Row data-testid="metric-percentage-input" gutter={20}>
|
||||
<Col span={20}>
|
||||
<Slider
|
||||
className="kpi-slider"
|
||||
@ -359,6 +331,7 @@ const AddKPIPage = () => {
|
||||
{selectedMetric.chartDataType === ChartDataType.Number && (
|
||||
<InputNumber
|
||||
className="w-full"
|
||||
data-testid="metric-number-input"
|
||||
min={0}
|
||||
value={metricValue}
|
||||
onChange={(value) => setMetricValue(Number(value))}
|
||||
@ -377,11 +350,14 @@ const AddKPIPage = () => {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('label.field-required', {
|
||||
field: t('label.start-date'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<DatePicker
|
||||
showTime
|
||||
className="w-full"
|
||||
data-testid="start-date"
|
||||
disabledDate={getDisabledDates}
|
||||
format={KPI_DATE_PICKER_FORMAT}
|
||||
onChange={(_, dateString) =>
|
||||
@ -398,11 +374,14 @@ const AddKPIPage = () => {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('label.field-required', {
|
||||
field: t('label.end-date'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<DatePicker
|
||||
showTime
|
||||
className="w-full"
|
||||
data-testid="end-date"
|
||||
disabledDate={getDisabledDates}
|
||||
format={KPI_DATE_PICKER_FORMAT}
|
||||
onChange={(_, dateString) =>
|
||||
@ -442,7 +421,7 @@ const AddKPIPage = () => {
|
||||
</Form>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col className="m-t-md" span={4}>
|
||||
<Col className="m-t-md" data-testid="right-panel" span={4}>
|
||||
<Typography.Paragraph className="text-base font-medium">
|
||||
{t('label.add-kpi')}
|
||||
</Typography.Paragraph>
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import EditKPIPage from './EditKPIPage';
|
||||
|
||||
import { DESCRIPTION_CHART, KPI_DATA } from './KPIMock.mock';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useHistory: jest.fn().mockReturnValue({
|
||||
push: mockPush,
|
||||
}),
|
||||
useParams: jest.fn().mockReturnValue({ useParams: 'description-kpi' }),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/DataInsightAPI', () => ({
|
||||
getChartById: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(DESCRIPTION_CHART)),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/common/rich-text-editor/RichTextEditor', () =>
|
||||
jest.fn().mockReturnValue(<div data-testid="editor">Editor</div>)
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'../../components/common/title-breadcrumb/title-breadcrumb.component',
|
||||
() =>
|
||||
jest.fn().mockReturnValue(<div data-testid="breadcrumb">BreadCrumb</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../components/Loader/Loader', () =>
|
||||
jest.fn().mockReturnValue(<div data-testid="loader">Loader</div>)
|
||||
);
|
||||
|
||||
jest.mock('../../axiosAPIs/KpiAPI', () => ({
|
||||
getKPIByName: jest.fn().mockImplementation(() => Promise.resolve(KPI_DATA)),
|
||||
patchKPI: jest.fn().mockImplementation(() => Promise.resolve(KPI_DATA)),
|
||||
}));
|
||||
|
||||
jest.mock('../../hooks/authHooks', () => ({
|
||||
useAuth: jest.fn().mockReturnValue({ isAdminUser: true }),
|
||||
}));
|
||||
|
||||
jest.mock('../../utils/DataInsightUtils', () => ({
|
||||
getKpiTargetValueByMetricType: jest.fn().mockReturnValue(10),
|
||||
getKPIFormattedDates: jest.fn().mockReturnValue({
|
||||
startDate: `2022-12-08 00:00`,
|
||||
endDate: `2022-12-28 23:59`,
|
||||
}),
|
||||
getDisabledDates: jest.fn().mockReturnValue(true),
|
||||
getKpiDateFormatByTimeStamp: jest.fn().mockReturnValue('2022-12-08'),
|
||||
}));
|
||||
|
||||
describe('Edit KPI page', () => {
|
||||
it('Should render all the components', async () => {
|
||||
render(<EditKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const container = await screen.findByTestId('edit-kpi-container');
|
||||
const breadCrumb = await screen.findByTestId('breadcrumb');
|
||||
const formTitle = await screen.findByTestId('form-title');
|
||||
const rightPanel = await screen.findByTestId('right-panel');
|
||||
|
||||
expect(container).toBeInTheDocument();
|
||||
|
||||
expect(breadCrumb).toBeInTheDocument();
|
||||
|
||||
expect(formTitle).toBeInTheDocument();
|
||||
|
||||
expect(formTitle.textContent).toContain('label.edit-entity');
|
||||
|
||||
const formContainer = await screen.findByTestId('kpi-form');
|
||||
|
||||
expect(formContainer).toBeInTheDocument();
|
||||
|
||||
expect(rightPanel).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render all the form fields', async () => {
|
||||
render(<EditKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const formContainer = await screen.findByTestId('kpi-form');
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
const displayName = await screen.findByTestId('displayName');
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
const startDate = await screen.findByTestId('start-date');
|
||||
const endDate = await screen.findByTestId('end-date');
|
||||
const editor = await screen.findByTestId('editor');
|
||||
const cancelButton = await screen.findByTestId('cancel-btn');
|
||||
const submitButton = await screen.findByTestId('submit-btn');
|
||||
|
||||
expect(formContainer).toBeInTheDocument();
|
||||
expect(chart).toBeInTheDocument();
|
||||
expect(displayName).toBeInTheDocument();
|
||||
expect(metricType).toBeInTheDocument();
|
||||
expect(startDate).toBeInTheDocument();
|
||||
expect(endDate).toBeInTheDocument();
|
||||
expect(editor).toBeInTheDocument();
|
||||
expect(cancelButton).toBeInTheDocument();
|
||||
expect(submitButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Chart input and Metric type input should be disable for edit form', async () => {
|
||||
render(<EditKPIPage />, { wrapper: MemoryRouter });
|
||||
|
||||
const chart = await screen.findByTestId('dataInsightChart');
|
||||
|
||||
const metricType = await screen.findByTestId('metricType');
|
||||
|
||||
expect(chart).toHaveClass('ant-input-disabled');
|
||||
|
||||
expect(metricType).toHaveClass('ant-input-disabled');
|
||||
});
|
||||
});
|
@ -47,10 +47,7 @@ import {
|
||||
KPI_DATE_PICKER_FORMAT,
|
||||
VALIDATE_MESSAGES,
|
||||
} from '../../constants/DataInsight.constants';
|
||||
import {
|
||||
ADD_KPI_TEXT,
|
||||
NO_PERMISSION_FOR_ACTION,
|
||||
} from '../../constants/HelperTextUtil';
|
||||
import { ADD_KPI_TEXT } from '../../constants/HelperTextUtil';
|
||||
import { DataInsightChart } from '../../generated/dataInsight/dataInsightChart';
|
||||
import { Kpi, KpiTargetType } from '../../generated/dataInsight/kpi/kpi';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
@ -58,12 +55,13 @@ import { KpiDate, KpiDates } from '../../interface/data-insight.interface';
|
||||
import {
|
||||
getDisabledDates,
|
||||
getKpiDateFormatByTimeStamp,
|
||||
getKPIFormattedDates,
|
||||
getKpiTargetValueByMetricType,
|
||||
} from '../../utils/DataInsightUtils';
|
||||
import { getTimeStampByDateTime } from '../../utils/TimeUtils';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
|
||||
const AddKPIPage = () => {
|
||||
const EditKPIPage = () => {
|
||||
const { isAdminUser } = useAuth();
|
||||
const { kpiName } = useParams<{ kpiName: string }>();
|
||||
|
||||
@ -164,8 +162,10 @@ const AddKPIPage = () => {
|
||||
|
||||
const handleSubmit: FormProps['onFinish'] = async (values) => {
|
||||
if (kpiData && metricData) {
|
||||
const startDate = getTimeStampByDateTime(kpiDates.startDate);
|
||||
const endDate = getTimeStampByDateTime(kpiDates.endDate);
|
||||
const formattedDates = getKPIFormattedDates(kpiDates);
|
||||
|
||||
const startDate = getTimeStampByDateTime(formattedDates.startDate);
|
||||
const endDate = getTimeStampByDateTime(formattedDates.endDate);
|
||||
|
||||
const targetValue = getKpiTargetValueByMetricType(
|
||||
kpiData.metricType,
|
||||
@ -234,15 +234,15 @@ const AddKPIPage = () => {
|
||||
{kpiData ? (
|
||||
<Row
|
||||
className="bg-body-main h-full"
|
||||
data-testid="add-kpi-container"
|
||||
data-testid="edit-kpi-container"
|
||||
gutter={[16, 16]}>
|
||||
<Col offset={4} span={12}>
|
||||
<TitleBreadcrumb titleLinks={breadcrumb} />
|
||||
<Card className="mt-4">
|
||||
<TitleBreadcrumb className="my-4" titleLinks={breadcrumb} />
|
||||
<Card>
|
||||
<Typography.Paragraph
|
||||
className="text-base"
|
||||
data-testid="form-title">
|
||||
{t('label.add-new-kpi')}
|
||||
{t('label.edit-entity', { entity: t('label.kpi-uppercase') })}
|
||||
</Typography.Paragraph>
|
||||
<Form
|
||||
data-testid="kpi-form"
|
||||
@ -251,12 +251,13 @@ const AddKPIPage = () => {
|
||||
layout="vertical"
|
||||
validateMessages={VALIDATE_MESSAGES}
|
||||
onFinish={handleSubmit}>
|
||||
<Form.Item label={t('label.name')} name="name">
|
||||
<Form.Item
|
||||
label={t('label.data-insight-chart')}
|
||||
name="dataInsightChart">
|
||||
<Input
|
||||
disabled
|
||||
data-testid="name"
|
||||
placeholder={t('label.kpi-name')}
|
||||
type="text"
|
||||
data-testid="dataInsightChart"
|
||||
value={selectedChart?.displayName || selectedChart?.name}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@ -268,19 +269,14 @@ const AddKPIPage = () => {
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('label.data-insight-chart')}
|
||||
name="dataInsightChart">
|
||||
<Form.Item label={t('label.metric-type')} name="metricType">
|
||||
<Input
|
||||
disabled
|
||||
value={selectedChart?.displayName || selectedChart?.name}
|
||||
data-testid="metricType"
|
||||
value={metricData?.name}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label={t('label.metric-type')} name="metricType">
|
||||
<Input disabled value={metricData?.name} />
|
||||
</Form.Item>
|
||||
|
||||
{!isUndefined(metricData) && (
|
||||
<Form.Item
|
||||
label={t('label.metric-value')}
|
||||
@ -301,7 +297,7 @@ const AddKPIPage = () => {
|
||||
]}>
|
||||
<>
|
||||
{kpiData?.metricType === KpiTargetType.Percentage && (
|
||||
<Row gutter={20}>
|
||||
<Row data-testid="metric-percentage-input" gutter={20}>
|
||||
<Col span={20}>
|
||||
<Slider
|
||||
className="kpi-slider"
|
||||
@ -336,6 +332,7 @@ const AddKPIPage = () => {
|
||||
{kpiData?.metricType === KpiTargetType.Number && (
|
||||
<InputNumber
|
||||
className="w-full"
|
||||
data-testid="metric-number-input"
|
||||
min={0}
|
||||
value={metricValue}
|
||||
onChange={(value) => setMetricValue(Number(value))}
|
||||
@ -354,11 +351,14 @@ const AddKPIPage = () => {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('label.field-required', {
|
||||
field: t('label.start-date'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<DatePicker
|
||||
showTime
|
||||
className="w-full"
|
||||
data-testid="start-date"
|
||||
disabledDate={getDisabledDates}
|
||||
format={KPI_DATE_PICKER_FORMAT}
|
||||
onChange={(_, dateString) =>
|
||||
@ -375,11 +375,14 @@ const AddKPIPage = () => {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('label.field-required', {
|
||||
field: t('label.end-date'),
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<DatePicker
|
||||
showTime
|
||||
className="w-full"
|
||||
data-testid="end-date"
|
||||
disabledDate={getDisabledDates}
|
||||
format={KPI_DATE_PICKER_FORMAT}
|
||||
onChange={(_, dateString) =>
|
||||
@ -409,7 +412,9 @@ const AddKPIPage = () => {
|
||||
</Button>
|
||||
<Tooltip
|
||||
title={
|
||||
isAdminUser ? t('label.save') : NO_PERMISSION_FOR_ACTION
|
||||
isAdminUser
|
||||
? t('label.save')
|
||||
: t('message.no-permission-for-action')
|
||||
}>
|
||||
<Button
|
||||
data-testid="submit-btn"
|
||||
@ -425,7 +430,7 @@ const AddKPIPage = () => {
|
||||
</Form>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col className="m-t-md" span={4}>
|
||||
<Col className="m-t-md" data-testid="right-panel" span={4}>
|
||||
<Typography.Paragraph className="text-base font-medium">
|
||||
{t('label.edit-entity', { entity: t('label.kpi-uppercase') })}
|
||||
</Typography.Paragraph>
|
||||
@ -441,4 +446,4 @@ const AddKPIPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default AddKPIPage;
|
||||
export default EditKPIPage;
|
||||
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 2021 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const KPI_CHARTS = [
|
||||
{
|
||||
id: 'd2f093d4-0ca8-42b8-8721-1c2a59951b59',
|
||||
name: 'dailyActiveUsers',
|
||||
displayName: 'Daily active users on the platform',
|
||||
fullyQualifiedName: 'dailyActiveUsers',
|
||||
description: 'Display the number of users active.',
|
||||
dataIndexType: 'web_analytic_user_activity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'activeUsers',
|
||||
displayName: 'Number of active users',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952802,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/d2f093d4-0ca8-42b8-8721-1c2a59951b59',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: 'fbad142d-16d5-479d-bed3-67bb5fd4104d',
|
||||
name: 'mostActiveUsers',
|
||||
displayName: 'Most Active Users',
|
||||
fullyQualifiedName: 'mostActiveUsers',
|
||||
description:
|
||||
'Displays the most active users on the platform based on page views.',
|
||||
dataIndexType: 'web_analytic_user_activity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'userName',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
{
|
||||
name: 'team',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'lastSession',
|
||||
displayName: 'Last time the user visited the platform',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'sessions',
|
||||
displayName: 'Total number of sessions',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'avgSessionDuration',
|
||||
displayName: 'The average duration time of a session',
|
||||
chartDataType: 'FLOAT',
|
||||
},
|
||||
{
|
||||
name: 'pageViews',
|
||||
displayName: 'Total number of page view',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952821,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/fbad142d-16d5-479d-bed3-67bb5fd4104d',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '9217560a-3fed-4c0d-85fa-d7c699feefac',
|
||||
name: 'mostViewedEntities',
|
||||
displayName: 'Most Viewed entites',
|
||||
fullyQualifiedName: 'mostViewedEntities',
|
||||
description: 'Displays the most viewed entities.',
|
||||
dataIndexType: 'web_analytic_entity_view_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'entityFqn',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
{
|
||||
name: 'owner',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'pageViews',
|
||||
displayName: 'Total number of page view',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952805,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/9217560a-3fed-4c0d-85fa-d7c699feefac',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '73d9b934-7664-4e84-8a7e-7fa00fe03f5f',
|
||||
name: 'pageViewsByEntities',
|
||||
displayName: 'Page views by entities',
|
||||
fullyQualifiedName: 'pageViewsByEntities',
|
||||
description: 'Displays the number of time an entity type was viewed.',
|
||||
dataIndexType: 'web_analytic_entity_view_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityType',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'pageViews',
|
||||
displayName: 'Total number of page view',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952798,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/73d9b934-7664-4e84-8a7e-7fa00fe03f5f',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
name: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
displayName: 'Percentage of Entities With Description',
|
||||
fullyQualifiedName: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
description: 'Display the percentage of entities with description by type.',
|
||||
dataIndexType: 'entity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityType',
|
||||
displayName: 'Entity Type',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'completedDescriptionFraction',
|
||||
displayName: 'Percentage of Completed Description',
|
||||
chartDataType: 'PERCENTAGE',
|
||||
},
|
||||
{
|
||||
name: 'completedDescription',
|
||||
displayName: 'Entities with Completed Description',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
{
|
||||
name: 'entityCount',
|
||||
displayName: 'Total Entities',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952816,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: 'd712533a-ea8c-409f-a9e3-3f68d06d7864',
|
||||
name: 'PercentageOfEntitiesWithOwnerByType',
|
||||
displayName: 'Percentage of Entities With Owner',
|
||||
fullyQualifiedName: 'PercentageOfEntitiesWithOwnerByType',
|
||||
description: 'Display the percentage of entities with owner by type.',
|
||||
dataIndexType: 'entity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityType',
|
||||
displayName: 'Entity Type',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'hasOwnerFraction',
|
||||
displayName: 'Percentage of Completed Owner',
|
||||
chartDataType: 'PERCENTAGE',
|
||||
},
|
||||
{
|
||||
name: 'hasOwner',
|
||||
displayName: 'Entities with Owner',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
{
|
||||
name: 'entityCount',
|
||||
displayName: 'Total Entities',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952825,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/d712533a-ea8c-409f-a9e3-3f68d06d7864',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '71d7f330-40d1-4c9e-b843-b5b62ff2efcd',
|
||||
name: 'TotalEntitiesByTier',
|
||||
displayName: 'Percentage of Entities With Tier',
|
||||
fullyQualifiedName: 'TotalEntitiesByTier',
|
||||
description: 'Display the percentage of entities with tier by type.',
|
||||
dataIndexType: 'entity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityTier',
|
||||
displayName: 'Entity Tier',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'entityCountFraction',
|
||||
displayName: 'Total Count of Entity',
|
||||
chartDataType: 'PERCENTAGE',
|
||||
},
|
||||
{
|
||||
name: 'entityCount',
|
||||
displayName: 'Total Entities',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952786,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/71d7f330-40d1-4c9e-b843-b5b62ff2efcd',
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: 'd3eff37a-1196-4e4a-bc6a-5a81bb6504b5',
|
||||
name: 'TotalEntitiesByType',
|
||||
displayName: 'Total Entities',
|
||||
fullyQualifiedName: 'TotalEntitiesByType',
|
||||
description: 'Display the total of entities by type.',
|
||||
dataIndexType: 'entity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityType',
|
||||
displayName: 'Entity Tier',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'entityCountFraction',
|
||||
displayName: 'Total Count of Entity',
|
||||
chartDataType: 'PERCENTAGE',
|
||||
},
|
||||
{
|
||||
name: 'entityCount',
|
||||
displayName: 'Total Entities',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952810,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/d3eff37a-1196-4e4a-bc6a-5a81bb6504b5',
|
||||
deleted: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const KPI_LIST = [
|
||||
{
|
||||
id: 'dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
name: 'description-kpi',
|
||||
displayName: 'Description KPI',
|
||||
fullyQualifiedName: 'description-kpi',
|
||||
description: '',
|
||||
metricType: 'PERCENTAGE',
|
||||
dataInsightChart: {
|
||||
id: '7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
type: 'dataInsightChart',
|
||||
name: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
fullyQualifiedName: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
description:
|
||||
'Display the percentage of entities with description by type.',
|
||||
displayName: 'Percentage of Entities With Description',
|
||||
deleted: false,
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
},
|
||||
targetDefinition: [
|
||||
{
|
||||
name: 'completedDescriptionFraction',
|
||||
value: '0.65',
|
||||
},
|
||||
],
|
||||
startDate: 1670351400000,
|
||||
endDate: 1672165800000,
|
||||
version: 0.2,
|
||||
updatedAt: 1670414685805,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/kpi/dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
changeDescription: {
|
||||
fieldsAdded: [],
|
||||
fieldsUpdated: [
|
||||
{
|
||||
name: 'startDate',
|
||||
oldValue: 1670395661000,
|
||||
newValue: 1670351400000,
|
||||
},
|
||||
{
|
||||
name: 'endDate',
|
||||
oldValue: 1672210072000,
|
||||
newValue: 1672165800000,
|
||||
},
|
||||
],
|
||||
fieldsDeleted: [],
|
||||
previousVersion: 0.1,
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const KPI_DATA = {
|
||||
id: 'dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
name: 'description-kpi',
|
||||
displayName: 'Description KPI',
|
||||
fullyQualifiedName: 'description-kpi',
|
||||
description: '',
|
||||
metricType: 'PERCENTAGE',
|
||||
dataInsightChart: {
|
||||
id: '7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
type: 'dataInsightChart',
|
||||
name: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
fullyQualifiedName: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
description: 'Display the percentage of entities with description by type.',
|
||||
displayName: 'Percentage of Entities With Description',
|
||||
deleted: false,
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
},
|
||||
targetDefinition: [
|
||||
{
|
||||
name: 'completedDescriptionFraction',
|
||||
value: '0.65',
|
||||
},
|
||||
],
|
||||
startDate: 1670351400000,
|
||||
endDate: 1672165800000,
|
||||
version: 0.2,
|
||||
updatedAt: 1670414685805,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/kpi/dabd01bb-095d-448e-af21-0427859b99b5',
|
||||
changeDescription: {
|
||||
fieldsAdded: [],
|
||||
fieldsUpdated: [
|
||||
{
|
||||
name: 'startDate',
|
||||
oldValue: 1670395661000,
|
||||
newValue: 1670351400000,
|
||||
},
|
||||
{
|
||||
name: 'endDate',
|
||||
oldValue: 1672210072000,
|
||||
newValue: 1672165800000,
|
||||
},
|
||||
],
|
||||
fieldsDeleted: [],
|
||||
previousVersion: 0.1,
|
||||
},
|
||||
deleted: false,
|
||||
};
|
||||
|
||||
export const DESCRIPTION_CHART = {
|
||||
id: '7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
name: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
displayName: 'Percentage of Entities With Description',
|
||||
fullyQualifiedName: 'PercentageOfEntitiesWithDescriptionByType',
|
||||
description: 'Display the percentage of entities with description by type.',
|
||||
dataIndexType: 'entity_report_data_index',
|
||||
dimensions: [
|
||||
{
|
||||
name: 'timestamp',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
{
|
||||
name: 'entityType',
|
||||
displayName: 'Entity Type',
|
||||
chartDataType: 'STRING',
|
||||
},
|
||||
],
|
||||
metrics: [
|
||||
{
|
||||
name: 'completedDescriptionFraction',
|
||||
displayName: 'Percentage of Completed Description',
|
||||
chartDataType: 'PERCENTAGE',
|
||||
},
|
||||
{
|
||||
name: 'completedDescription',
|
||||
displayName: 'Entities with Completed Description',
|
||||
chartDataType: 'NUMBER',
|
||||
},
|
||||
{
|
||||
name: 'entityCount',
|
||||
displayName: 'Total Entities',
|
||||
chartDataType: 'INT',
|
||||
},
|
||||
],
|
||||
version: 0.1,
|
||||
updatedAt: 1670231952816,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/dataInsight/7dc794d3-1881-408c-92fc-6182aa453bc8',
|
||||
deleted: false,
|
||||
};
|
@ -45,6 +45,7 @@ import { TotalEntitiesByTier } from '../generated/dataInsight/type/totalEntities
|
||||
import {
|
||||
ChartValue,
|
||||
DataInsightChartTooltipProps,
|
||||
KpiDates,
|
||||
} from '../interface/data-insight.interface';
|
||||
import { pluralize } from './CommonUtils';
|
||||
import { getFormattedDateFromMilliSeconds } from './TimeUtils';
|
||||
@ -523,3 +524,10 @@ export const getKpiResultFeedback = (day: number, isTargetMet: boolean) => {
|
||||
|
||||
export const getDataInsightPathWithFqn = (fqn: string) =>
|
||||
ROUTES.DATA_INSIGHT_WITH_TAB.replace(PLACEHOLDER_ROUTE_TAB, fqn);
|
||||
|
||||
export const getKPIFormattedDates = (kpiDates: KpiDates): KpiDates => {
|
||||
return {
|
||||
startDate: `${kpiDates.startDate} 00:00`,
|
||||
endDate: `${kpiDates.endDate} 23:59`,
|
||||
};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user