diff --git a/docs/docs/settings/user.md b/docs/docs/settings/user.md index fc8a1664cb..bc6919c780 100644 --- a/docs/docs/settings/user.md +++ b/docs/docs/settings/user.md @@ -29,6 +29,7 @@ The *Display Settings* screen shows general display configuration options: {{ usersetting("SHOW_FULL_CATEGORY_IN_TABLES")}} {{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}} {{ usersetting("ENABLE_LAST_BREADCRUMB") }} +{{ usersetting("SHOW_EXTRA_MODEL_INFO") }} {{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }} {{ usersetting("DISPLAY_ITEMS_FINAL_LEVEL") }} diff --git a/src/backend/InvenTree/common/setting/user.py b/src/backend/InvenTree/common/setting/user.py index c9cae610ba..f5a2cd3f38 100644 --- a/src/backend/InvenTree/common/setting/user.py +++ b/src/backend/InvenTree/common/setting/user.py @@ -235,6 +235,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = { 'default': False, 'validator': bool, }, + 'SHOW_EXTRA_MODEL_INFO': { + 'name': _('Show Extra Model Information'), + 'description': _('Display extra information in model selection dropdowns'), + 'default': False, + 'validator': bool, + }, 'SHOW_FULL_LOCATION_IN_TABLES': { 'name': _('Show full stock location in tables'), 'description': _( diff --git a/src/frontend/lib/enums/ModelInformation.tsx b/src/frontend/lib/enums/ModelInformation.tsx index 63aeb6dff5..4eb6b4934d 100644 --- a/src/frontend/lib/enums/ModelInformation.tsx +++ b/src/frontend/lib/enums/ModelInformation.tsx @@ -10,6 +10,7 @@ export interface ModelInformationInterface { url_detail?: string; api_endpoint: ApiEndpoints; admin_url?: string; + pk_field?: string; supports_barcode?: boolean; icon: keyof InvenTreeIconType; } diff --git a/src/frontend/lib/types/Rendering.tsx b/src/frontend/lib/types/Rendering.tsx index 2ad427c519..ebd64dd745 100644 --- a/src/frontend/lib/types/Rendering.tsx +++ b/src/frontend/lib/types/Rendering.tsx @@ -15,6 +15,7 @@ export interface InstanceRenderInterface { link?: boolean; navigate?: any; showSecondary?: boolean; + showHover?: boolean; extra?: Record; } diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx index 191c56f2a2..150c45034e 100644 --- a/src/frontend/src/components/render/Instance.tsx +++ b/src/frontend/src/components/render/Instance.tsx @@ -1,16 +1,20 @@ import { t } from '@lingui/core/macro'; import { + ActionIcon, Alert, Anchor, + Box, Group, + HoverCard, type MantineSize, Paper, Skeleton, Space, + Stack, Text } from '@mantine/core'; import { useQuery } from '@tanstack/react-query'; -import { type ReactNode, useCallback } from 'react'; +import { type ReactNode, useCallback, useMemo } from 'react'; import { ModelInformationDict } from '@lib/enums/ModelInformation'; import { ModelType } from '@lib/enums/ModelType'; @@ -25,8 +29,11 @@ import type { export type { InstanceRenderInterface } from '@lib/types/Rendering'; import { getBaseUrl, navigateToLink, shortenString } from '@lib/index'; +import { IconLink } from '@tabler/icons-react'; +import { useNavigate } from 'react-router-dom'; import { useApi } from '../../contexts/ApiContext'; import { usePluginState } from '../../states/PluginState'; +import { useUserSettingsState } from '../../states/SettingsStates'; import { Thumbnail } from '../images/Thumbnail'; import { RenderBuildItem, RenderBuildLine, RenderBuildOrder } from './Build'; import { @@ -125,11 +132,95 @@ export function RenderInstance(props: RenderInstanceProps): ReactNode { props.custom_model ?? props.model ?? '' ); - // provider component - if (!RenderComponent) { - return ; - } - return ; + const navigate = useNavigate(); + const userSettings = useUserSettingsState(); + + // Extract model information from the defined model type + const modelInfo = useMemo(() => { + if (!props.model) { + return undefined; + } + + return ModelInformationDict[ + props.model.toString().toLowerCase() as ModelType + ]; + }, [props.model]); + + const showHover: boolean = useMemo(() => { + if (!modelInfo) { + return false; + } + + // Override with the props.showHover attribute + if (props.showHover !== undefined) { + return props.showHover; + } + + // If not specified, fall back to the user configured setting + return userSettings.isSet('SHOW_EXTRA_MODEL_INFO'); + }, [props.showHover, modelInfo, userSettings]); + + // Extract model ID from the provided instance data, using the defined primary key field (or 'pk' as a fallback) + const modelId = useMemo(() => { + if (!modelInfo || !props.instance) { + return undefined; + } + + return props.instance[modelInfo.pk_field ?? 'pk']; + }, [modelInfo, props.instance]); + + const detailUrl = useMemo(() => { + if (!modelInfo || !modelId || !modelInfo.url_detail) { + return undefined; + } + + return modelInfo.url_detail.replace(':pk', modelId.toString()); + }, [modelInfo, modelId]); + + return ( + + + + {!!RenderComponent ? ( + + ) : ( + + )} + + + + + + + {modelInfo?.label()} + + {modelId && {`[${t`ID`}: ${modelId}]`}} + + {detailUrl && ( + navigateToLink(detailUrl, navigate, event)} + > + + + + + {t`View details`} + + + )} + + + + ); } export function RenderRemoteInstance({ diff --git a/src/frontend/src/pages/Index/Settings/UserSettings.tsx b/src/frontend/src/pages/Index/Settings/UserSettings.tsx index 88dfbcfdb0..ae71430928 100644 --- a/src/frontend/src/pages/Index/Settings/UserSettings.tsx +++ b/src/frontend/src/pages/Index/Settings/UserSettings.tsx @@ -61,6 +61,7 @@ export default function UserSettings() { 'FORMS_CLOSE_USING_ESCAPE', 'DISPLAY_STOCKTAKE_TAB', 'ENABLE_LAST_BREADCRUMB', + 'SHOW_EXTRA_MODEL_INFO', 'SHOW_FULL_LOCATION_IN_TABLES', 'SHOW_FULL_CATEGORY_IN_TABLES', 'SHOW_BOM_SUBASSEMBLY_LEVELS'