Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const isVisible = async (locator: Locator) =>

const expectIncidentTableRowsToContain = async (page: Page, text: string) => {
const rows = page.locator(
'.ant-table-tbody tr:not(.ant-table-measure-row):not(.ant-table-placeholder)'
'[data-testid="test-case-incident-manager-table"] tbody tr'
);
const rowCount = await rows.count();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type IncidentStatusPopoverShellProps = {
dataTestid: string;
trigger: ReactNode;
children: ReactNode;
popoverClassName?: string;
};

export const IncidentStatusPopoverShell = ({
Expand All @@ -30,10 +31,14 @@ export const IncidentStatusPopoverShell = ({
dataTestid,
trigger,
children,
popoverClassName,
}: IncidentStatusPopoverShellProps) => (
<PopoverTrigger isOpen={isOpen} onOpenChange={onOpenChange}>
{trigger}
<Popover containerClassName={containerClassName} data-testid={dataTestid}>
<Popover
className={popoverClassName}
containerClassName={containerClassName}
data-testid={dataTestid}>
{children}
</Popover>
</PopoverTrigger>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ const InlineTestCaseIncidentStatus = ({
containerClassName="tw:max-h-[500px] tw:min-w-0 tw:w-[320px] tw:border tw:border-border-secondary"
dataTestid={`${data.testCaseReference?.name}-assignee-popover`}
isOpen={showAssigneePopover}
popoverClassName="tw:!max-h-none"
trigger={renderStatusChipButton()}
onOpenChange={(open) => {
if (open) {
Expand All @@ -586,9 +587,10 @@ const InlineTestCaseIncidentStatus = ({
if (showResolvedPopover) {
return (
<IncidentStatusPopoverShell
containerClassName="tw:min-w-0 tw:w-[320px] tw:border tw:border-border-secondary"
containerClassName="tw:min-w-0 tw:w-80 tw:overflow-y-auto tw:border tw:border-border-secondary"
dataTestid={`${data.testCaseReference?.name}-resolved-popover`}
isOpen={showResolvedPopover}
popoverClassName="tw:!max-h-none"
trigger={renderStatusChipButton()}
onOpenChange={(open) => {
if (!open) {
Expand All @@ -611,7 +613,7 @@ const InlineTestCaseIncidentStatus = ({
onOpenChange={handleStatusMenuOpenChange}>
{renderStatusChipButton()}
<Dropdown.Popover
className="tw:min-w-[100px] tw:w-max tw:overflow-auto"
className="tw:min-w-25 tw:w-max tw:overflow-auto"
placement="top">
{statusMenuItems}
</Dropdown.Popover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Button, Dropdown, Skeleton } from '@openmetadata/ui-core-components';
import {
Button,
Dropdown,
Skeleton,
Table,
} from '@openmetadata/ui-core-components';
import { Form, Select } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch';
import { isEqual, isString, isUndefined, omit, parseInt, pick } from 'lodash';
Expand Down Expand Up @@ -75,9 +79,9 @@ import DateTimeDisplay from '../common/DateTimeDisplay/DateTimeDisplay';
import ErrorPlaceHolder from '../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import FilterTablePlaceHolder from '../common/ErrorWithPlaceholder/FilterTablePlaceHolder';
import MuiDatePickerMenu from '../common/MuiDatePickerMenu/MuiDatePickerMenu';
import NextPrevious from '../common/NextPrevious/NextPrevious';
import { PagingHandlerParams } from '../common/NextPrevious/NextPrevious.interface';
import { OwnerLabel } from '../common/OwnerLabel/OwnerLabel.component';
import Table from '../common/Table/Table';
import {
ProfilerTabPath,
TestCasePermission,
Expand Down Expand Up @@ -594,140 +598,92 @@ const IncidentManager = ({
);
};

const columns: ColumnsType<TestCaseResolutionStatus> = useMemo(
const columns = useMemo(
() => [
{
title: t('label.test-case-name'),
dataIndex: 'name',
key: 'name',
width: 300,
fixed: 'left',
render: (_, record) => {
return (
<Link
className="m-0 break-all text-primary"
data-testid={`test-case-${record.testCaseReference?.name}`}
to={getTestCaseDetailPagePath(
record.testCaseReference?.fullyQualifiedName ?? ''
)}>
{getEntityName(record.testCaseReference)}
</Link>
);
},
},
{ id: 'name', label: t('label.test-case-name') },
...(isIncidentPage
? [
{
title: t('label.table'),
dataIndex: 'testCaseReference',
key: 'testCaseReference',
width: 150,
render: (value: EntityReference) => {
const tableFqn = getPartialNameFromTableFQN(
value.fullyQualifiedName ?? '',
[
FqnPart.Service,
FqnPart.Database,
FqnPart.Schema,
FqnPart.Table,
],
'.'
);

return (
<Link
data-testid="table-link"
to={getEntityDetailsPath(
EntityType.TABLE,
tableFqn,
EntityTabs.PROFILER,
ProfilerTabPath.DATA_QUALITY
)}
onClick={(e) => e.stopPropagation()}>
{getNameFromFQN(tableFqn) ?? value.fullyQualifiedName}
</Link>
);
},
},
]
? [{ id: 'testCaseReference', label: t('label.table') }]
: []),
{
title: t('label.last-updated'),
dataIndex: 'timestamp',
key: 'timestamp',
width: 150,
render: (value: number) => {
return <DateTimeDisplay timestamp={value} />;
},
},
{
title: t('label.status'),
dataIndex: 'testCaseResolutionStatusType',
key: 'testCaseResolutionStatusType',
width: 100,
render: (_, record: TestCaseResolutionStatus) => {
if (isPermissionLoading) {
return <Skeleton height={24} variant="rectangular" width={100} />;
}
const hasPermission = testCasePermissions.find(
(item) =>
item.fullyQualifiedName ===
record.testCaseReference?.fullyQualifiedName
);
{ id: 'timestamp', label: t('label.last-updated') },
{ id: 'testCaseResolutionStatusType', label: t('label.status') },
{ id: 'severity', label: t('label.severity') },
{ id: 'testCaseResolutionStatusDetails', label: t('label.assignee') },
],
[isIncidentPage, t]
);

return (
const renderRow = (record: TestCaseResolutionStatus) => {
const ref = record.testCaseReference;
const tableFqn = getPartialNameFromTableFQN(
ref?.fullyQualifiedName ?? '',
[FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table],
'.'
);
const hasPermission = testCasePermissions.find(
(item) => item.fullyQualifiedName === ref?.fullyQualifiedName
);

return (
<Table.Row id={record.id ?? ''} key={record.id}>
<Table.Cell>
<Link
className="m-0 break-all text-primary"
data-testid={`test-case-${ref?.name}`}
to={getTestCaseDetailPagePath(ref?.fullyQualifiedName ?? '')}>
{getEntityName(ref)}
</Link>
</Table.Cell>
{isIncidentPage && (
<Table.Cell>
<Link
data-testid="table-link"
to={getEntityDetailsPath(
EntityType.TABLE,
tableFqn,
EntityTabs.PROFILER,
ProfilerTabPath.DATA_QUALITY
)}
onClick={(e) => e.stopPropagation()}>
{getNameFromFQN(tableFqn) ?? ref?.fullyQualifiedName}
</Link>
</Table.Cell>
)}
<Table.Cell>
<DateTimeDisplay timestamp={record.timestamp as number} />
</Table.Cell>
<Table.Cell>
{isPermissionLoading ? (
<Skeleton height={24} variant="rectangular" width={100} />
) : (
<TestCaseIncidentManagerStatus
isInline
data={record}
hasPermission={hasPermission?.EditAll && !tableDetails?.deleted}
onSubmit={handleStatusSubmit}
/>
);
},
},
{
title: t('label.severity'),
dataIndex: 'severity',
key: 'severity',
width: 100,
render: (value: Severities, record: TestCaseResolutionStatus) => {
if (isPermissionLoading) {
return <Skeleton height={24} variant="rectangular" width={100} />;
}

const hasPermission = testCasePermissions.find(
(item) =>
item.fullyQualifiedName ===
record.testCaseReference?.fullyQualifiedName
);

return (
)}
</Table.Cell>
<Table.Cell>
{isPermissionLoading ? (
<Skeleton height={24} variant="rectangular" width={100} />
) : (
<Severity
isInline
hasPermission={hasPermission?.EditAll && !tableDetails?.deleted}
severity={value}
severity={record.severity}
onSubmit={(severity) => handleSeveritySubmit(record, severity)}
/>
);
},
},
{
title: t('label.assignee'),
dataIndex: 'testCaseResolutionStatusDetails',
key: 'testCaseResolutionStatusDetails',
width: 200,
render: testCaseResolutionStatusDetailsRender,
},
],
[
tableDetails?.deleted,
testCaseListData.data,
testCasePermissions,
isPermissionLoading,
handleAssigneeUpdate,
handleStatusSubmit,
]
);
)}
</Table.Cell>
<Table.Cell>
{testCaseResolutionStatusDetailsRender(
record.testCaseResolutionStatusDetails as Assigned | undefined,
record
)}
</Table.Cell>
</Table.Row>
);
};

if (
!commonTestCasePermission?.ViewAll &&
Expand Down Expand Up @@ -846,31 +802,41 @@ const IncidentManager = ({
</div>

<Table
columns={columns}
containerClassName="test-case-table-container custom-card-with-table"
aria-label={t('label.incident-manager')}
data-testid="test-case-incident-manager-table"
dataSource={testCaseListData.data}
loading={testCaseListData.isLoading}
{...(pagingData && showPagination
? {
customPaginationProps: {
...pagingData,
showPagination,
},
}
: {})}
locale={{
emptyText: (
<FilterTablePlaceHolder
placeholderText={t('message.no-incident-found')}
/>
),
}}
pagination={false}
rowKey="id"
scroll={testCaseListData.data.length > 0 ? { x: '100%' } : undefined}
size="small"
/>
size="sm">
<Table.Header columns={columns}>
{(col) => <Table.Head id={col.id} key={col.id} label={col.label} />}
</Table.Header>
<Table.Body
dependencies={[
isPermissionLoading,
testCasePermissions,
testCaseListData.data,
]}
items={testCaseListData.isLoading ? [] : testCaseListData.data}
Comment thread
shah-harshit marked this conversation as resolved.
renderEmptyState={() =>
testCaseListData.isLoading ? (
<div className="tw:p-4">
{Array.from({ length: 5 }).map((_, i) => (
<Skeleton
className="tw:mb-2"
height={40}
key={i}
width="100%"
/>
))}
</div>
Comment thread
shah-harshit marked this conversation as resolved.
Outdated
) : (
Comment thread
shah-harshit marked this conversation as resolved.
<FilterTablePlaceHolder
placeholderText={t('message.no-incident-found')}
/>
)
}>
{(record) => renderRow(record)}
</Table.Body>
</Table>
{pagingData && showPagination && <NextPrevious {...pagingData} />}
</div>
);
};
Expand Down
Loading
Loading