mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-30 21:25:36 +00:00
[UI] Hover instance (#12038)
* Add new user setting * Implement hover-card for RenderInstance * Allow override when calling RenderInstance * Simplify * Add link icon * Adjust logic * Simplify logic * update playwright Ref: https://github.com/microsoft/playwright/issues/40998
This commit is contained in:
@@ -29,6 +29,7 @@ The *Display Settings* screen shows general display configuration options:
|
|||||||
{{ usersetting("SHOW_FULL_CATEGORY_IN_TABLES")}}
|
{{ usersetting("SHOW_FULL_CATEGORY_IN_TABLES")}}
|
||||||
{{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}}
|
{{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}}
|
||||||
{{ usersetting("ENABLE_LAST_BREADCRUMB") }}
|
{{ usersetting("ENABLE_LAST_BREADCRUMB") }}
|
||||||
|
{{ usersetting("SHOW_EXTRA_MODEL_INFO") }}
|
||||||
{{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }}
|
{{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }}
|
||||||
{{ usersetting("DISPLAY_ITEMS_FINAL_LEVEL") }}
|
{{ usersetting("DISPLAY_ITEMS_FINAL_LEVEL") }}
|
||||||
|
|
||||||
|
|||||||
@@ -235,6 +235,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
|
|||||||
'default': False,
|
'default': False,
|
||||||
'validator': bool,
|
'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': {
|
'SHOW_FULL_LOCATION_IN_TABLES': {
|
||||||
'name': _('Show full stock location in tables'),
|
'name': _('Show full stock location in tables'),
|
||||||
'description': _(
|
'description': _(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export interface ModelInformationInterface {
|
|||||||
url_detail?: string;
|
url_detail?: string;
|
||||||
api_endpoint: ApiEndpoints;
|
api_endpoint: ApiEndpoints;
|
||||||
admin_url?: string;
|
admin_url?: string;
|
||||||
|
pk_field?: string;
|
||||||
supports_barcode?: boolean;
|
supports_barcode?: boolean;
|
||||||
icon: keyof InvenTreeIconType;
|
icon: keyof InvenTreeIconType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface InstanceRenderInterface {
|
|||||||
link?: boolean;
|
link?: boolean;
|
||||||
navigate?: any;
|
navigate?: any;
|
||||||
showSecondary?: boolean;
|
showSecondary?: boolean;
|
||||||
|
showHover?: boolean;
|
||||||
extra?: Record<string, any>;
|
extra?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import {
|
import {
|
||||||
|
ActionIcon,
|
||||||
Alert,
|
Alert,
|
||||||
Anchor,
|
Anchor,
|
||||||
|
Box,
|
||||||
Group,
|
Group,
|
||||||
|
HoverCard,
|
||||||
type MantineSize,
|
type MantineSize,
|
||||||
Paper,
|
Paper,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Space,
|
Space,
|
||||||
|
Stack,
|
||||||
Text
|
Text
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
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 { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
@@ -25,8 +29,11 @@ import type {
|
|||||||
|
|
||||||
export type { InstanceRenderInterface } from '@lib/types/Rendering';
|
export type { InstanceRenderInterface } from '@lib/types/Rendering';
|
||||||
import { getBaseUrl, navigateToLink, shortenString } from '@lib/index';
|
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 { useApi } from '../../contexts/ApiContext';
|
||||||
import { usePluginState } from '../../states/PluginState';
|
import { usePluginState } from '../../states/PluginState';
|
||||||
|
import { useUserSettingsState } from '../../states/SettingsStates';
|
||||||
import { Thumbnail } from '../images/Thumbnail';
|
import { Thumbnail } from '../images/Thumbnail';
|
||||||
import { RenderBuildItem, RenderBuildLine, RenderBuildOrder } from './Build';
|
import { RenderBuildItem, RenderBuildLine, RenderBuildOrder } from './Build';
|
||||||
import {
|
import {
|
||||||
@@ -125,11 +132,95 @@ export function RenderInstance(props: RenderInstanceProps): ReactNode {
|
|||||||
props.custom_model ?? props.model ?? ''
|
props.custom_model ?? props.model ?? ''
|
||||||
);
|
);
|
||||||
|
|
||||||
// provider component
|
const navigate = useNavigate();
|
||||||
if (!RenderComponent) {
|
const userSettings = useUserSettingsState();
|
||||||
return <UnknownRenderer model={props.model} />;
|
|
||||||
|
// Extract model information from the defined model type
|
||||||
|
const modelInfo = useMemo(() => {
|
||||||
|
if (!props.model) {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
return <RenderComponent {...props} />;
|
|
||||||
|
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 (
|
||||||
|
<HoverCard
|
||||||
|
disabled={!showHover}
|
||||||
|
position='top-end'
|
||||||
|
withinPortal
|
||||||
|
openDelay={500}
|
||||||
|
closeDelay={100}
|
||||||
|
zIndex={99999}
|
||||||
|
>
|
||||||
|
<HoverCard.Target>
|
||||||
|
<Box>
|
||||||
|
{!!RenderComponent ? (
|
||||||
|
<RenderComponent {...props} />
|
||||||
|
) : (
|
||||||
|
<UnknownRenderer model={props.model} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</HoverCard.Target>
|
||||||
|
<HoverCard.Dropdown>
|
||||||
|
<Stack gap='xs'>
|
||||||
|
<Group justify='space-between'>
|
||||||
|
<Text size='sm' fw='bold'>
|
||||||
|
{modelInfo?.label()}
|
||||||
|
</Text>
|
||||||
|
{modelId && <Text size='xs'>{`[${t`ID`}: ${modelId}]`}</Text>}
|
||||||
|
</Group>
|
||||||
|
{detailUrl && (
|
||||||
|
<Anchor
|
||||||
|
href={detailUrl}
|
||||||
|
target='_blank'
|
||||||
|
onClick={(event) => navigateToLink(detailUrl, navigate, event)}
|
||||||
|
>
|
||||||
|
<Group gap='xs' wrap='nowrap'>
|
||||||
|
<ActionIcon variant='transparent' size='xs'>
|
||||||
|
<IconLink />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text size='sm'>{t`View details`}</Text>
|
||||||
|
</Group>
|
||||||
|
</Anchor>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</HoverCard.Dropdown>
|
||||||
|
</HoverCard>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RenderRemoteInstance({
|
export function RenderRemoteInstance({
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export default function UserSettings() {
|
|||||||
'FORMS_CLOSE_USING_ESCAPE',
|
'FORMS_CLOSE_USING_ESCAPE',
|
||||||
'DISPLAY_STOCKTAKE_TAB',
|
'DISPLAY_STOCKTAKE_TAB',
|
||||||
'ENABLE_LAST_BREADCRUMB',
|
'ENABLE_LAST_BREADCRUMB',
|
||||||
|
'SHOW_EXTRA_MODEL_INFO',
|
||||||
'SHOW_FULL_LOCATION_IN_TABLES',
|
'SHOW_FULL_LOCATION_IN_TABLES',
|
||||||
'SHOW_FULL_CATEGORY_IN_TABLES',
|
'SHOW_FULL_CATEGORY_IN_TABLES',
|
||||||
'SHOW_BOM_SUBASSEMBLY_LEVELS'
|
'SHOW_BOM_SUBASSEMBLY_LEVELS'
|
||||||
|
|||||||
Reference in New Issue
Block a user