From afab76835fbda1aa2b2366636228ebe1cb0863fd Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 29 Sep 2026 19:58:31 +1000 Subject: [PATCH] [UI] Details tweaks (#12949) * Fix hover div element * Improve badge formatting * Set staleTime for useQuery in NameBadge * add staleTime elsewhere * Improved error handlign for badges * Better caching for parameterTemplate useQuery * Disable remoteInstance query without pk --- .../src/components/details/Details.tsx | 71 +++++++++++-------- .../src/components/render/Instance.tsx | 8 ++- .../tables/general/ParametricDataTable.tsx | 9 ++- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/frontend/src/components/details/Details.tsx b/src/frontend/src/components/details/Details.tsx index 5bc219285a..cf1990396b 100644 --- a/src/frontend/src/components/details/Details.tsx +++ b/src/frontend/src/components/details/Details.tsx @@ -125,11 +125,18 @@ function HoverNameBadge(data: any, type: BadgeType) { data.username, getDetailUrl(ModelType.user, data.pk, true), data?.image, - <> - {data.is_superuser && {t`Superuser`}} - {data.is_staff && {t`Administrator`}} - {data.email && t`Email: ` + data.email} - + + {data.email} + + {data.is_superuser && {t`Superuser`}} + {data.is_staff && ( + {t`Administrator`} + )} + {data.is_active === false && ( + {t`Inactive`} + )} + + ]; case 'group': return [ @@ -163,7 +170,7 @@ function HoverNameBadge(data: any, type: BadgeType) { - + {line_data[4]} @@ -181,8 +188,10 @@ function NameBadge({ }: Readonly<{ pk: string | number; type: BadgeType }>) { const api = useApi(); - const { data } = useQuery({ + const { data, isLoading, isError } = useQuery({ queryKey: ['badge', type, pk], + enabled: !!pk, + staleTime: 5 * 60 * 1000, // 5 minutes queryFn: async () => { let path = ''; @@ -202,14 +211,7 @@ function NameBadge({ const url = apiUrl(path, pk); - return api.get(url).then((response) => { - switch (response.status) { - case 200: - return response.data; - default: - return {}; - } - }); + return api.get(url).then((response) => response.data); } }); @@ -219,10 +221,14 @@ function NameBadge({ return HoverNameBadge(data, type); }, [data]); - if (!data || data.isLoading || data.isFetching) { + if (isLoading) { return ; } + if (!pk || isError || !data) { + return '---'; + } + // Rendering a user's name for the badge function _render_name() { if (!data || !data.pk) { @@ -337,8 +343,20 @@ function TableAnchorValue(props: Readonly) { const api = useApi(); const navigate = useNavigate(); - const { data } = useQuery({ - queryKey: ['detail', props.field_data.model, props.field_value], + const hasValue: boolean = + props.field_value !== null && + props.field_value !== undefined && + props.field_value !== ''; + + const { data, isLoading } = useQuery({ + queryKey: [ + 'detail', + props.field_data.model, + props.field_value, + props.field_data.model_filters + ], + enabled: hasValue && !props.field_data.external, + staleTime: 5 * 60 * 1000, // 5 minutes queryFn: async () => { if (!props.field_data?.model) { return {}; @@ -356,14 +374,7 @@ function TableAnchorValue(props: Readonly) { .get(url, { params: props.field_data.model_filters ?? undefined }) - .then((response) => { - switch (response.status) { - case 200: - return response.data; - default: - return {}; - } - }); + .then((response) => response.data); } }); @@ -385,7 +396,11 @@ function TableAnchorValue(props: Readonly) { return `/${getBaseUrl()}${detailUrl}`; }, [detailUrl]); - if (!data || data.isLoading || data.isFetching) { + if (!hasValue) { + return '---'; + } + + if (isLoading) { return ; } @@ -409,7 +424,7 @@ function TableAnchorValue(props: Readonly) { // Construct the "return value" for the fetched data let value = undefined; - if (props.field_data.model_formatter) { + if (data && props.field_data.model_formatter) { value = props.field_data.model_formatter(data) ?? value; } else if (props.field_data.model_field) { value = data?.[props.field_data.model_field] ?? value; diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx index 018a052c39..1a821ea69a 100644 --- a/src/frontend/src/components/render/Instance.tsx +++ b/src/frontend/src/components/render/Instance.tsx @@ -160,8 +160,10 @@ export function RenderRemoteInstance({ }: Readonly): ReactNode { const api = useApi(); - const { data, isLoading, isFetching } = useQuery({ - queryKey: ['model', model, pk], + const { data, isLoading } = useQuery({ + queryKey: ['model', model, pk, modelUrl], + enabled: !!pk, + staleTime: 5 * 60 * 1000, // 5 minutes queryFn: async () => { const url = modelUrl ? apiUrl(modelUrl, pk) @@ -171,7 +173,7 @@ export function RenderRemoteInstance({ } }); - if (isLoading || isFetching) { + if (isLoading) { return ; } diff --git a/src/frontend/src/tables/general/ParametricDataTable.tsx b/src/frontend/src/tables/general/ParametricDataTable.tsx index c56a87c482..eb1a675a8a 100644 --- a/src/frontend/src/tables/general/ParametricDataTable.tsx +++ b/src/frontend/src/tables/general/ParametricDataTable.tsx @@ -178,7 +178,14 @@ export default function ParametricDataTable({ // Fetch all active parameter templates for the given model type const parameterTemplates = useQuery({ - queryKey: ['parameter-templates', modelType], + queryKey: [ + 'parameter-templates', + modelType, + modelId, + relatedModel, + relatedModelId + ], + staleTime: 5 * 60 * 1000, // 5 minutes queryFn: async () => { return api .get(apiUrl(ApiEndpoints.parameter_template_list), {