Minor: address feedback for incident manager feature (#14955)

This commit is contained in:
Shailesh Parmar 2024-01-30 23:25:50 +05:30 committed by GitHub
parent 686dbed964
commit 728a71ee5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 74 additions and 55 deletions

View File

@ -269,7 +269,10 @@ describe('Incident Manager', () => {
verifyResponseStatusCode('@getTestCase', 200); verifyResponseStatusCode('@getTestCase', 200);
cy.get('[data-testid="incident"]').click(); cy.get('[data-testid="incident"]').click();
verifyResponseStatusCode('@getTaskFeed', 200); verifyResponseStatusCode('@getTaskFeed', 200);
cy.get('[data-testid="reject-task"]').scrollIntoView().click(); cy.get('[data-testid="task-cta-buttons"]')
.contains('Reassign')
.scrollIntoView()
.click();
interceptURL( interceptURL(
'GET', 'GET',
'/api/v1/search/suggest?q=admin&index=*user_search_index*', '/api/v1/search/suggest?q=admin&index=*user_search_index*',
@ -286,12 +289,12 @@ describe('Incident Manager', () => {
cy.get('.ant-modal-footer').contains('Submit').click(); cy.get('.ant-modal-footer').contains('Submit').click();
verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200); verifyResponseStatusCode('@updateTestCaseIncidentStatus', 200);
// Todo: skipping this for now as its not working from backend // Todo: skipping this for now as its not working from backend
// cy.clickOnLogo(); cy.clickOnLogo();
// cy.get('[id*="tab-tasks"]').click(); cy.get('[id*="tab-tasks"]').click();
// cy.get('[data-testid="task-feed-card"]') cy.get('[data-testid="task-feed-card"]')
// .contains(NEW_TABLE_TEST_CASE.name) .contains(testCaseName)
// .scrollIntoView() .scrollIntoView()
// .should('be.visible'); .should('be.visible');
}); });
it('Resolve incident', () => { it('Resolve incident', () => {
@ -306,7 +309,10 @@ describe('Incident Manager', () => {
verifyResponseStatusCode('@getTestCase', 200); verifyResponseStatusCode('@getTestCase', 200);
cy.get('[data-testid="incident"]').click(); cy.get('[data-testid="incident"]').click();
verifyResponseStatusCode('@getTaskFeed', 200); verifyResponseStatusCode('@getTaskFeed', 200);
cy.get('[data-testid="approve-task"]').scrollIntoView().click(); cy.get('[data-testid="task-cta-buttons"] [role="img"]')
.scrollIntoView()
.click();
cy.get('[role="menu"').find('[data-menu-id*="resolve"]').click();
cy.get('#testCaseFailureReason').click(); cy.get('#testCaseFailureReason').click();
cy.get('[title="Missing Data"]').click(); cy.get('[title="Missing Data"]').click();
cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror') cy.get('.toastui-editor-md-container > .toastui-editor > .ProseMirror')

View File

@ -89,11 +89,11 @@ jest.mock('../../../utils/FeedUtils', () => ({
})); }));
jest.mock('../../../utils/TasksUtils', () => ({ jest.mock('../../../utils/TasksUtils', () => ({
...jest.requireActual('../../../utils/TasksUtils'),
fetchOptions: jest.fn().mockReturnValue('getEntityLink'), fetchOptions: jest.fn().mockReturnValue('getEntityLink'),
getTaskDetailPath: jest.fn().mockReturnValue('/'), getTaskDetailPath: jest.fn().mockReturnValue('/'),
isDescriptionTask: jest.fn().mockReturnValue(false), isDescriptionTask: jest.fn().mockReturnValue(false),
isTagsTask: jest.fn().mockReturnValue(true), isTagsTask: jest.fn().mockReturnValue(true),
TASK_ACTION_LIST: jest.fn().mockReturnValue([]),
generateOptions: jest.fn().mockReturnValue([]), generateOptions: jest.fn().mockReturnValue([]),
})); }));

View File

@ -83,6 +83,7 @@ import {
fetchOptions, fetchOptions,
generateOptions, generateOptions,
getTaskDetailPath, getTaskDetailPath,
INCIDENT_TASK_ACTION_LIST,
isDescriptionTask, isDescriptionTask,
isTagsTask, isTagsTask,
TASK_ACTION_LIST, TASK_ACTION_LIST,
@ -133,7 +134,11 @@ export const TaskTab = ({
testCaseResolutionStatus, testCaseResolutionStatus,
initialAssignees: usersList, initialAssignees: usersList,
} = useActivityFeedProvider(); } = useActivityFeedProvider();
const [taskAction, setTaskAction] = useState<TaskAction>(TASK_ACTION_LIST[0]); const isTaskTestCaseResult =
taskDetails?.type === TaskType.RequestTestCaseFailureResolution;
const [taskAction, setTaskAction] = useState<TaskAction>(
isTaskTestCaseResult ? INCIDENT_TASK_ACTION_LIST[0] : TASK_ACTION_LIST[0]
);
const isTaskClosed = isEqual(taskDetails?.status, ThreadTaskStatus.Closed); const isTaskClosed = isEqual(taskDetails?.status, ThreadTaskStatus.Closed);
const [showEditTaskModel, setShowEditTaskModel] = useState(false); const [showEditTaskModel, setShowEditTaskModel] = useState(false);
const [comment, setComment] = useState(''); const [comment, setComment] = useState('');
@ -185,8 +190,6 @@ export const TaskTab = ({
const isTaskDescription = isDescriptionTask(taskDetails?.type as TaskType); const isTaskDescription = isDescriptionTask(taskDetails?.type as TaskType);
const isTaskTags = isTagsTask(taskDetails?.type as TaskType); const isTaskTags = isTagsTask(taskDetails?.type as TaskType);
const isTaskTestCaseResult =
taskDetails?.type === TaskType.RequestTestCaseFailureResolution;
const isTaskGlossaryApproval = taskDetails?.type === TaskType.RequestApproval; const isTaskGlossaryApproval = taskDetails?.type === TaskType.RequestApproval;
@ -408,6 +411,31 @@ export const TaskTab = ({
} }
}; };
const handleTaskMenuClick = (info: MenuInfo) => {
setTaskAction(
INCIDENT_TASK_ACTION_LIST.find((action) => action.key === info.key) ??
INCIDENT_TASK_ACTION_LIST[0]
);
switch (info.key) {
case TaskActionMode.RE_ASSIGN:
setIsEditAssignee(true);
break;
case TaskActionMode.RESOLVE:
setShowEditTaskModel(true);
break;
}
};
const onTaskDropdownClick = () => {
if (taskAction.key === TaskActionMode.RESOLVE) {
setShowEditTaskModel(true);
} else {
handleTaskMenuClick({ key: taskAction.key } as MenuInfo);
}
};
const approvalWorkflowActions = useMemo(() => { const approvalWorkflowActions = useMemo(() => {
const hasApprovalAccess = const hasApprovalAccess =
isAssignee || (Boolean(isPartOfAssigneeTeam) && !isCreator); isAssignee || (Boolean(isPartOfAssigneeTeam) && !isCreator);
@ -458,33 +486,23 @@ export const TaskTab = ({
const hasApprovalAccess = isAssignee || isCreator || editPermission; const hasApprovalAccess = isAssignee || isCreator || editPermission;
return ( return (
<Space <Dropdown.Button
className="m-t-sm items-end w-full" className="m-t-sm"
data-testid="task-cta-buttons" data-testid="task-cta-buttons"
size="small"> icon={<DownOutlined />}
<Tooltip menu={{
title={!hasApprovalAccess && t('message.no-access-placeholder')}> items: INCIDENT_TASK_ACTION_LIST,
<Button selectable: true,
data-testid="reject-task" selectedKeys: [taskAction.key],
disabled={!hasApprovalAccess} onClick: handleTaskMenuClick,
onClick={() => setIsEditAssignee(true)}> disabled: !hasApprovalAccess,
{t('label.re-assign')} }}
</Button>
</Tooltip>
<Tooltip
title={!hasApprovalAccess && t('message.no-access-placeholder')}>
<Button
data-testid="approve-task"
disabled={!hasApprovalAccess}
type="primary" type="primary"
onClick={() => setShowEditTaskModel(true)}> onClick={onTaskDropdownClick}>
{t('label.resolve')} {taskAction.label}
</Button> </Dropdown.Button>
</Tooltip>
</Space>
); );
}, [taskDetails, isAssignee, isPartOfAssigneeTeam]); }, [taskDetails, isAssignee, isPartOfAssigneeTeam, taskAction]);
const actionButtons = useMemo(() => { const actionButtons = useMemo(() => {
if (isTaskClosed) { if (isTaskClosed) {

View File

@ -22,7 +22,6 @@ import {
useState, useState,
} from 'react'; } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { import {
Area, Area,
AreaChart, AreaChart,
@ -35,7 +34,6 @@ import {
import { ReactComponent as TotalDataAssetsEmptyIcon } from '../../assets/svg/data-insight-no-data-placeholder.svg'; import { ReactComponent as TotalDataAssetsEmptyIcon } from '../../assets/svg/data-insight-no-data-placeholder.svg';
import { CHART_WIDGET_DAYS_DURATION } from '../../constants/constants'; import { CHART_WIDGET_DAYS_DURATION } from '../../constants/constants';
import { TOTAL_ENTITY_CHART_COLOR } from '../../constants/DataInsight.constants'; import { TOTAL_ENTITY_CHART_COLOR } from '../../constants/DataInsight.constants';
import { DATA_INSIGHT_GUIDE_DOCS } from '../../constants/docs.constants';
import { SIZE } from '../../enums/common.enum'; import { SIZE } from '../../enums/common.enum';
import { WidgetWidths } from '../../enums/CustomizablePage.enum'; import { WidgetWidths } from '../../enums/CustomizablePage.enum';
import { DataReportIndex } from '../../generated/dataInsight/dataInsightChart'; import { DataReportIndex } from '../../generated/dataInsight/dataInsightChart';
@ -45,7 +43,6 @@ import {
} from '../../generated/dataInsight/dataInsightChartResult'; } from '../../generated/dataInsight/dataInsightChartResult';
import { getAggregateChartData } from '../../rest/DataInsightAPI'; import { getAggregateChartData } from '../../rest/DataInsightAPI';
import { axisTickFormatter } from '../../utils/ChartUtils'; import { axisTickFormatter } from '../../utils/ChartUtils';
import { Transi18next } from '../../utils/CommonUtils';
import { getGraphDataByEntityType } from '../../utils/DataInsightUtils'; import { getGraphDataByEntityType } from '../../utils/DataInsightUtils';
import { import {
getCurrentMillis, getCurrentMillis,
@ -151,21 +148,6 @@ const TotalDataAssetsWidget = ({
width={SIZE.X_SMALL} width={SIZE.X_SMALL}
/> />
} }
message={
<Transi18next
i18nKey="message.no-total-data-assets"
renderElement={
<Link
rel="noreferrer"
target="_blank"
to={{ pathname: DATA_INSIGHT_GUIDE_DOCS }}
/>
}
values={{
setup: t('message.setup-data-insights'),
}}
/>
}
/> />
</Col> </Col>
</Row> </Row>

View File

@ -59,6 +59,8 @@ export interface TaskAction {
export enum TaskActionMode { export enum TaskActionMode {
VIEW = 'view', VIEW = 'view',
EDIT = 'edit', EDIT = 'edit',
RE_ASSIGN = 're-assign',
RESOLVE = 'resolve',
} }
export enum TaskTabs { export enum TaskTabs {

View File

@ -567,6 +567,17 @@ export const TASK_ACTION_LIST: TaskAction[] = [
}, },
]; ];
export const INCIDENT_TASK_ACTION_LIST: TaskAction[] = [
{
label: i18Next.t('label.re-assign'),
key: TaskActionMode.RE_ASSIGN,
},
{
label: i18Next.t('label.resolve'),
key: TaskActionMode.RESOLVE,
},
];
export const isDescriptionTask = (taskType: TaskType) => export const isDescriptionTask = (taskType: TaskType) =>
[TaskType.RequestDescription, TaskType.UpdateDescription].includes(taskType); [TaskType.RequestDescription, TaskType.UpdateDescription].includes(taskType);