Repository: datahub-project/datahub
Pull request #12950: fix(ui/incident): Add validation to restrict unauthorized edit or resolve
Author: login: amit-apptware
Labels: name: community-contribution
description: PR or Issue raised by member(s) of DataHub Community
name: product
description: PR or Issue related to the DataHub UI/UX
name: merge-pending-ci
description: A PR that has passed review and should be merged once CI is green.
Created: 2025-03-24T06:52:36Z | Merged: 2025-03-27T18:32:33Z

## Test cases

Tested with below scenarios on OSS for editing or resolving the incidents:

- Edit an incident by selecting its row from the table in the incident drawer.
- Attempt to resolve an incident by clicking the "Resolve" button in the table.

## Checklist

- [ ] The PR conforms to DataHub's [Contributing Guideline](https://github.com/datahub-project/datahub/blob/master/docs/CONTRIBUTING.md) (particularly [Commit Message Format](https://github.com/datahub-project/datahub/blob/master/docs/CONTRIBUTING.md#commit-message-format))
- [ ] Links to related issues (if applicable)
- [ ] Tests for the changes have been added/updated (if applicable)
- [ ] Docs related to the changes have been added/updated (if applicable). If a new feature has been added a Usage Guide has been added for the same.
- [ ] For any breaking change/potential downtime/deprecation/big changes an entry has been made in [Updating DataHub](https://github.com/datahub-project/datahub/blob/master/docs/how/updating-datahub.md)



Diff:
diff --git a/datahub-web-react/src/alchemy-components/components/Button/Button.tsx b/datahub-web-react/src/alchemy-components/components/Button/Button.tsx
index a41cdad05a6c81..8b2345b5805b2c 100644
--- a/datahub-web-react/src/alchemy-components/components/Button/Button.tsx
+++ b/datahub-web-react/src/alchemy-components/components/Button/Button.tsx
@@ -30,6 +30,8 @@ export const Button = ({
     isDisabled = buttonDefaults.isDisabled,
     isActive = buttonDefaults.isActive,
     children,
+    iconSource,
+    iconColor,
     ...props
 }: ButtonProps) => {
     const styleProps = {
@@ -52,9 +54,13 @@ export const Button = ({
 
     return (
         <ButtonBase {...styleProps} {...props}>
-            {icon && iconPosition === 'left' && <Icon icon={icon} size={iconSize || size} />}
+            {icon && iconPosition === 'left' && (
+                <Icon icon={icon} color={iconColor} size={iconSize || size} source={iconSource} />
+            )}
             {!isCircle && children}
-            {icon && iconPosition === 'right' && <Icon icon={icon} size={iconSize || size} />}
+            {icon && iconPosition === 'right' && (
+                <Icon icon={icon} color={iconColor} size={iconSize || size} source={iconSource} />
+            )}
         </ButtonBase>
     );
 };
diff --git a/datahub-web-react/src/alchemy-components/components/Button/types.ts b/datahub-web-react/src/alchemy-components/components/Button/types.ts
index 8e1ee6953a4938..214e094f5c7a89 100644
--- a/datahub-web-react/src/alchemy-components/components/Button/types.ts
+++ b/datahub-web-react/src/alchemy-components/components/Button/types.ts
@@ -2,6 +2,7 @@ import { ButtonHTMLAttributes } from 'react';
 
 import type { IconNames } from '@components';
 import type { SizeOptions, ColorOptions, FontSizeOptions } from '@components/theme/config';
+import { IconSource } from '../Icon/types';
 
 export type ButtonVariant = 'filled' | 'outline' | 'text';
 
@@ -21,6 +22,8 @@ export interface ButtonProps
         Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {
     icon?: IconNames;
     iconSize?: FontSizeOptions;
+    iconSource?: IconSource;
+    iconColor?: ColorOptions;
 }
 
 export type ButtonStyleProps = Omit<ButtonPropsDefaults, 'iconPosition'>;
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDetailDrawer.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDetailDrawer.tsx
index e84c3e800e94a1..582e79498ae2a9 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDetailDrawer.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDetailDrawer.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
 
 import { Drawer, Modal } from 'antd';
 import ClickOutside from '@src/app/shared/ClickOutside';
-import { Incident } from '@src/types.generated';
+import { EntityPrivileges, Incident } from '@src/types.generated';
 import { IncidentDrawerHeader } from './IncidentDrawerHeader';
 import { IncidentView } from './IncidentView';
 import { IncidentEditor } from './IncidentEditor';
@@ -18,9 +18,17 @@ type IncidentDetailDrawerProps = {
     onCancel?: () => void;
     onSubmit?: (incident?: Incident) => void;
     entity?: EntityStagedForIncident;
+    privileges?: EntityPrivileges;
 };
 
-export const IncidentDetailDrawer = ({ mode, onCancel, onSubmit, incident, entity }: IncidentDetailDrawerProps) => {
+export const IncidentDetailDrawer = ({
+    mode,
+    onCancel,
+    onSubmit,
+    incident,
+    entity,
+    privileges,
+}: IncidentDetailDrawerProps) => {
     const [isEditView, setIsEditView] = useState<boolean>(false);
     const showEditor = isEditView || mode === IncidentAction.CREATE;
     const modalClosePopup = () => {
@@ -57,6 +65,7 @@ export const IncidentDetailDrawer = ({ mode, onCancel, onSubmit, incident, entit
                     setIsEditActive={setIsEditView}
                     data={incident}
                     platform={entity?.platform}
+                    privileges={privileges}
                 />
                 {showEditor ? (
                     <IncidentEditor
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
index ff1a999578dbc3..e357b1c2716f86 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
@@ -1,12 +1,11 @@
 import React from 'react';
-import styled from 'styled-components';
-import { Link as LinkIcon, PencilSimpleLine, X } from '@phosphor-icons/react';
+import { Button } from '@src/alchemy-components';
 import { Tooltip2 } from '@src/alchemy-components/components/Tooltip2';
 import PlatformIcon from '@src/app/sharedV2/icons/PlatformIcon';
 import { capitalizeFirstLetter } from '@src/app/shared/textUtil';
-import { DataPlatform } from '@src/types.generated';
+import { DataPlatform, EntityPrivileges } from '@src/types.generated';
 import { useIncidentURNCopyLink } from '../hooks';
-import { IncidentAction } from '../constant';
+import { IncidentAction, noPermissionsMessage } from '../constant';
 import { IncidentTableRow } from '../types';
 import {
     ForPlatformWrapper,
@@ -16,24 +15,6 @@ import {
     StyledTitle,
 } from './styledComponents';
 
-const EditButton = styled(PencilSimpleLine)`
-    :hover {
-        cursor: pointer;
-    }
-`;
-
-const CloseButton = styled(X)`
-    :hover {
-        cursor: pointer;
-    }
-`;
-
-const LinkButton = styled(LinkIcon)`
-    :hover {
-        cursor: pointer;
-    }
-`;
-
 type IncidentDrawerHeaderProps = {
     mode: IncidentAction;
     onClose?: () => void;
@@ -41,6 +22,7 @@ type IncidentDrawerHeaderProps = {
     setIsEditActive: React.Dispatch<React.SetStateAction<boolean>>;
     data?: IncidentTableRow;
     platform?: DataPlatform;
+    privileges?: EntityPrivileges;
 };
 
 export const IncidentDrawerHeader = ({
@@ -50,12 +32,18 @@ export const IncidentDrawerHeader = ({
     setIsEditActive,
     data,
     platform,
+    privileges,
 }: IncidentDrawerHeaderProps) => {
     const handleIncidentLinkCopy = useIncidentURNCopyLink(data ? data?.urn : '');
+
+    const canEditIncidents = privileges?.canEditIncidents || false;
+
     return (
         <StyledHeader>
             <StyledHeaderTitleContainer>
-                <StyledTitle>{mode === IncidentAction.CREATE ? 'Create New Incident' : data?.title}</StyledTitle>
+                <StyledTitle data-testid="drawer-header-title">
+                    {mode === IncidentAction.CREATE ? 'Create New Incident' : data?.title}
+                </StyledTitle>
                 {platform && (
                     <ForPlatformWrapper>
                         <PlatformIcon platform={platform} size={16} styles={{ marginRight: 4 }} />
@@ -66,19 +54,41 @@ export const IncidentDrawerHeader = ({
             <StyledHeaderActions>
                 {mode === IncidentAction.EDIT && isEditActive === false && (
                     <>
-                        <Tooltip2 title="Edit Incident">
-                            <EditButton
-                                size={20}
-                                onClick={() => setIsEditActive(!isEditActive)}
-                                data-testid="edit-incident-icon"
-                            />
+                        <Tooltip2 title={canEditIncidents ? 'Edit Incident' : noPermissionsMessage}>
+                            <span>
+                                <Button
+                                    icon="PencilSimpleLine"
+                                    variant="text"
+                                    iconColor="gray"
+                                    iconSource="phosphor"
+                                    onClick={() => setIsEditActive(!isEditActive)}
+                                    disabled={!canEditIncidents}
+                                    data-testid="edit-incident-icon"
+                                    size="xl"
+                                />
+                            </span>
                         </Tooltip2>
                         <Tooltip2 title="Copy Link">
-                            <LinkButton size={20} onClick={handleIncidentLinkCopy} />
+                            <Button
+                                icon="Link"
+                                variant="text"
+                                iconColor="gray"
+                                iconSource="phosphor"
+                                onClick={handleIncidentLinkCopy}
+                                size="xl"
+                            />
                         </Tooltip2>
                     </>
                 )}
-                <CloseButton size={20} onClick={() => onClose?.()} data-testid="incident-drawer-close-button" />
+                <Button
+                    icon="X"
+                    variant="text"
+                    iconColor="gray"
+                    iconSource="phosphor"
+                    onClick={() => onClose?.()}
+                    data-testid="incident-drawer-close-button"
+                    size="xl"
+                />
             </StyledHeaderActions>
         </StyledHeader>
     );
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentList.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentList.tsx
index a2ecd819326e8f..4297bc65e47e10 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentList.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentList.tsx
@@ -88,6 +88,7 @@ export const IncidentList = () => {
                     refetch={() => {
                         refetch();
                     }}
+                    privileges={privileges}
                 />
             );
         }
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentListTable.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentListTable.tsx
index d0445929a88301..1f02e1c8dd8c6e 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentListTable.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentListTable.tsx
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
 import { useEntityData } from '@src/app/entity/shared/EntityContext';
 import { Table } from '@src/alchemy-components';
 import { SortingState } from '@src/alchemy-components/components/Table/types';
+import { EntityPrivileges } from '@src/types.generated';
 import { IncidentDetailDrawer } from './AcrylComponents/IncidentDetailDrawer';
 import { IncidentListFilter, IncidentTable, IncidentTableRow } from './types';
 import { useIncidentsTableColumns, useOpenIncidentDetailModal } from './hooks';
@@ -15,9 +16,10 @@ type Props = {
     incidentData: IncidentTable;
     filter: IncidentListFilter;
     refetch: () => void;
+    privileges?: EntityPrivileges;
 };
 
-export const IncidentListTable = ({ incidentData, filter, refetch }: Props) => {
+export const IncidentListTable = ({ incidentData, filter, refetch, privileges }: Props) => {
     const { entityData } = useEntityData();
     const { groupBy } = filter;
 
@@ -29,7 +31,7 @@ export const IncidentListTable = ({ incidentData, filter, refetch }: Props) => {
     );
 
     // get columns data from the custom hooks
-    const incidentsTableCols = useIncidentsTableColumns();
+    const incidentsTableCols = useIncidentsTableColumns(privileges);
     const [sortedOptions, setSortedOptions] = useState<{ sortColumn: string; sortOrder: SortingState }>({
         sortColumn: '',
         sortOrder: SortingState.ORIGINAL,
@@ -138,6 +140,7 @@ export const IncidentListTable = ({ incidentData, filter, refetch }: Props) => {
                     urn={focusIncidentUrn}
                     mode={IncidentAction.EDIT}
                     incident={focusIncidentData}
+                    privileges={privileges}
                     onCancel={() => setFocusIncidentUrn(null)}
                     onSubmit={() => {
                         setTimeout(() => {
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx
index bf4e6d4d4502d7..516e6f329e9d9f 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx
@@ -1,5 +1,6 @@
 import React, { useEffect, useState } from 'react';
-import { CorpUser, IncidentState } from '@src/types.generated';
+import { Tooltip } from 'antd';
+import { CorpUser, EntityPrivileges, IncidentState } from '@src/types.generated';
 import { Button, colors, Pill, Popover } from '@src/alchemy-components';
 import { useGetEntitiesLazyQuery } from '@src/graphql/entity.generated';
 import { Check } from '@phosphor-icons/react';
@@ -12,6 +13,7 @@ import { IncidentTableRow } from './types';
 import { IncidentResolutionPopup } from './IncidentResolutionPopup';
 import { LoadingWrapper } from './AcrylComponents/styledComponents';
 import { ResolvedSection } from './ResolvedSection';
+import { noPermissionsMessage } from './constant';
 
 const ME = 'Me';
 
@@ -26,7 +28,15 @@ const ResolveButton = styled(Button)`
     padding: 0px;
 `;
 
-export const IncidentResolveButton = ({ incident }: { incident: IncidentTableRow }) => {
+export const IncidentResolveButton = ({
+    incident,
+    privileges,
+}: {
+    incident: IncidentTableRow;
+    privileges?: EntityPrivileges;
+}) => {
+    const canEditIncidents = privileges?.canEditIncidents || false;
+
     const me = useUserContext();
     const [showResolvePopup, setShowResolvePopup] = useState(false);
     const [incidentResolver, setIncidentResolver] = useState<CorpUser | any>(null);
@@ -113,9 +123,11 @@ export const IncidentResolveButton = ({ incident }: { incident: IncidentTableRow
             data-testid="incident-resolve-button-container"
         >
             {incident?.state === IncidentState.Active ? (
-                <ResolveButton variant="text" onClick={handleShowPopup}>
-                    Resolve
-                </ResolveButton>
+                <Tooltip showArrow={false} title={!canEditIncidents ? noPermissionsMessage : null}>
+                    <ResolveButton disabled={!canEditIncidents} variant="text" onClick={handleShowPopup}>
+                        Resolve
+                    </ResolveButton>
+                </Tooltip>
             ) : (
                 showPopoverWithResolver
             )}
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/constant.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/constant.ts
index 51b85e99a4f477..79cda2ed4d5aab 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/constant.ts
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/constant.ts
@@ -220,3 +220,5 @@ export const STAGE_ORDER = [
 export const STATE_ORDER = [INCIDENT_STATE_NAME_MAP.ACTIVE, INCIDENT_STATE_NAME_MAP.RESOLVED];
 
 export const MAX_VISIBLE_ASSIGNEE = 5;
+
+export const noPermissionsMessage = 'You do not have permission to edit incidents for this asset.';
diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/hooks.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/hooks.tsx
index ae6ac72a37288f..4732398b8411e5 100644
--- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/hooks.tsx
+++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/hooks.tsx
@@ -8,14 +8,14 @@ import { IncidentPriorityLabel } from '@src/alchemy-components/components/Incide
 import { getCapitalizeWord } from '@src/alchemy-components/components/IncidentStagePill/utils';
 import { AlignmentOptions } from '@src/alchemy-components/theme/config';
 import { useEntityRegistryV2 } from '@src/app/useEntityRegistry';
-import { CorpUser } from '@src/types.generated';
+import { CorpUser, EntityPrivileges } from '@src/types.generated';
 import { getQueryParams } from '../Dataset/Validations/assertionUtils';
 import { getAssigneeNamesWithAvatarUrl, getLinkedAssetsCount } from './utils';
 import { IncidentResolveButton } from './IncidentResolveButton';
 import { IncidentAssigneeAvatarStack } from './IncidentAssigneeAvatarStack';
 import { CategoryType } from './styledComponents';
 
-export const useIncidentsTableColumns = () => {
+export const useIncidentsTableColumns = (privileges?: EntityPrivileges) => {
     return useMemo(() => {
         const columns = [
             {
@@ -107,13 +107,13 @@ export const useIncidentsTableColumns = () => {
                 key: 'actions',
                 width: '15%',
                 render: (record) => {
-                    return !record.groupName && <IncidentResolveButton incident={record} />;
+                    return !record.groupName && <IncidentResolveButton incident={record} privileges={privileges} />;
                 },
                 alignment: 'right' as AlignmentOptions,
             },
         ];
         return columns;
-    }, []);
+    }, [privileges]);
 };
 
 export const useIncidentURNCopyLink = (Urn: string) => {


Reviews:
user: login: jjoyce0510
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-26T01:42:38Z
user: login: jjoyce0510
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T01:44:21Z
user: login: jjoyce0510
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T01:44:37Z
user: login: jjoyce0510
body: As a final check, make sure that the "Create incident" button ALSO has this handling.

... And if you have a tooltip 
<Button disabled={!canEditIncidents}>Create Incident</Button> 
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T01:45:21Z
user: login: jjoyce0510
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T02:09:54Z
user: login: jjoyce0510
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T02:11:08Z
user: login: jjoyce0510
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T17:19:22Z
user: login: jjoyce0510
body: Let's get this one in - Important for us to do. 
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-27T17:19:42Z
user: login: amit-apptware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T17:35:13Z

Review comments:
diff_hunk: @@ -50,7 +56,7 @@ export const IncidentDrawerHeader = ({
                         <Tooltip2 title="Edit Incident">
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
user: login: jjoyce0510
body: here you should say:

<Tooltip2 title={canEditIncidents ? "Edit Incident" : noPermissionMessage} />
created_at: 2025-03-26T01:44:21Z
author_association: COLLABORATOR
diff_hunk: @@ -50,7 +56,7 @@ export const IncidentDrawerHeader = ({
                         <Tooltip2 title="Edit Incident">
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
user: login: jjoyce0510
body: Also, should make the button type / state = Disabled. So the user cannot click it 
created_at: 2025-03-26T01:44:36Z
author_association: COLLABORATOR
diff_hunk: @@ -39,27 +41,32 @@ export const IncidentDrawerHeader = ({
     isEditActive,
     setIsEditActive,
     data,
+    privileges,
 }: IncidentDrawerHeaderProps) => {
     const handleIncidentLinkCopy = useIncidentURNCopyLink(data ? data?.urn : '');
+
+    const canEditIncidents = privileges?.canEditIncidents || false;
+
     return (
         <StyledHeader>
             <StyledTitle>{mode === IncidentAction.ADD ? 'Create New Incident' : data?.title}</StyledTitle>
             <StyledHeaderActions>
                 {mode === IncidentAction.VIEW && isEditActive === false && (
                     <>
-                        <Tooltip2 title="Edit Incident">
-                            <EditButton
+                        <Tooltip2 title={canEditIncidents ? 'Edit Incident' : noPermissionsMessage}>
+                            <EditIcon
                                 size={20}
-                                onClick={() => setIsEditActive(!isEditActive)}
+                                onClick={() => canEditIncidents && setIsEditActive(!isEditActive)}
                                 data-testid="edit-incident-icon"
+                                aria-disabled={!canEditIncidents}
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
user: login: jjoyce0510
body: You can remove this if it doesn't change anything about the icon. 
created_at: 2025-03-27T02:09:54Z
author_association: COLLABORATOR
diff_hunk: @@ -2,24 +2,25 @@ import React from 'react';
 import { Link as LinkIcon, PencilSimpleLine, X } from '@phosphor-icons/react';
 import styled from 'styled-components';
 import { Tooltip2 } from '@src/alchemy-components/components/Tooltip2';
+import { EntityPrivileges } from '@src/types.generated';
 import { useIncidentURNCopyLink } from '../hooks';
-import { IncidentAction } from '../constant';
+import { IncidentAction, noPermissionsMessage } from '../constant';
 import { IncidentTableRow } from '../types';
 import { StyledHeader, StyledHeaderActions, StyledTitle } from './styledComponents';
 
-const EditButton = styled(PencilSimpleLine)`
+const EditIcon = styled(PencilSimpleLine)`
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/IncidentDrawerHeader.tsx
user: login: jjoyce0510
body: You can also try to use our button component as a wrapper

// Option 1: 
<Button icon={icon} disabled={!canEditIncidents} /> 

// Option 2: 
<Button disabled={!canEditIncidents}>
    {icon} 
</Button>

created_at: 2025-03-27T02:11:08Z
author_association: COLLABORATOR
diff_hunk: @@ -113,9 +123,11 @@ export const IncidentResolveButton = ({ incident }: { incident: IncidentTableRow
             data-testid="incident-resolve-button-container"
         >
             {incident?.state === IncidentState.Active ? (
-                <ResolveButton variant="text" onClick={handleShowPopup}>
-                    Resolve
-                </ResolveButton>
+                <Tooltip showArrow={false} title={(!canEditIncidents && noPermissionsMessage) || null}>
+                    <ResolveButton variant="text" onClick={() => canEditIncidents && handleShowPopup()}>
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx
user: login: jjoyce0510
body: A bit weird to do this &&...

Remember we prefer ? : ternary
created_at: 2025-03-27T17:19:22Z
author_association: COLLABORATOR
diff_hunk: @@ -113,9 +123,11 @@ export const IncidentResolveButton = ({ incident }: { incident: IncidentTableRow
             data-testid="incident-resolve-button-container"
         >
             {incident?.state === IncidentState.Active ? (
-                <ResolveButton variant="text" onClick={handleShowPopup}>
-                    Resolve
-                </ResolveButton>
+                <Tooltip showArrow={false} title={(!canEditIncidents && noPermissionsMessage) || null}>
+                    <ResolveButton variant="text" onClick={() => canEditIncidents && handleShowPopup()}>
path: datahub-web-react/src/app/entityV2/shared/tabs/Incident/IncidentResolveButton.tsx
user: login: amit-apptware
body: Done
created_at: 2025-03-27T17:35:13Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-24T07:13:58Z
body: ## [Codecov](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) Report
Attention: Patch coverage is `41.17647%` with `30 lines` in your changes missing coverage. Please review.

| [Files with missing lines](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) | Patch % | Lines |
|---|---|---|
| [...yV2/shared/tabs/Incident/IncidentResolveButton.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FIncidentResolveButton.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9JbmNpZGVudFJlc29sdmVCdXR0b24udHN4) | 23.52% | [13 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [.../Incident/AcrylComponents/IncidentDrawerHeader.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FAcrylComponents%2FIncidentDrawerHeader.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9BY3J5bENvbXBvbmVudHMvSW5jaWRlbnREcmF3ZXJIZWFkZXIudHN4) | 37.50% | [10 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [...ntityV2/shared/tabs/Incident/IncidentListTable.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FIncidentListTable.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9JbmNpZGVudExpc3RUYWJsZS50c3g=) | 60.00% | [2 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [...ct/src/app/entityV2/shared/tabs/Incident/hooks.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2Fhooks.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9ob29rcy50c3g=) | 50.00% | [2 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [.../Incident/AcrylComponents/IncidentDetailDrawer.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FAcrylComponents%2FIncidentDetailDrawer.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9BY3J5bENvbXBvbmVudHMvSW5jaWRlbnREZXRhaWxEcmF3ZXIudHN4) | 75.00% | [1 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [...app/entityV2/shared/tabs/Incident/IncidentList.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FIncidentList.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9JbmNpZGVudExpc3QudHN4) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |
| [...V2/shared/tabs/Incident/IncidentTitleContainer.tsx](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&filepath=datahub-web-react%2Fsrc%2Fapp%2FentityV2%2Fshared%2Ftabs%2FIncident%2FIncidentTitleContainer.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project#diff-ZGF0YWh1Yi13ZWItcmVhY3Qvc3JjL2FwcC9lbnRpdHlWMi9zaGFyZWQvdGFicy9JbmNpZGVudC9JbmNpZGVudFRpdGxlQ29udGFpbmVyLnRzeA==) | 50.00% | [1 Missing :warning: ](https://app.codecov.io/gh/datahub-project/datahub/pull/12950?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project) |

:x: Your patch check has failed because the patch coverage (41.17%) is below the target coverage (75.00%). You can increase the patch coverage or adjust the [target](https://docs.codecov.com/docs/commit-status#target) coverage.


:loudspeaker: Thoughts on this report? [Let us know!](https://about.codecov.io/pull-request-comment-report/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=datahub-project)

<details><summary> :rocket: New features to boost your workflow: </summary>

- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: jjoyce0510
created_at: 2025-03-27T02:11:31Z
body: There are some conflicts to resolve
author_association: COLLABORATOR