mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-01 13:13:10 +00:00
Chore(ui): AutoPilot status banner behaviour improvements (#20758)
* Modify the AutoPilot status banner visibility banner to hide once closed until and unless the status changes again * Add test case for asyncDeleteProvider * Fix the sonarcloud issues * Fix the failing playwright tests * Fix the playwright for delete service
This commit is contained in:
parent
ccee49f24b
commit
fc58893239
@ -122,8 +122,22 @@ export const deleteService = async (
|
|||||||
// Closing the toast notification
|
// Closing the toast notification
|
||||||
await toastNotification(page, /deleted successfully!/, 5 * 60 * 1000); // Wait for up to 5 minutes for the toast notification to appear
|
await toastNotification(page, /deleted successfully!/, 5 * 60 * 1000); // Wait for up to 5 minutes for the toast notification to appear
|
||||||
|
|
||||||
|
await page.reload();
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
await page.waitForSelector('[data-testid="loader"]', { state: 'detached' });
|
||||||
|
|
||||||
|
const serviceSearchResponse = page.waitForResponse(
|
||||||
|
`/api/v1/search/query?q=*${encodeURIComponent(
|
||||||
|
escapeESReservedCharacters(serviceName)
|
||||||
|
)}*`
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.fill('[data-testid="searchbar"]', serviceName);
|
||||||
|
|
||||||
|
await serviceSearchResponse;
|
||||||
|
|
||||||
await page.waitForSelector(`[data-testid="service-name-${serviceName}"]`, {
|
await page.waitForSelector(`[data-testid="service-name-${serviceName}"]`, {
|
||||||
state: 'hidden',
|
state: 'detached',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,8 +172,7 @@ const APIEndpointDetails: React.FC<APIEndpointDetailsProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? onToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ const DashboardDetails = ({
|
|||||||
dashboardDetails.id
|
dashboardDetails.id
|
||||||
);
|
);
|
||||||
setDashboardPermissions(entityPermission);
|
setDashboardPermissions(entityPermission);
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.dashboard'),
|
entity: t('label.dashboard'),
|
||||||
@ -203,8 +203,7 @@ const DashboardDetails = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -151,8 +151,7 @@ const DataModelDetails = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -155,8 +155,7 @@ const MetricDetails: React.FC<MetricDetailsProps> = ({
|
|||||||
getFeedCounts(EntityType.METRIC, decodedMetricFqn, handleFeedCount);
|
getFeedCounts(EntityType.METRIC, decodedMetricFqn, handleFeedCount);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push(ROUTES.METRICS),
|
||||||
isSoftDelete ? onToggleDelete(version) : history.push(ROUTES.METRICS),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
|||||||
mlModelDetail.id
|
mlModelDetail.id
|
||||||
);
|
);
|
||||||
setMlModelPermissions(entityPermission);
|
setMlModelPermissions(entityPermission);
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.ml-model'),
|
entity: t('label.ml-model'),
|
||||||
@ -294,8 +294,7 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
|||||||
}, [mlModelDetail, mlModelStoreColumn]);
|
}, [mlModelDetail, mlModelStoreColumn]);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ const PipelineDetails = ({
|
|||||||
pipelineDetails.id
|
pipelineDetails.id
|
||||||
);
|
);
|
||||||
setPipelinePermissions(entityPermission);
|
setPipelinePermissions(entityPermission);
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.asset-lowercase'),
|
entity: t('label.asset-lowercase'),
|
||||||
@ -254,8 +254,7 @@ const PipelineDetails = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import { AxiosError } from 'axios';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
import { ServiceTypes } from 'Models';
|
import { ServiceTypes } from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { PLATFORM_INSIGHTS_CHART } from '../../constants/ServiceInsightsTab.constants';
|
import { PLATFORM_INSIGHTS_CHART } from '../../constants/ServiceInsightsTab.constants';
|
||||||
import { SystemChartType } from '../../enums/DataInsight.enum';
|
import { SystemChartType } from '../../enums/DataInsight.enum';
|
||||||
@ -27,7 +27,9 @@ import {
|
|||||||
getCurrentDayStartGMTinMillis,
|
getCurrentDayStartGMTinMillis,
|
||||||
getDayAgoStartGMTinMillis,
|
getDayAgoStartGMTinMillis,
|
||||||
} from '../../utils/date-time/DateTimeUtils';
|
} from '../../utils/date-time/DateTimeUtils';
|
||||||
|
import { updateAutoPilotStatus } from '../../utils/LocalStorageUtils';
|
||||||
import {
|
import {
|
||||||
|
checkIfAutoPilotStatusIsDismissed,
|
||||||
filterDistributionChartItem,
|
filterDistributionChartItem,
|
||||||
getPlatformInsightsChartDataFormattingMethod,
|
getPlatformInsightsChartDataFormattingMethod,
|
||||||
getStatusIconFromStatusType,
|
getStatusIconFromStatusType,
|
||||||
@ -144,9 +146,40 @@ const ServiceInsightsTab = ({
|
|||||||
workflowStatesData?.mainInstanceState?.status
|
workflowStatesData?.mainInstanceState?.status
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const showAutoPilotStatus = useMemo(() => {
|
||||||
|
const isDataPresent =
|
||||||
|
!isWorkflowStatusLoading && !isUndefined(workflowStatesData);
|
||||||
|
const isStatusDismissed = checkIfAutoPilotStatusIsDismissed(
|
||||||
|
serviceDetails.fullyQualifiedName,
|
||||||
|
workflowStatesData?.mainInstanceState?.status
|
||||||
|
);
|
||||||
|
|
||||||
|
return isDataPresent && !isStatusDismissed;
|
||||||
|
}, [
|
||||||
|
isWorkflowStatusLoading,
|
||||||
|
workflowStatesData,
|
||||||
|
serviceDetails.fullyQualifiedName,
|
||||||
|
workflowStatesData?.mainInstanceState?.status,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const onStatusBannerClose = useCallback(() => {
|
||||||
|
if (
|
||||||
|
serviceDetails.fullyQualifiedName &&
|
||||||
|
workflowStatesData?.mainInstanceState?.status
|
||||||
|
) {
|
||||||
|
updateAutoPilotStatus({
|
||||||
|
serviceFQN: serviceDetails.fullyQualifiedName,
|
||||||
|
status: workflowStatesData?.mainInstanceState?.status,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
serviceDetails.fullyQualifiedName,
|
||||||
|
workflowStatesData?.mainInstanceState?.status,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="service-insights-tab" gutter={[16, 16]}>
|
<Row className="service-insights-tab" gutter={[16, 16]}>
|
||||||
{!isWorkflowStatusLoading && !isUndefined(workflowStatesData) && (
|
{showAutoPilotStatus && (
|
||||||
<Alert
|
<Alert
|
||||||
closable
|
closable
|
||||||
showIcon
|
showIcon
|
||||||
@ -163,6 +196,7 @@ const ServiceInsightsTab = ({
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
message={message}
|
message={message}
|
||||||
|
onClose={onStatusBannerClose}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{arrayOfWidgets.map(
|
{arrayOfWidgets.map(
|
||||||
|
@ -241,8 +241,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
getFeedCounts(EntityType.TOPIC, decodedTopicFQN, handleFeedCount);
|
getFeedCounts(EntityType.TOPIC, decodedTopicFQN, handleFeedCount);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -218,6 +218,7 @@ const DeleteWidgetModal = ({
|
|||||||
deleteType: values.deleteType,
|
deleteType: values.deleteType,
|
||||||
prepareType,
|
prepareType,
|
||||||
isRecursiveDelete: isRecursiveDelete ?? false,
|
isRecursiveDelete: isRecursiveDelete ?? false,
|
||||||
|
afterDeleteAction,
|
||||||
});
|
});
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
handleOnEntityDeleteCancel();
|
handleOnEntityDeleteCancel();
|
||||||
@ -234,6 +235,7 @@ const DeleteWidgetModal = ({
|
|||||||
isRecursiveDelete,
|
isRecursiveDelete,
|
||||||
handleOnEntityDeleteConfirm,
|
handleOnEntityDeleteConfirm,
|
||||||
handleOnEntityDeleteCancel,
|
handleOnEntityDeleteCancel,
|
||||||
|
afterDeleteAction,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 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 LOCAL_STORAGE_AUTO_PILOT_STATUS =
|
||||||
|
'serviceAutoPilotDismissedStatuses';
|
@ -24,6 +24,7 @@ export interface DeleteWidgetAsyncFormFields {
|
|||||||
deleteType: DeleteType;
|
deleteType: DeleteType;
|
||||||
prepareType: boolean;
|
prepareType: boolean;
|
||||||
isRecursiveDelete: boolean;
|
isRecursiveDelete: boolean;
|
||||||
|
afterDeleteAction?: (isSoftDelete?: boolean, version?: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AsyncDeleteContextType {
|
export interface AsyncDeleteContextType {
|
||||||
|
@ -30,6 +30,8 @@ jest.mock('../../rest/miscAPI', () => ({
|
|||||||
deleteAsyncEntity: jest.fn().mockImplementation(() => Promise.resolve()),
|
deleteAsyncEntity: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const mockAfterDeleteAction = jest.fn();
|
||||||
|
|
||||||
describe('AsyncDeleteProvider', () => {
|
describe('AsyncDeleteProvider', () => {
|
||||||
const mockResponse = {
|
const mockResponse = {
|
||||||
entityName: 'DELETE',
|
entityName: 'DELETE',
|
||||||
@ -95,6 +97,7 @@ describe('AsyncDeleteProvider', () => {
|
|||||||
mockError,
|
mockError,
|
||||||
'server.delete-entity-error'
|
'server.delete-entity-error'
|
||||||
);
|
);
|
||||||
|
expect(mockAfterDeleteAction).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle websocket response', async () => {
|
it('should handle websocket response', async () => {
|
||||||
@ -158,4 +161,18 @@ describe('AsyncDeleteProvider', () => {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should execute afterDeleteAction if present', async () => {
|
||||||
|
(deleteAsyncEntity as jest.Mock).mockResolvedValueOnce(mockResponse);
|
||||||
|
const { result } = renderHook(() => useAsyncDeleteProvider(), { wrapper });
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await result.current.handleOnAsyncEntityDeleteConfirm({
|
||||||
|
...mockDeleteParams,
|
||||||
|
afterDeleteAction: mockAfterDeleteAction,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockAfterDeleteAction).toHaveBeenCalledWith(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -46,6 +46,7 @@ const AsyncDeleteProvider = ({ children }: AsyncDeleteProviderProps) => {
|
|||||||
deleteType,
|
deleteType,
|
||||||
prepareType,
|
prepareType,
|
||||||
isRecursiveDelete,
|
isRecursiveDelete,
|
||||||
|
afterDeleteAction,
|
||||||
}: DeleteWidgetAsyncFormFields) => {
|
}: DeleteWidgetAsyncFormFields) => {
|
||||||
try {
|
try {
|
||||||
const response = await deleteAsyncEntity(
|
const response = await deleteAsyncEntity(
|
||||||
@ -73,6 +74,9 @@ const AsyncDeleteProvider = ({ children }: AsyncDeleteProviderProps) => {
|
|||||||
setAsyncDeleteJob(response);
|
setAsyncDeleteJob(response);
|
||||||
asyncDeleteJobRef.current = response;
|
asyncDeleteJobRef.current = response;
|
||||||
showSuccessToast(response.message);
|
showSuccessToast(response.message);
|
||||||
|
if (afterDeleteAction) {
|
||||||
|
afterDeleteAction(deleteType === DeleteType.SOFT_DELETE);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
error as AxiosError,
|
error as AxiosError,
|
||||||
|
@ -329,8 +329,7 @@ const APICollectionPage: FunctionComponent = () => {
|
|||||||
}, [currentVersion, decodedAPICollectionFQN]);
|
}, [currentVersion, decodedAPICollectionFQN]);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ const ContainerPage = () => {
|
|||||||
await fetchContainerDetail(containerFQN);
|
await fetchContainerDetail(containerFQN);
|
||||||
getEntityFeedCount();
|
getEntityFeedCount();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.asset-lowercase'),
|
entity: t('label.asset-lowercase'),
|
||||||
@ -364,8 +364,7 @@ const ContainerPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
decodedDatabaseFQN
|
decodedDatabaseFQN
|
||||||
);
|
);
|
||||||
setDatabasePermission(response);
|
setDatabasePermission(response);
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Error
|
// Error
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -368,8 +368,7 @@ const DatabaseDetails: FunctionComponent = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -332,8 +332,7 @@ const DatabaseSchemaPage: FunctionComponent = () => {
|
|||||||
}, [currentVersion, decodedDatabaseSchemaFQN]);
|
}, [currentVersion, decodedDatabaseSchemaFQN]);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ function SearchIndexDetailsPage() {
|
|||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
id: details.id,
|
id: details.id,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Error here
|
// Error here
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -482,8 +482,7 @@ function SearchIndexDetailsPage() {
|
|||||||
}, [version]);
|
}, [version]);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ import {
|
|||||||
} from '../../utils/date-time/DateTimeUtils';
|
} from '../../utils/date-time/DateTimeUtils';
|
||||||
import entityUtilClassBase from '../../utils/EntityUtilClassBase';
|
import entityUtilClassBase from '../../utils/EntityUtilClassBase';
|
||||||
import { getEntityFeedLink, getEntityName } from '../../utils/EntityUtils';
|
import { getEntityFeedLink, getEntityName } from '../../utils/EntityUtils';
|
||||||
|
import { removeAutoPilotStatus } from '../../utils/LocalStorageUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
import {
|
import {
|
||||||
getEditConnectionPath,
|
getEditConnectionPath,
|
||||||
@ -961,16 +962,18 @@ const ServiceDetailsPage: FunctionComponent = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => {
|
||||||
isSoftDelete
|
if (!isSoftDelete) {
|
||||||
? handleToggleDelete(version)
|
removeAutoPilotStatus(serviceDetails.fullyQualifiedName ?? '');
|
||||||
: history.push(
|
history.push(
|
||||||
getSettingPath(
|
getSettingPath(
|
||||||
GlobalSettingsMenuCategory.SERVICES,
|
GlobalSettingsMenuCategory.SERVICES,
|
||||||
getServiceRouteFromServiceType(serviceCategory)
|
getServiceRouteFromServiceType(serviceCategory)
|
||||||
)
|
)
|
||||||
),
|
);
|
||||||
[handleToggleDelete, serviceCategory]
|
}
|
||||||
|
},
|
||||||
|
[serviceCategory, serviceDetails.fullyQualifiedName]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRestoreService = useCallback(async () => {
|
const handleRestoreService = useCallback(async () => {
|
||||||
@ -1342,6 +1345,11 @@ const ServiceDetailsPage: FunctionComponent = () => {
|
|||||||
isWorkflowStatusLoading,
|
isWorkflowStatusLoading,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const afterAutoPilotAppTrigger = useCallback(() => {
|
||||||
|
removeAutoPilotStatus(serviceDetails.fullyQualifiedName ?? '');
|
||||||
|
fetchWorkflowInstanceStates();
|
||||||
|
}, [serviceDetails.fullyQualifiedName, fetchWorkflowInstanceStates]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
@ -1367,7 +1375,7 @@ const ServiceDetailsPage: FunctionComponent = () => {
|
|||||||
isRecursiveDelete
|
isRecursiveDelete
|
||||||
afterDeleteAction={afterDeleteAction}
|
afterDeleteAction={afterDeleteAction}
|
||||||
afterDomainUpdateAction={afterDomainUpdateAction}
|
afterDomainUpdateAction={afterDomainUpdateAction}
|
||||||
afterTriggerAction={fetchWorkflowInstanceStates}
|
afterTriggerAction={afterAutoPilotAppTrigger}
|
||||||
dataAsset={serviceDetails}
|
dataAsset={serviceDetails}
|
||||||
disableRunAgentsButton={disableRunAgentsButton}
|
disableRunAgentsButton={disableRunAgentsButton}
|
||||||
entityType={entityType}
|
entityType={entityType}
|
||||||
|
@ -130,7 +130,7 @@ const StoredProcedurePage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
setStoredProcedurePermissions(permission);
|
setStoredProcedurePermissions(permission);
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.resource-permission-lowercase'),
|
entity: t('label.resource-permission-lowercase'),
|
||||||
@ -358,8 +358,7 @@ const StoredProcedurePage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -445,7 +444,7 @@ const StoredProcedurePage = () => {
|
|||||||
const tabLabelMap = getTabLabelMapFromTabs(customizedPage?.tabs);
|
const tabLabelMap = getTabLabelMapFromTabs(customizedPage?.tabs);
|
||||||
|
|
||||||
const tabs = getStoredProcedureDetailsPageTabs({
|
const tabs = getStoredProcedureDetailsPageTabs({
|
||||||
activeTab: activeTab as EntityTabs,
|
activeTab,
|
||||||
feedCount,
|
feedCount,
|
||||||
decodedStoredProcedureFQN,
|
decodedStoredProcedureFQN,
|
||||||
entityName,
|
entityName,
|
||||||
|
@ -228,7 +228,7 @@ const TableDetailsPageV1: React.FC = () => {
|
|||||||
data.nodes?.filter((node) => node?.fullyQualifiedName !== tableFqn) ??
|
data.nodes?.filter((node) => node?.fullyQualifiedName !== tableFqn) ??
|
||||||
[];
|
[];
|
||||||
setDqFailureCount(updatedNodes.length);
|
setDqFailureCount(updatedNodes.length);
|
||||||
} catch (error) {
|
} catch {
|
||||||
setDqFailureCount(0);
|
setDqFailureCount(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -259,7 +259,7 @@ const TableDetailsPageV1: React.FC = () => {
|
|||||||
} else {
|
} else {
|
||||||
setDqFailureCount(failureCount);
|
setDqFailureCount(failureCount);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
setTestCaseSummary(undefined);
|
setTestCaseSummary(undefined);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -274,7 +274,7 @@ const TableDetailsPageV1: React.FC = () => {
|
|||||||
entityId: tableDetails.id,
|
entityId: tableDetails.id,
|
||||||
});
|
});
|
||||||
setQueryCount(response.paging.total);
|
setQueryCount(response.paging.total);
|
||||||
} catch (error) {
|
} catch {
|
||||||
setQueryCount(0);
|
setQueryCount(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -324,7 +324,7 @@ const TableDetailsPageV1: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
setTablePermissions(tablePermission);
|
setTablePermissions(tablePermission);
|
||||||
} catch (error) {
|
} catch {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
t('server.fetch-entity-permissions-error', {
|
t('server.fetch-entity-permissions-error', {
|
||||||
entity: t('label.resource-permission-lowercase'),
|
entity: t('label.resource-permission-lowercase'),
|
||||||
@ -664,8 +664,7 @@ const TableDetailsPageV1: React.FC = () => {
|
|||||||
}, [version, tableFqn]);
|
}, [version, tableFqn]);
|
||||||
|
|
||||||
const afterDeleteAction = useCallback(
|
const afterDeleteAction = useCallback(
|
||||||
(isSoftDelete?: boolean, version?: number) =>
|
(isSoftDelete?: boolean) => !isSoftDelete && history.push('/'),
|
||||||
isSoftDelete ? handleToggleDelete(version) : history.push('/'),
|
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 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 { WorkflowStatus } from '../generated/governance/workflows/workflowInstance';
|
||||||
|
|
||||||
|
export interface AutoPilotStatus {
|
||||||
|
serviceFQN: string;
|
||||||
|
status: WorkflowStatus;
|
||||||
|
}
|
@ -10,7 +10,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { LOCAL_STORAGE_AUTO_PILOT_STATUS } from '../constants/LocalStorage.constants';
|
||||||
import { OM_SESSION_KEY } from '../hooks/useApplicationStore';
|
import { OM_SESSION_KEY } from '../hooks/useApplicationStore';
|
||||||
|
import { AutoPilotStatus } from './LocalStorageUtils.interface';
|
||||||
|
|
||||||
export const getOidcToken = (): string => {
|
export const getOidcToken = (): string => {
|
||||||
return (
|
return (
|
||||||
@ -38,3 +40,38 @@ export const setRefreshToken = (token: string) => {
|
|||||||
session.refreshTokenKey = token;
|
session.refreshTokenKey = token;
|
||||||
localStorage.setItem(OM_SESSION_KEY, JSON.stringify(session));
|
localStorage.setItem(OM_SESSION_KEY, JSON.stringify(session));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAutoPilotStatuses = (): Array<AutoPilotStatus> => {
|
||||||
|
return JSON.parse(
|
||||||
|
localStorage.getItem(LOCAL_STORAGE_AUTO_PILOT_STATUS) ?? '[]'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateAutoPilotStatus = (workflowStatus: AutoPilotStatus) => {
|
||||||
|
const currentStatuses = getAutoPilotStatuses();
|
||||||
|
// Remove the status if it already exists for the serviceFQN
|
||||||
|
const filteredStatuses = currentStatuses.filter(
|
||||||
|
(status) => status.serviceFQN !== workflowStatus.serviceFQN
|
||||||
|
);
|
||||||
|
// Add the new status
|
||||||
|
const updatedStatuses: Array<AutoPilotStatus> = [
|
||||||
|
...filteredStatuses,
|
||||||
|
workflowStatus,
|
||||||
|
];
|
||||||
|
|
||||||
|
localStorage.setItem(
|
||||||
|
LOCAL_STORAGE_AUTO_PILOT_STATUS,
|
||||||
|
JSON.stringify(updatedStatuses)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeAutoPilotStatus = (serviceFQN: string) => {
|
||||||
|
const currentStatuses = getAutoPilotStatuses();
|
||||||
|
const filteredStatuses = currentStatuses.filter(
|
||||||
|
(status) => status.serviceFQN !== serviceFQN
|
||||||
|
);
|
||||||
|
localStorage.setItem(
|
||||||
|
LOCAL_STORAGE_AUTO_PILOT_STATUS,
|
||||||
|
JSON.stringify(filteredStatuses)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -36,6 +36,7 @@ import i18n from '../utils/i18next/LocalUtil';
|
|||||||
import { Transi18next } from './CommonUtils';
|
import { Transi18next } from './CommonUtils';
|
||||||
import documentationLinksClassBase from './DocumentationLinksClassBase';
|
import documentationLinksClassBase from './DocumentationLinksClassBase';
|
||||||
import Fqn from './Fqn';
|
import Fqn from './Fqn';
|
||||||
|
import { getAutoPilotStatuses } from './LocalStorageUtils';
|
||||||
|
|
||||||
const { t } = i18n;
|
const { t } = i18n;
|
||||||
|
|
||||||
@ -296,3 +297,19 @@ export const filterDistributionChartItem = (item: {
|
|||||||
|
|
||||||
return toLower(tag_name) === toLower(item.group);
|
return toLower(tag_name) === toLower(item.group);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const checkIfAutoPilotStatusIsDismissed = (
|
||||||
|
serviceFQN?: string,
|
||||||
|
workflowStatus?: WorkflowStatus
|
||||||
|
) => {
|
||||||
|
if (!serviceFQN || !workflowStatus) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const autoPilotStatuses = getAutoPilotStatuses();
|
||||||
|
|
||||||
|
return autoPilotStatuses.some(
|
||||||
|
(status) =>
|
||||||
|
status.serviceFQN === serviceFQN && status.status === workflowStatus
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user