mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-11 00:11:05 +00:00
MINOR: fix the recent run not showing for data-insight application (#15811)
* fix the recent run not showing for application * supported unit test for the same * used ingestionRecentRuns for application run status * limit the records shown * change the file logsViewer from component to page * minor fix
This commit is contained in:
parent
ba561c9674
commit
05dfd4ddfd
@ -193,8 +193,8 @@ const UpdateTagsPage = withSuspenseFallback(
|
|||||||
React.lazy(() => import('../../pages/TasksPage/UpdateTagPage/UpdateTagPage'))
|
React.lazy(() => import('../../pages/TasksPage/UpdateTagPage/UpdateTagPage'))
|
||||||
);
|
);
|
||||||
|
|
||||||
const LogsViewer = withSuspenseFallback(
|
const LogsViewerPage = withSuspenseFallback(
|
||||||
React.lazy(() => import('../../pages/LogsViewer/LogsViewer.component'))
|
React.lazy(() => import('../../pages/LogsViewerPage/LogsViewerPage'))
|
||||||
);
|
);
|
||||||
|
|
||||||
const DataInsightPage = withSuspenseFallback(
|
const DataInsightPage = withSuspenseFallback(
|
||||||
@ -402,7 +402,7 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
|
|||||||
component={TestSuiteDetailsPage}
|
component={TestSuiteDetailsPage}
|
||||||
path={ROUTES.TEST_SUITES_WITH_FQN}
|
path={ROUTES.TEST_SUITES_WITH_FQN}
|
||||||
/>
|
/>
|
||||||
<Route exact component={LogsViewer} path={ROUTES.LOGS} />
|
<Route exact component={LogsViewerPage} path={ROUTES.LOGS} />
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
component={TestSuiteIngestionPage}
|
component={TestSuiteIngestionPage}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { IngestionPipeline } from '../../../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
import { IngestionPipeline } from '../../../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
|
import { mockDataInsightApplicationRun } from '../../../../../mocks/LogsViewerPage.mock';
|
||||||
import { getRunHistoryForPipeline } from '../../../../../rest/ingestionPipelineAPI';
|
import { getRunHistoryForPipeline } from '../../../../../rest/ingestionPipelineAPI';
|
||||||
import ConnectionStepCard from '../../../../common/TestConnection/ConnectionStepCard/ConnectionStepCard';
|
import ConnectionStepCard from '../../../../common/TestConnection/ConnectionStepCard/ConnectionStepCard';
|
||||||
import { IngestionRecentRuns } from './IngestionRecentRuns.component';
|
import { IngestionRecentRuns } from './IngestionRecentRuns.component';
|
||||||
@ -337,4 +338,17 @@ describe('Test IngestionRecentRun component', () => {
|
|||||||
await screen.findByText(/testConnectionStepCard/)
|
await screen.findByText(/testConnectionStepCard/)
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not fetch getRunHistoryForPipeline in case of Application', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<IngestionRecentRuns
|
||||||
|
isApplicationType
|
||||||
|
appRuns={mockDataInsightApplicationRun.data}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getRunHistoryForPipeline).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -43,8 +43,10 @@ import ConnectionStepCard from '../../../../common/TestConnection/ConnectionStep
|
|||||||
import './ingestion-recent-run.style.less';
|
import './ingestion-recent-run.style.less';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
ingestion: IngestionPipeline;
|
ingestion?: IngestionPipeline;
|
||||||
classNames?: string;
|
classNames?: string;
|
||||||
|
appRuns?: PipelineStatus[];
|
||||||
|
isApplicationType?: boolean;
|
||||||
}
|
}
|
||||||
const queryParams = {
|
const queryParams = {
|
||||||
startTs: getEpochMillisForPastDays(1),
|
startTs: getEpochMillisForPastDays(1),
|
||||||
@ -54,6 +56,8 @@ const queryParams = {
|
|||||||
export const IngestionRecentRuns: FunctionComponent<Props> = ({
|
export const IngestionRecentRuns: FunctionComponent<Props> = ({
|
||||||
ingestion,
|
ingestion,
|
||||||
classNames,
|
classNames,
|
||||||
|
appRuns,
|
||||||
|
isApplicationType,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [recentRunStatus, setRecentRunStatus] = useState<PipelineStatus[]>([]);
|
const [recentRunStatus, setRecentRunStatus] = useState<PipelineStatus[]>([]);
|
||||||
@ -137,27 +141,30 @@ export const IngestionRecentRuns: FunctionComponent<Props> = ({
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await getRunHistoryForPipeline(
|
const response = await getRunHistoryForPipeline(
|
||||||
ingestion.fullyQualifiedName ?? '',
|
ingestion?.fullyQualifiedName ?? '',
|
||||||
queryParams
|
queryParams
|
||||||
);
|
);
|
||||||
|
|
||||||
const runs = response.data.splice(0, 5).reverse() ?? [];
|
const runs = response.data.splice(0, 5).reverse() ?? [];
|
||||||
|
|
||||||
setRecentRunStatus(
|
setRecentRunStatus(
|
||||||
runs.length === 0 && ingestion.pipelineStatuses
|
runs.length === 0 && ingestion?.pipelineStatuses
|
||||||
? [ingestion.pipelineStatuses]
|
? [ingestion.pipelineStatuses]
|
||||||
: runs
|
: runs
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [ingestion, ingestion.fullyQualifiedName]);
|
}, [ingestion, ingestion?.fullyQualifiedName]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ingestion.fullyQualifiedName) {
|
if (isApplicationType && appRuns) {
|
||||||
|
setRecentRunStatus(appRuns.splice(0, 5).reverse() ?? []);
|
||||||
|
setLoading(false);
|
||||||
|
} else if (ingestion?.fullyQualifiedName) {
|
||||||
fetchPipelineStatus();
|
fetchPipelineStatus();
|
||||||
}
|
}
|
||||||
}, [ingestion, ingestion.fullyQualifiedName]);
|
}, [ingestion, ingestion?.fullyQualifiedName]);
|
||||||
|
|
||||||
const handleRunStatusClick = (status: PipelineStatus) => {
|
const handleRunStatusClick = (status: PipelineStatus) => {
|
||||||
setExpandedKeys([]);
|
setExpandedKeys([]);
|
||||||
|
|||||||
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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 { PipelineState } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
|
|
||||||
|
export const mockLogsData = {
|
||||||
|
ingestion_task: 'test Logs',
|
||||||
|
total: '6',
|
||||||
|
after: '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockIngestionPipeline = {
|
||||||
|
id: 'c379d75a-43cd-4d93-a799-0bba4a22c690',
|
||||||
|
name: 'test-redshift_metadata_ZeCajs9g',
|
||||||
|
displayName: 'test-redshift_metadata_ZeCajs9g',
|
||||||
|
pipelineType: 'metadata',
|
||||||
|
owner: {
|
||||||
|
id: 'e43cdd2e-7698-4e06-8cb4-dbcdf401d6dc',
|
||||||
|
type: 'user',
|
||||||
|
name: 'admin',
|
||||||
|
fullyQualifiedName: 'admin',
|
||||||
|
deleted: false,
|
||||||
|
href: 'http://localhost:8585/api/v1/users/e43cdd2e-7698-4e06-8cb4-dbcdf401d6dc',
|
||||||
|
},
|
||||||
|
fullyQualifiedName: 'test-redshift.test-redshift_metadata_ZeCajs9g',
|
||||||
|
sourceConfig: {
|
||||||
|
config: {
|
||||||
|
type: 'DatabaseMetadata',
|
||||||
|
markDeletedTables: true,
|
||||||
|
markAllDeletedTables: false,
|
||||||
|
includeTables: true,
|
||||||
|
includeViews: true,
|
||||||
|
includeTags: true,
|
||||||
|
useFqnForFiltering: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
openMetadataServerConnection: {
|
||||||
|
clusterName: 'openmetadata',
|
||||||
|
type: 'OpenMetadata',
|
||||||
|
hostPort: 'http://openmetadata-server:8585/api',
|
||||||
|
authProvider: 'openmetadata',
|
||||||
|
verifySSL: 'no-ssl',
|
||||||
|
securityConfig: {
|
||||||
|
jwtToken: 'test_token',
|
||||||
|
},
|
||||||
|
secretsManagerProvider: 'noop',
|
||||||
|
},
|
||||||
|
airflowConfig: {
|
||||||
|
pausePipeline: false,
|
||||||
|
concurrency: 1,
|
||||||
|
pipelineTimezone: 'UTC',
|
||||||
|
retries: 3,
|
||||||
|
retryDelay: 300,
|
||||||
|
pipelineCatchup: false,
|
||||||
|
scheduleInterval: '*/5 * * * *',
|
||||||
|
maxActiveRuns: 1,
|
||||||
|
workflowDefaultView: 'tree',
|
||||||
|
workflowDefaultViewOrientation: 'LR',
|
||||||
|
},
|
||||||
|
service: {
|
||||||
|
id: '086ad38c-dd10-42ae-a58b-1c72ee6e7f50',
|
||||||
|
type: 'databaseService',
|
||||||
|
name: 'test-redshift',
|
||||||
|
fullyQualifiedName: 'test-redshift',
|
||||||
|
description: '',
|
||||||
|
deleted: false,
|
||||||
|
href: 'http://localhost:8585/api/v1/services/databaseServices/086ad38c-dd10-42ae-a58b-1c72ee6e7f50',
|
||||||
|
},
|
||||||
|
pipelineStatuses: [
|
||||||
|
{
|
||||||
|
runId: 'scheduled__2022-10-20T04:35:00+00:00',
|
||||||
|
state: 'running',
|
||||||
|
startDate: 1666240861500,
|
||||||
|
timestamp: 1666240500000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loggerLevel: 'DEBUG',
|
||||||
|
deployed: true,
|
||||||
|
enabled: true,
|
||||||
|
href: 'http://localhost:8585/api/v1/services/ingestionPipelines/c379d75a-43cd-4d93-a799-0bba4a22c690',
|
||||||
|
version: 0.1,
|
||||||
|
updatedAt: 1666240859704,
|
||||||
|
updatedBy: 'admin',
|
||||||
|
deleted: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockDataInsightApplication = {
|
||||||
|
id: '8437b08f-404a-4129-8448-610323daf51e',
|
||||||
|
name: 'DataInsightsApplication',
|
||||||
|
displayName: 'Data Insights',
|
||||||
|
description:
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
'**Data Insights: A Revolutionary Tool for Metadata Analysis and Data Management**\n\n**Comprehensive Data Analytics:** Dive deep into the world of data with our advanced analytics, crafted to transform raw metadata into valuable insights.',
|
||||||
|
fullyQualifiedName: 'DataInsightsApplication',
|
||||||
|
version: 0.1,
|
||||||
|
updatedAt: 1712299044226,
|
||||||
|
updatedBy: 'admin',
|
||||||
|
href: 'http://localhost:8585/api/v1/apps/8437b08f-404a-4129-8448-610323daf51e',
|
||||||
|
deleted: false,
|
||||||
|
provider: 'user',
|
||||||
|
developer: 'Collate Inc.',
|
||||||
|
developerUrl: 'https://www.getcollate.io',
|
||||||
|
privacyPolicyUrl: 'https://www.getcollate.io',
|
||||||
|
supportEmail: 'support@getcollate.io',
|
||||||
|
className: 'org.openmetadata.service.apps.bundles.insights.DataInsightsApp',
|
||||||
|
appType: 'external',
|
||||||
|
scheduleType: 'Scheduled',
|
||||||
|
permission: 'All',
|
||||||
|
bot: {
|
||||||
|
id: '2f38b35d-bc91-4412-af2a-294644d44b2c',
|
||||||
|
type: 'bot',
|
||||||
|
name: 'DataInsightsApplicationBot',
|
||||||
|
fullyQualifiedName: 'DataInsightsApplicationBot',
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
runtime: {
|
||||||
|
enabled: 'true',
|
||||||
|
},
|
||||||
|
allowConfiguration: false,
|
||||||
|
system: false,
|
||||||
|
appConfiguration: {},
|
||||||
|
preview: false,
|
||||||
|
appSchedule: {
|
||||||
|
scheduleTimeline: 'Custom',
|
||||||
|
cronExpression: '0 0 * * *',
|
||||||
|
},
|
||||||
|
appScreenshots: ['DataInsightsPic1.png'],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockDataInsightApplicationRun = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
runId: '7852085e-2ef3-44d1-8c95-dd8c14d33895',
|
||||||
|
pipelineState: PipelineState.Success,
|
||||||
|
startDate: 1712299055158,
|
||||||
|
timestamp: 1712299055158,
|
||||||
|
endDate: 1712299060061,
|
||||||
|
status: [
|
||||||
|
{
|
||||||
|
name: 'OpenMetadata Insights',
|
||||||
|
records: 71,
|
||||||
|
updated_records: 0,
|
||||||
|
warnings: 0,
|
||||||
|
errors: 0,
|
||||||
|
filtered: 0,
|
||||||
|
failures: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'OpenMetadata',
|
||||||
|
records: 71,
|
||||||
|
updated_records: 0,
|
||||||
|
warnings: 0,
|
||||||
|
errors: 0,
|
||||||
|
filtered: 0,
|
||||||
|
failures: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
paging: {
|
||||||
|
before: 'MTcxMjIxMzc0NjM1Ng==',
|
||||||
|
after: 'MTcxMjMwMDE0NjM1Ng==',
|
||||||
|
total: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockLatestDataInsightApplicationRunLogs = {
|
||||||
|
data_insight_task:
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
"31103bd4cfc9\n*** Found local files:\n*** * /opt/airflow/logs/dag_id=OpenMetadata_dataInsight/run_id=manual__2024-04-05T06:37:28+00:00/task_id=data_insight_task/attempt=1.log\n[2024-04-05T06:37:35.052+0000] {taskinstance.py:1159} INFO - Dependencies all met for dep_context=non-requeueable deps ti=<TaskInstance: OpenMetadata_dataInsight.data_insight_task manual__2024-04-05T06:37:28+00:00 [queued]>\n[2024-04-05T06:37:35.057+0000] {taskinstance.py:1159} INFO - Dependencies all met for dep_context=requeueable deps ti=<TaskInstance: OpenMetadata_dataInsight.data_insight_task manual__2024-04-05T06:37:28+00:00 [queued]>\n[2024-04-05T06:37:35.057+0000] {taskinstance.py:1361} INFO - Starting attempt 1 of 1\n[2024-04-05T06:37:35.065+0000] {taskinstance.py:1382} INFO - Executing <Task(CustomPythonOperator): data_insight_task> on 2024-04-05 06:37:28+00:00\n[2024-04-05T06:37:35.068+0000] {standard_task_runner.py:57} INFO - Started process 40504 to run task\n[2024-04-05T06:37:35.072+0000] {standard_task_runner.py:84} INFO - Running: ['airflow', 'tasks', 'run', 'OpenMetadata_dataInsight', 'data_insight_task', 'manual__2024-04-05T06:37:28+00:00', '--job-id', '81', '--raw', '--subdir', 'DAGS_FOLDER/OpenMetadata_dataInsight.py', '--cfg-path', '/tmp/tmpu41_kxxp']\n[2024-04-05T06:37:35.073+0000] {standard_task_runner.py:85} INFO - Job 81: Subtask data_insight_task\n[2024-04-05T06:37:35.099+0000] {task_command.py:416} INFO - Running <TaskInstance: OpenMetadata_dataInsight.data_insight_task manual__2024-04-05T06:37:28+00:00 [running]> on host 31103bd4cfc9\n[2024-04-05T06:37:35.151+0000] {taskinstance.py:1662} INFO - Exporting env vars: AIRFLOW_CTX_DAG_OWNER='openmetadata' AIRFLOW_CTX_DAG_ID='OpenMetadata_dataInsight' AIRFLOW_CTX_TASK_ID='data_insight_task' AIRFLOW_CTX_EXECUTION_DATE='2024-04-05T06:37:28+00:00",
|
||||||
|
total: '1',
|
||||||
|
};
|
||||||
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 mockLogsData = {
|
|
||||||
ingestion_task: 'test Logs',
|
|
||||||
total: '6',
|
|
||||||
after: '1',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockIngestionPipeline = {
|
|
||||||
id: 'c379d75a-43cd-4d93-a799-0bba4a22c690',
|
|
||||||
name: 'test-redshift_metadata_ZeCajs9g',
|
|
||||||
displayName: 'test-redshift_metadata_ZeCajs9g',
|
|
||||||
pipelineType: 'metadata',
|
|
||||||
owner: {
|
|
||||||
id: 'e43cdd2e-7698-4e06-8cb4-dbcdf401d6dc',
|
|
||||||
type: 'user',
|
|
||||||
name: 'admin',
|
|
||||||
fullyQualifiedName: 'admin',
|
|
||||||
deleted: false,
|
|
||||||
href: 'http://localhost:8585/api/v1/users/e43cdd2e-7698-4e06-8cb4-dbcdf401d6dc',
|
|
||||||
},
|
|
||||||
fullyQualifiedName: 'test-redshift.test-redshift_metadata_ZeCajs9g',
|
|
||||||
sourceConfig: {
|
|
||||||
config: {
|
|
||||||
type: 'DatabaseMetadata',
|
|
||||||
markDeletedTables: true,
|
|
||||||
markAllDeletedTables: false,
|
|
||||||
includeTables: true,
|
|
||||||
includeViews: true,
|
|
||||||
includeTags: true,
|
|
||||||
useFqnForFiltering: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
openMetadataServerConnection: {
|
|
||||||
clusterName: 'openmetadata',
|
|
||||||
type: 'OpenMetadata',
|
|
||||||
hostPort: 'http://openmetadata-server:8585/api',
|
|
||||||
authProvider: 'openmetadata',
|
|
||||||
verifySSL: 'no-ssl',
|
|
||||||
securityConfig: {
|
|
||||||
jwtToken: 'test_token',
|
|
||||||
},
|
|
||||||
secretsManagerProvider: 'noop',
|
|
||||||
},
|
|
||||||
airflowConfig: {
|
|
||||||
pausePipeline: false,
|
|
||||||
concurrency: 1,
|
|
||||||
pipelineTimezone: 'UTC',
|
|
||||||
retries: 3,
|
|
||||||
retryDelay: 300,
|
|
||||||
pipelineCatchup: false,
|
|
||||||
scheduleInterval: '*/5 * * * *',
|
|
||||||
maxActiveRuns: 1,
|
|
||||||
workflowDefaultView: 'tree',
|
|
||||||
workflowDefaultViewOrientation: 'LR',
|
|
||||||
},
|
|
||||||
service: {
|
|
||||||
id: '086ad38c-dd10-42ae-a58b-1c72ee6e7f50',
|
|
||||||
type: 'databaseService',
|
|
||||||
name: 'test-redshift',
|
|
||||||
fullyQualifiedName: 'test-redshift',
|
|
||||||
description: '',
|
|
||||||
deleted: false,
|
|
||||||
href: 'http://localhost:8585/api/v1/services/databaseServices/086ad38c-dd10-42ae-a58b-1c72ee6e7f50',
|
|
||||||
},
|
|
||||||
pipelineStatuses: [
|
|
||||||
{
|
|
||||||
runId: 'scheduled__2022-10-20T04:35:00+00:00',
|
|
||||||
state: 'running',
|
|
||||||
startDate: 1666240861500,
|
|
||||||
timestamp: 1666240500000,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
loggerLevel: 'DEBUG',
|
|
||||||
deployed: true,
|
|
||||||
enabled: true,
|
|
||||||
href: 'http://localhost:8585/api/v1/services/ingestionPipelines/c379d75a-43cd-4d93-a799-0bba4a22c690',
|
|
||||||
version: 0.1,
|
|
||||||
updatedAt: 1666240859704,
|
|
||||||
updatedBy: 'admin',
|
|
||||||
deleted: false,
|
|
||||||
};
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2024 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -13,8 +13,20 @@
|
|||||||
|
|
||||||
import { act, render, screen } from '@testing-library/react';
|
import { act, render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LogsViewer from './LogsViewer.component';
|
import { useParams } from 'react-router-dom';
|
||||||
import { mockIngestionPipeline, mockLogsData } from './mocks/LogsViewer.mock';
|
import {
|
||||||
|
mockDataInsightApplication,
|
||||||
|
mockDataInsightApplicationRun,
|
||||||
|
mockIngestionPipeline,
|
||||||
|
mockLatestDataInsightApplicationRunLogs,
|
||||||
|
mockLogsData,
|
||||||
|
} from '../../mocks/LogsViewerPage.mock';
|
||||||
|
import {
|
||||||
|
getApplicationByName,
|
||||||
|
getExternalApplicationRuns,
|
||||||
|
getLatestApplicationRuns,
|
||||||
|
} from '../../rest/applicationAPI';
|
||||||
|
import LogsViewerPage from './LogsViewerPage';
|
||||||
|
|
||||||
jest.mock('react-router-dom', () => ({
|
jest.mock('react-router-dom', () => ({
|
||||||
useParams: jest.fn().mockReturnValue({
|
useParams: jest.fn().mockReturnValue({
|
||||||
@ -60,10 +72,28 @@ jest.mock(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('LogsViewer.component', () => {
|
jest.mock('./LogsViewerPageSkeleton.component', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <p>LogsViewerPageSkeleton</p>);
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('../../rest/applicationAPI', () => ({
|
||||||
|
getApplicationByName: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve(mockDataInsightApplication)),
|
||||||
|
getExternalApplicationRuns: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve(mockDataInsightApplicationRun)),
|
||||||
|
getLatestApplicationRuns: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() =>
|
||||||
|
Promise.resolve(mockLatestDataInsightApplicationRunLogs)
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('LogsViewerPage.component', () => {
|
||||||
it('On initial, component should render', async () => {
|
it('On initial, component should render', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<LogsViewer />);
|
render(<LogsViewerPage />);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await screen.findByText('TitleBreadcrumb.component')
|
await screen.findByText('TitleBreadcrumb.component')
|
||||||
@ -78,4 +108,39 @@ describe('LogsViewer.component', () => {
|
|||||||
|
|
||||||
expect(logElement).toBeInTheDocument();
|
expect(logElement).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should fetch api for application logs', async () => {
|
||||||
|
(useParams as jest.Mock).mockReturnValue({
|
||||||
|
logEntityType: 'apps',
|
||||||
|
fqn: 'DataInsightsApplication',
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(<LogsViewerPage />);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getApplicationByName).toHaveBeenCalled();
|
||||||
|
expect(getExternalApplicationRuns).toHaveBeenCalled();
|
||||||
|
expect(getLatestApplicationRuns).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show basic configuration for application in right panel', async () => {
|
||||||
|
(useParams as jest.Mock).mockReturnValue({
|
||||||
|
logEntityType: 'apps',
|
||||||
|
fqn: 'DataInsightsApplication',
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(<LogsViewerPage />);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Type')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Custom')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByText('Schedule')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('0 0 * * *')).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(screen.getByText('Recent Runs')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('IngestionRecentRuns')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2024 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2024 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -11,9 +11,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, Col, Row, Space, Tag, Typography } from 'antd';
|
import { Button, Col, Row, Space, Typography } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { isEmpty, isNil, isUndefined, startCase, toNumber } from 'lodash';
|
import { isEmpty, isNil, isUndefined, toNumber } from 'lodash';
|
||||||
import React, {
|
import React, {
|
||||||
Fragment,
|
Fragment,
|
||||||
useCallback,
|
useCallback,
|
||||||
@ -31,20 +31,18 @@ import TitleBreadcrumb from '../../components/common/TitleBreadcrumb/TitleBreadc
|
|||||||
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
|
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
|
||||||
import { IngestionRecentRuns } from '../../components/Settings/Services/Ingestion/IngestionRecentRun/IngestionRecentRuns.component';
|
import { IngestionRecentRuns } from '../../components/Settings/Services/Ingestion/IngestionRecentRun/IngestionRecentRuns.component';
|
||||||
import { GlobalSettingOptions } from '../../constants/GlobalSettings.constants';
|
import { GlobalSettingOptions } from '../../constants/GlobalSettings.constants';
|
||||||
import { PIPELINE_INGESTION_RUN_STATUS } from '../../constants/pipeline.constants';
|
|
||||||
import { PipelineType } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline';
|
import { PipelineType } from '../../generated/api/services/ingestionPipelines/createIngestionPipeline';
|
||||||
import { App, AppScheduleClass } from '../../generated/entity/applications/app';
|
import { App, AppScheduleClass } from '../../generated/entity/applications/app';
|
||||||
import { AppRunRecord } from '../../generated/entity/applications/appRunRecord';
|
|
||||||
import {
|
import {
|
||||||
IngestionPipeline,
|
IngestionPipeline,
|
||||||
PipelineState,
|
PipelineStatus,
|
||||||
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
} from '../../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
import { Include } from '../../generated/type/include';
|
import { Include } from '../../generated/type/include';
|
||||||
import { Paging } from '../../generated/type/paging';
|
import { Paging } from '../../generated/type/paging';
|
||||||
import { useFqn } from '../../hooks/useFqn';
|
import { useFqn } from '../../hooks/useFqn';
|
||||||
import {
|
import {
|
||||||
getApplicationByName,
|
getApplicationByName,
|
||||||
getApplicationRuns,
|
getExternalApplicationRuns,
|
||||||
getLatestApplicationRuns,
|
getLatestApplicationRuns,
|
||||||
} from '../../rest/applicationAPI';
|
} from '../../rest/applicationAPI';
|
||||||
import {
|
import {
|
||||||
@ -54,11 +52,11 @@ import {
|
|||||||
import { getEpochMillisForPastDays } from '../../utils/date-time/DateTimeUtils';
|
import { getEpochMillisForPastDays } from '../../utils/date-time/DateTimeUtils';
|
||||||
import { getLogBreadCrumbs } from '../../utils/LogsViewer.utils';
|
import { getLogBreadCrumbs } from '../../utils/LogsViewer.utils';
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import './logs-viewer.style.less';
|
import './logs-viewer-page.style.less';
|
||||||
import LogViewerSkeleton from './LogsViewer-skeleton.component';
|
import { LogViewerParams } from './LogsViewerPage.interfaces';
|
||||||
import { LogViewerParams } from './LogsViewer.interfaces';
|
import LogViewerPageSkeleton from './LogsViewerPageSkeleton.component';
|
||||||
|
|
||||||
const LogsViewer = () => {
|
const LogsViewerPage = () => {
|
||||||
const { logEntityType } = useParams<LogViewerParams>();
|
const { logEntityType } = useParams<LogViewerParams>();
|
||||||
const { fqn: ingestionName } = useFqn();
|
const { fqn: ingestionName } = useFqn();
|
||||||
|
|
||||||
@ -68,7 +66,7 @@ const LogsViewer = () => {
|
|||||||
const [logs, setLogs] = useState<string>('');
|
const [logs, setLogs] = useState<string>('');
|
||||||
const [ingestionDetails, setIngestionDetails] = useState<IngestionPipeline>();
|
const [ingestionDetails, setIngestionDetails] = useState<IngestionPipeline>();
|
||||||
const [appData, setAppData] = useState<App>();
|
const [appData, setAppData] = useState<App>();
|
||||||
const [appLatestRun, setAppLatestRun] = useState<AppRunRecord>();
|
const [appRuns, setAppRuns] = useState<PipelineStatus[]>([]);
|
||||||
const [paging, setPaging] = useState<Paging>();
|
const [paging, setPaging] = useState<Paging>();
|
||||||
|
|
||||||
const isApplicationType = useMemo(
|
const isApplicationType = useMemo(
|
||||||
@ -84,13 +82,13 @@ const LogsViewer = () => {
|
|||||||
if (isApplicationType) {
|
if (isApplicationType) {
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
const oneDayAgo = getEpochMillisForPastDays(1);
|
const oneDayAgo = getEpochMillisForPastDays(1);
|
||||||
const { data } = await getApplicationRuns(ingestionName, {
|
const { data } = await getExternalApplicationRuns(ingestionName, {
|
||||||
startTs: oneDayAgo,
|
startTs: oneDayAgo,
|
||||||
endTs: currentTime,
|
endTs: currentTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
const logs = await getLatestApplicationRuns(ingestionName);
|
const logs = await getLatestApplicationRuns(ingestionName);
|
||||||
setAppLatestRun(data[0]);
|
setAppRuns(data);
|
||||||
setLogs(logs.data_insight_task || logs.application_task);
|
setLogs(logs.data_insight_task || logs.application_task);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -267,28 +265,18 @@ const LogsViewer = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const recentRuns = useMemo(() => {
|
const recentRuns = useMemo(() => {
|
||||||
if (isApplicationType) {
|
if (!isUndefined(ingestionDetails) || appRuns) {
|
||||||
return (
|
return (
|
||||||
<Tag
|
<IngestionRecentRuns
|
||||||
className="ingestion-run-badge latest"
|
appRuns={appRuns}
|
||||||
color={
|
ingestion={ingestionDetails}
|
||||||
PIPELINE_INGESTION_RUN_STATUS[
|
isApplicationType={isApplicationType}
|
||||||
(appLatestRun?.status as unknown as PipelineState) ??
|
/>
|
||||||
PipelineState.Failed
|
|
||||||
]
|
|
||||||
}
|
|
||||||
data-testid="pipeline-status">
|
|
||||||
{startCase(appLatestRun?.status)}
|
|
||||||
</Tag>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ingestionDetails?.fullyQualifiedName) {
|
|
||||||
return <IngestionRecentRuns ingestion={ingestionDetails} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '--';
|
return '--';
|
||||||
}, [logEntityType, appLatestRun, ingestionDetails]);
|
}, [isApplicationType, appRuns, ingestionDetails]);
|
||||||
|
|
||||||
const logSummaries = useMemo(() => {
|
const logSummaries = useMemo(() => {
|
||||||
const scheduleClass = appData?.appSchedule as AppScheduleClass;
|
const scheduleClass = appData?.appSchedule as AppScheduleClass;
|
||||||
@ -396,10 +384,10 @@ const LogsViewer = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
) : (
|
) : (
|
||||||
<LogViewerSkeleton />
|
<LogViewerPageSkeleton />
|
||||||
)}
|
)}
|
||||||
</PageLayoutV1>
|
</PageLayoutV1>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogsViewer;
|
export default LogsViewerPage;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2024 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -14,7 +14,7 @@
|
|||||||
import { Col, Row, Skeleton } from 'antd';
|
import { Col, Row, Skeleton } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const LogViewerSkeleton = () => {
|
const LogViewerPageSkeleton = () => {
|
||||||
return (
|
return (
|
||||||
<Row className="border-top justify-between" gutter={[16, 16]}>
|
<Row className="border-top justify-between" gutter={[16, 16]}>
|
||||||
<Col className="p-md border-right" span={18}>
|
<Col className="p-md border-right" span={18}>
|
||||||
@ -47,4 +47,4 @@ const LogViewerSkeleton = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogViewerSkeleton;
|
export default LogViewerPageSkeleton;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2024 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -17,6 +17,7 @@ import { DataInsightLatestRun } from '../components/Settings/Applications/AppDet
|
|||||||
import { App } from '../generated/entity/applications/app';
|
import { App } from '../generated/entity/applications/app';
|
||||||
import { AppRunRecord } from '../generated/entity/applications/appRunRecord';
|
import { AppRunRecord } from '../generated/entity/applications/appRunRecord';
|
||||||
import { CreateAppRequest } from '../generated/entity/applications/createAppRequest';
|
import { CreateAppRequest } from '../generated/entity/applications/createAppRequest';
|
||||||
|
import { PipelineStatus } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||||
import { ListParams } from '../interface/API.interface';
|
import { ListParams } from '../interface/API.interface';
|
||||||
import { getEncodedFqn } from '../utils/StringsUtils';
|
import { getEncodedFqn } from '../utils/StringsUtils';
|
||||||
import APIClient from './index';
|
import APIClient from './index';
|
||||||
@ -71,6 +72,20 @@ export const getApplicationRuns = async (
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getExternalApplicationRuns = async (
|
||||||
|
appName: string,
|
||||||
|
params?: AppListParams
|
||||||
|
) => {
|
||||||
|
const response = await APIClient.get<PagingResponse<PipelineStatus[]>>(
|
||||||
|
`${BASE_URL}/name/${getEncodedFqn(appName)}/status`,
|
||||||
|
{
|
||||||
|
params,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
export const getLatestApplicationRuns = async (appName: string) => {
|
export const getLatestApplicationRuns = async (appName: string) => {
|
||||||
const response = await APIClient.get<DataInsightLatestRun>(
|
const response = await APIClient.get<DataInsightLatestRun>(
|
||||||
`${BASE_URL}/name/${getEncodedFqn(appName)}/logs`
|
`${BASE_URL}/name/${getEncodedFqn(appName)}/logs`
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import {
|
|||||||
import { PipelineServiceClientResponse } from '../generated/entity/services/ingestionPipelines/pipelineServiceClientResponse';
|
import { PipelineServiceClientResponse } from '../generated/entity/services/ingestionPipelines/pipelineServiceClientResponse';
|
||||||
import { Paging } from '../generated/type/paging';
|
import { Paging } from '../generated/type/paging';
|
||||||
import { ListParams } from '../interface/API.interface';
|
import { ListParams } from '../interface/API.interface';
|
||||||
import { IngestionPipelineLogByIdInterface } from '../pages/LogsViewer/LogsViewer.interfaces';
|
import { IngestionPipelineLogByIdInterface } from '../pages/LogsViewerPage/LogsViewerPage.interfaces';
|
||||||
import { getEncodedFqn } from '../utils/StringsUtils';
|
import { getEncodedFqn } from '../utils/StringsUtils';
|
||||||
import APIClient from './index';
|
import APIClient from './index';
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user