Fix: Fixed UI errors and warnings (#23837)

* Fix: Fixed UI errors and warnings

* Fix: Removed commented code

* Fix: removed the post interface

* Fix: reverted few changes

* Fix: Addressed PR comments

* Fix: removed unnecessary types

* Fix: removed unnecessary types

* Fix: fixed unit test issue
This commit is contained in:
Rohit Jain 2025-10-17 10:09:52 +05:30 committed by GitHub
parent be8beb5159
commit c8d3412f31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 135 additions and 117 deletions

View File

@ -15,7 +15,7 @@ import classNames from 'classnames';
import { compare } from 'fast-json-patch';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import { Thread } from '../../../generated/entity/feed/thread';
import { Post, Thread } from '../../../generated/entity/feed/thread';
import { useUserProfile } from '../../../hooks/user-profile/useUserProfile';
import {
formatDateTime,
@ -37,7 +37,7 @@ import ActivityFeedActions from '../Shared/ActivityFeedActions';
interface CommentCardInterface {
feed: Thread;
post: any;
post: Post;
isLastReply: boolean;
closeFeedEditor: () => void;
}

View File

@ -87,7 +87,7 @@ const DomainDetailPage = () => {
}
};
const handleDomainDelete = (id: string) => {
const handleDomainDelete = () => {
// Navigate back to domains listing page after deletion
navigate(ROUTES.DOMAIN);
};

View File

@ -19,7 +19,10 @@ export const GlossaryStatusBadge = ({ status }: { status: EntityStatus }) => {
return (
<Space>
<Divider className="m-x-xs h-6" type="vertical" />
<StatusBadge label={status} status={StatusClass[status]} />
<StatusBadge
label={status}
status={StatusClass[status as keyof typeof StatusClass]}
/>
</Space>
);
};

View File

@ -774,7 +774,7 @@ const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => {
<StatusBadge
dataTestId={termFQN + '-status'}
label={status}
status={StatusClass[status]}
status={StatusClass[status as keyof typeof StatusClass]}
/>
</div>
</Popover>

View File

@ -629,7 +629,7 @@ const LineageTable: FC<{ entity: SourceType }> = ({ entity }) => {
? 'fromEntity'
: 'toEntity',
sorter: true,
render: (record?: SearchSourceAlias) => (
render: (record?: SearchSourceAlias & { type: EntityType }) => (
<Link
to={getEntityLinkFromType(
record?.fullyQualifiedName ?? '',
@ -671,7 +671,7 @@ const LineageTable: FC<{ entity: SourceType }> = ({ entity }) => {
? 'fromEntity'
: 'toEntity',
sorter: true,
render: (record?: SearchSourceAlias) => (
render: (record?: SearchSourceAlias & { type?: EntityType }) => (
<Link
to={getEntityLinkFromType(
record?.fullyQualifiedName ?? '',

View File

@ -49,7 +49,7 @@ jest.mock('antd', () => {
return {
...antd,
Modal: ({ children, open, onCancel, ...props }: any) =>
Modal: ({ children, open, ...props }: any) =>
open ? (
<div data-testid="modal" {...props}>
{children}

View File

@ -114,7 +114,7 @@ jest.mock('../../../../utils/date-time/DateTimeUtils', () => ({
getEpochMillisForPastDays: jest.fn().mockReturnValue('startDay'),
getIntervalInMilliseconds: jest.fn().mockReturnValue('interval'),
formatDuration: jest.fn().mockReturnValue('formatDuration'),
formatDurationToHHMMSS: jest.fn().mockImplementation((_ms) => {
formatDurationToHHMMSS: jest.fn().mockImplementation(() => {
// Return a consistent formatted duration for all cases
return '02:30:15';
}),

View File

@ -18,6 +18,7 @@ import {
render,
screen,
} from '@testing-library/react';
import { Status } from '../../../../../generated/entity/applications/appRunRecord';
import { IngestionPipeline } from '../../../../../generated/entity/services/ingestionPipelines/ingestionPipeline';
import { EXECUTION_RUNS, FAILURE } from '../../../../../mocks/Ingestion.mock';
import { mockDataInsightApplicationRun } from '../../../../../mocks/LogsViewerPage.mock';
@ -438,7 +439,7 @@ describe('Test IngestionRecentRun component', () => {
const unorderedAppRuns = [
{
runId: 'app-run-2',
status: 'Success',
status: Status.Success,
startTime: 1667307000,
timestamp: 1667307000,
endTime: 1667307003,
@ -446,7 +447,7 @@ describe('Test IngestionRecentRun component', () => {
},
{
runId: 'app-run-1',
status: 'Failed',
status: Status.Failed,
startTime: 1667301000,
timestamp: 1667301000,
endTime: 1667301003,
@ -454,7 +455,7 @@ describe('Test IngestionRecentRun component', () => {
},
{
runId: 'app-run-3',
status: 'Running',
status: Status.Running,
startTime: 1667309000,
timestamp: 1667309000,
endTime: 1667309003,

View File

@ -499,22 +499,25 @@ const MUIAsyncTreeSelect: FC<MUIAsyncTreeSelectProps> = ({
);
// Handle input blur to restore selected value if no new selection
const handleInputBlur = useCallback(
(e: React.FocusEvent) => {
// Restore selected value in single-select if no new selection
if (!multiple && selectedOptions.length > 0) {
const selectedLabel = selectedOptions[0].label;
if (inputValue !== selectedLabel) {
setInputValue(selectedLabel);
debouncedSetSearchTerm(''); // Clear search to show all options
}
const handleInputBlur = useCallback(() => {
// Restore selected value in single-select if no new selection
if (!multiple && selectedOptions.length > 0) {
const selectedLabel = selectedOptions[0].label;
if (inputValue !== selectedLabel) {
setInputValue(selectedLabel);
debouncedSetSearchTerm(''); // Clear search to show all options
}
}
// Call existing blur handler for dropdown management
handleBlur(e);
},
[multiple, selectedOptions, inputValue, handleBlur, debouncedSetSearchTerm]
);
// Call existing blur handler for dropdown management
handleBlur();
}, [
multiple,
selectedOptions,
inputValue,
handleBlur,
debouncedSetSearchTerm,
]);
// Calculate if has clearable value
const hasClearableValue = multiple

View File

@ -23,13 +23,13 @@ export interface TreeContentProps {
error: string | null;
hasData: boolean;
children: ReactNode;
selectedItems?: string[] | null;
selectedItems?: string | null;
expandedItems?: string[];
focusedItem?: string;
apiRef?: MutableRefObject<any>;
loadingMessage?: string;
noDataMessage?: string;
onNodeToggle?: SimpleTreeViewProps['onExpandedItemsChange'];
onNodeToggle?: SimpleTreeViewProps<boolean>['onExpandedItemsChange'];
onFocusedItemChange?: (event: React.SyntheticEvent, itemId: string) => void;
onItemClick?: (event: React.MouseEvent, itemId: string) => void;
}

View File

@ -35,24 +35,21 @@ export const useTreeFocusManagement = ({
}
}, [inputRef, disabled]);
const handleBlur = useCallback(
(e: React.FocusEvent) => {
// Use setTimeout to check if the new focus is still within our component
setTimeout(() => {
const currentActiveElement = document.activeElement;
const handleBlur = useCallback(() => {
// Use setTimeout to check if the new focus is still within our component
setTimeout(() => {
const currentActiveElement = document.activeElement;
// Close if focus moved outside our component
if (
anchorRef.current &&
!anchorRef.current.contains(currentActiveElement) &&
!(currentActiveElement as HTMLElement)?.closest('.MuiPopper-root')
) {
onCloseDropdown?.();
}
}, 100);
},
[onCloseDropdown, anchorRef]
);
// Close if focus moved outside our component
if (
anchorRef.current &&
!anchorRef.current.contains(currentActiveElement) &&
!(currentActiveElement as HTMLElement)?.closest('.MuiPopper-root')
) {
onCloseDropdown?.();
}
}, 100);
}, [onCloseDropdown, anchorRef]);
const handleMouseDown = useCallback((e: React.MouseEvent) => {
e.preventDefault();

View File

@ -35,7 +35,6 @@ export const useTreeKeyboardNavigation = ({
getVisibleNodes,
expandedNodes,
toggleNodeExpansion,
treeData,
inputRef,
handleNodeClick,
onOpenDropdown,

View File

@ -16,6 +16,7 @@ import { debounce, isArray, isEmpty } from 'lodash';
import { EntityTags } from 'Models';
import {
FC,
HtmlHTMLAttributes,
ReactNode,
useCallback,
useEffect,
@ -62,6 +63,26 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
const [open, setOpen] = useState(false);
const { t } = useTranslation();
const fetchOptions = async (searchText: string) => {
setLoading(true);
try {
const response = await tagClassBase.getTags(searchText, 1, true);
const fetchedOptions = response?.data || [];
const mappedOptions: TagOption[] = fetchedOptions.map(
(opt: SelectOption) => ({
label: opt.label,
value: opt.value,
data: opt.data as TagLabel,
})
);
setOptions(mappedOptions);
} catch {
setOptions([]);
} finally {
setLoading(false);
}
};
const searchDebounced = useRef(
debounce(async (searchValue: string) => {
await fetchOptions(searchValue);
@ -94,26 +115,6 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
}
}, [open]);
const fetchOptions = async (searchText: string) => {
setLoading(true);
try {
const response = await tagClassBase.getTags(searchText, 1, 20);
const fetchedOptions = response?.data || [];
const mappedOptions: TagOption[] = fetchedOptions.map(
(opt: SelectOption) => ({
label: opt.label,
value: opt.value,
data: opt.data as TagLabel,
})
);
setOptions(mappedOptions);
} catch (error) {
setOptions([]);
} finally {
setLoading(false);
}
};
const handleInputChange = useCallback(
(_event: React.SyntheticEvent, newInputValue: string) => {
setInputValue(newInputValue);
@ -122,11 +123,7 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
);
const handleChange = useCallback(
(
event: React.SyntheticEvent,
newValue: (TagOption | string)[],
reason: string
) => {
(_event: React.SyntheticEvent, newValue: (TagOption | string)[]) => {
if (isArray(newValue)) {
// Filter out string values from freeSolo
const optionValues = newValue.filter(
@ -176,10 +173,10 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
ListboxProps={
{
key: `listbox-${memoizedOptions.length}`,
} as any
} as HtmlHTMLAttributes<HTMLUListElement>
}
autoFocus={autoFocus}
getOptionLabel={(option: TagOption | string) =>
getOptionLabel={(option) =>
typeof option === 'string' ? option : option.label
}
inputValue={inputValue}
@ -213,7 +210,9 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
<Box display="flex" flexDirection="column">
<Box
fontWeight="medium"
sx={{ color: option.data?.style?.color || undefined }}>
sx={{
color: option.data?.style?.color || undefined,
}}>
{option.label}
</Box>
{(option.data?.displayName || option.data?.name) && (
@ -224,8 +223,8 @@ const MUITagSuggestion: FC<MUITagSuggestionProps> = ({
</Box>
</Box>
)}
renderTags={(value: TagOption[], getTagProps) =>
value.map((option: TagOption, index: number) => {
renderTags={(value, getTagProps) =>
value.map((option, index: number) => {
const chipProps = getTagProps({ index });
return (

View File

@ -14,7 +14,14 @@
import { Autocomplete, Box, Chip, TextField, useTheme } from '@mui/material';
import { XClose } from '@untitledui/icons';
import { debounce } from 'lodash';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import {
FC,
SyntheticEvent,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as IconTeams } from '../../../assets/svg/teams-grey.svg';
import { PAGE_SIZE_MEDIUM } from '../../../constants/constants';
@ -112,7 +119,7 @@ const MUIUserTeamSelect: FC<MUIUserTeamSelectProps> = ({
users.map((user) => ({
label: getEntityName(user),
value: user.id,
entity: user,
entity: user as unknown as EntityReference,
isTeam: false,
}))
);
@ -144,7 +151,7 @@ const MUIUserTeamSelect: FC<MUIUserTeamSelectProps> = ({
teams.map((team) => ({
label: getEntityName(team),
value: team.id,
entity: team,
entity: team as unknown as EntityReference,
isTeam: true,
}))
);
@ -190,7 +197,7 @@ const MUIUserTeamSelect: FC<MUIUserTeamSelectProps> = ({
}, [open]);
const handleChange = (
_event: any,
_event: SyntheticEvent<Element, Event>,
newValue: string | OptionType | (string | OptionType)[] | null
) => {
if (!onChange) {

View File

@ -18,7 +18,7 @@ import { FC, ReactElement } from 'react';
export interface TagChipProps extends Omit<MuiChipProps, 'variant' | 'color'> {
label: string;
icon?: ReactElement;
onDelete?: () => void;
onDelete?: (e: Event) => void;
size?: 'small' | 'medium' | 'large';
variant?: 'filled' | 'outlined' | 'blueGray';
tagColor?: string; // For the colored bar indicator

View File

@ -25,6 +25,7 @@ export interface TreeNode<T = unknown> {
parent?: string;
allowSelection?: boolean;
lazyLoad?: boolean;
hasChildren?: boolean;
}
export interface TreeDataFetcherParams {

View File

@ -163,20 +163,6 @@ export const useAsyncTreeSelect = <T = unknown,>(
[]
);
// Utility function to determine if a node should lazy load
const shouldNodeLazyLoad = useCallback(
(node: TreeNode<T> | null, componentLazyLoad: boolean): boolean => {
if (!node) {
return componentLazyLoad;
}
return (
node.lazyLoad !== false && (node.lazyLoad === true || componentLazyLoad)
);
},
[]
);
// Handle node expansion
const handleNodeExpansion = useCallback(
(nodeId: string) => {

View File

@ -10,10 +10,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TFunctionKeys } from 'i18next';
import { EntityTabs, EntityType } from '../enums/entity.enum';
import { PageType } from '../generated/system/ui/page';
export const TAB_LABEL_MAP: Record<EntityTabs, string> = {
export const TAB_LABEL_MAP = {
[EntityTabs.OVERVIEW]: 'label.overview',
[EntityTabs.GLOSSARY_TERMS]: 'label.glossary-term-plural',
[EntityTabs.ASSETS]: 'label.asset-plural',
@ -60,7 +61,7 @@ export const TAB_LABEL_MAP: Record<EntityTabs, string> = {
[EntityTabs.CONTRACT]: 'label.contract',
[EntityTabs.DIRECTORIES]: 'label.directory-plural',
[EntityTabs.WORKSHEETS]: 'label.worksheet-plural',
} as const;
} as Record<EntityTabs, TFunctionKeys>;
export type CustomizeEntityType =
| EntityType.TABLE

View File

@ -33,7 +33,14 @@ import { DataInsightTabs } from '../interface/data-insight.interface';
import { createIconWithStroke } from '../utils/IconUtils';
import { PLACEHOLDER_ROUTE_TAB, ROUTES } from './constants';
const DataProductIcon = createIconWithStroke(Cube01, 1.2);
const DataProductIcon = createIconWithStroke(
Cube01 as React.ComponentType<{
size?: number;
strokeWidth?: number;
style?: React.CSSProperties;
}>,
1.2
);
export const SIDEBAR_NESTED_KEYS = {
[ROUTES.OBSERVABILITY_ALERTS]: ROUTES.OBSERVABILITY_ALERTS,

View File

@ -80,6 +80,7 @@ class DataQualityClassBase {
}
public getExportDataQualityDashboardButton(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_activeTab: DataQualityPageTabs
): React.ReactNode {
return null;

View File

@ -130,7 +130,7 @@ const BulkEntityImportPage = () => {
entityType,
fqn
);
setEntity(response);
setEntity(response as DataAssetsHeaderProps['dataAsset']);
} catch {
// not show error here
}

View File

@ -318,7 +318,7 @@ export const searchGlossaryTermsPaginated = async (
offset = 0,
fields?: string
) => {
const params: Record<string, any> = {
const params: Record<string, number | string> = {
limit,
offset,
};

View File

@ -36,7 +36,7 @@ export const updateLineageEdge = async (edge: AddLineage) => {
export const exportLineageAsync = async (
fqn: string,
entityType: string,
entityType?: string,
config?: LineageConfig,
queryFilter?: string
) => {

View File

@ -10,9 +10,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
/* eslint-disable */
const React = require('react');
module.exports = {
useAntdColumnResize: jest.fn().mockImplementation((hookDataFunction) => {
return {

View File

@ -107,6 +107,16 @@ import { t } from './i18next/LocalUtil';
import { jsonToCSV } from './StringsUtils';
import { showErrorToast } from './ToastUtils';
interface LayoutedElements {
node: Array<
Node & {
nodeHeight: number;
childrenHeight: number;
}
>;
edge: Edge[];
}
export const MAX_LINEAGE_LENGTH = 20;
export const encodeLineageHandles = (handle: string) => {
@ -176,7 +186,7 @@ export const getLayoutedElements = (
isExpanded = true,
expandAllColumns = false,
columnsHavingLineage: string[] = []
) => {
): LayoutedElements => {
const Graph = graphlib.Graph;
const dagreGraph = new Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));

View File

@ -490,6 +490,7 @@ class EntityUtilClassBase {
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getEntityFloatingButton(_: EntityType): FC | null {
return null;
}

View File

@ -325,15 +325,15 @@ describe('EntityUtils unit tests', () => {
{ text: null, searchText: 'test', expected: '' },
{ text: 'mockText', searchText: null, expected: 'mockText' },
{ text: null, searchText: null, expected: '' },
{ text: 0 as any, searchText: '', expected: 0 },
{ text: false as any, searchText: '', expected: false },
{ text: 0, searchText: '', expected: 0 },
{ text: false, searchText: '', expected: false },
];
it.each(falsyTestCases)(
'should return expected when text or searchText is null or falsy',
({ text, searchText, expected }) => {
const result = highlightSearchText(
text ?? undefined,
(text as string) ?? undefined,
searchText ?? undefined
);

View File

@ -498,14 +498,6 @@ export const getGlossaryWidgetFromKey = (widget: WidgetConfig) => {
);
};
export const getAllExpandableKeys = (terms: ModifiedGlossary[]): string[] => {
const keys: string[] = [];
processTerms(terms, keys);
return keys;
};
const processTerms = (termList: ModifiedGlossary[], keys: string[]) => {
termList.forEach((term) => {
if (
@ -520,3 +512,11 @@ const processTerms = (termList: ModifiedGlossary[], keys: string[]) => {
}
});
};
export const getAllExpandableKeys = (terms: ModifiedGlossary[]): string[] => {
const keys: string[] = [];
processTerms(terms, keys);
return keys;
};

View File

@ -54,7 +54,7 @@ import {
Users01,
XClose,
} from '@untitledui/icons';
import { ComponentType } from 'react';
import { ComponentType, FC } from 'react';
// Map of icon names to their components
export const ICON_MAP: Record<
@ -179,7 +179,7 @@ export const renderIcon = (
* @param entityType - The type of entity
* @returns The icon component
*/
export const getDefaultIconForEntityType = (entityType?: string) => {
export const getDefaultIconForEntityType = (entityType?: string): FC => {
if (entityType === 'dataProduct') {
return Cube01;
}

View File

@ -284,7 +284,8 @@ class ServiceUtilClassBase {
};
}
public getServiceExtraInfo(_data?: ServicesType): any {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getServiceExtraInfo(_data?: ServicesType) {
return null;
}
@ -826,6 +827,7 @@ class ServiceUtilClassBase {
return getDriveConfig(type);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public getInsightsTabWidgets(_: ServiceTypes) {
const widgets: Record<string, React.ComponentType<any>> = {
AgentsStatusWidget,