From 4fa86c146171622e41c2aed2ce76896eb3efff09 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2024 01:33:52 +0000 Subject: [PATCH 1/2] Fix for hovering in parameteric part table - Visual glitches are now gone --- src/frontend/src/functions/icons.tsx | 2 + src/frontend/src/tables/InvenTreeTable.tsx | 2 +- src/frontend/src/tables/TableHoverCard.tsx | 28 ++++-- .../src/tables/part/ParametricPartTable.tsx | 94 +++++++++++-------- 4 files changed, 77 insertions(+), 49 deletions(-) diff --git a/src/frontend/src/functions/icons.tsx b/src/frontend/src/functions/icons.tsx index 40d744cde626..7770628c6e44 100644 --- a/src/frontend/src/functions/icons.tsx +++ b/src/frontend/src/functions/icons.tsx @@ -27,6 +27,7 @@ import { IconCornerUpRightDouble, IconCurrencyDollar, IconDots, + IconEdit, IconExclamationCircle, IconExternalLink, IconFileUpload, @@ -109,6 +110,7 @@ const icons = { units: IconRulerMeasure, keywords: IconTag, status: IconInfoCircle, + edit: IconEdit, info: IconInfoCircle, exclamation: IconExclamationCircle, details: IconInfoCircle, diff --git a/src/frontend/src/tables/InvenTreeTable.tsx b/src/frontend/src/tables/InvenTreeTable.tsx index 233378af0c07..af2ccad8ebe9 100644 --- a/src/frontend/src/tables/InvenTreeTable.tsx +++ b/src/frontend/src/tables/InvenTreeTable.tsx @@ -81,7 +81,7 @@ const defaultPageSize: number = 25; * @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format) * @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions * @param onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked - * @param onCellClick : (event: any, record: any, recordIndex: number, column: any, columnIndex: number) => void - Callback function when a cell is clicked + * @param onCellClick : (event: any, record: any, index: number, column: any, columnIndex: number) => void - Callback function when a cell is clicked * @param modelType: ModelType - The model type for the table */ export type InvenTreeTableProps = { diff --git a/src/frontend/src/tables/TableHoverCard.tsx b/src/frontend/src/tables/TableHoverCard.tsx index adb983f9b50b..de32f946b89a 100644 --- a/src/frontend/src/tables/TableHoverCard.tsx +++ b/src/frontend/src/tables/TableHoverCard.tsx @@ -1,7 +1,7 @@ import { t } from '@lingui/macro'; import { Divider, Group, HoverCard, Stack, Text } from '@mantine/core'; import { IconInfoCircle } from '@tabler/icons-react'; -import { ReactNode } from 'react'; +import { ReactNode, useMemo } from 'react'; import { InvenTreeIcon, InvenTreeIconType } from '../functions/icons'; @@ -23,12 +23,26 @@ export function TableHoverCard({ icon?: InvenTreeIconType; iconColor?: string; }) { - // If no extra information presented, just return the raw value - if (!extra) { - return value; - } + const extraItems: ReactNode = useMemo(() => { + if (Array.isArray(extra)) { + if (extra.length == 0) { + return null; + } - if (Array.isArray(extra) && extra.length == 0) { + return ( + + {extra.map((item, idx) => ( +
{item}
+ ))} +
+ ); + } else { + return extra; + } + }, [extra]); + + // If no extra information presented, just return the raw value + if (!extraItems) { return value; } @@ -50,7 +64,7 @@ export function TableHoverCard({ {title} - {extra} + {extraItems} diff --git a/src/frontend/src/tables/part/ParametricPartTable.tsx b/src/frontend/src/tables/part/ParametricPartTable.tsx index de4718fe23fa..e742afc1f6ca 100644 --- a/src/frontend/src/tables/part/ParametricPartTable.tsx +++ b/src/frontend/src/tables/part/ParametricPartTable.tsx @@ -3,7 +3,8 @@ import { ActionIcon, Group, Tooltip } from '@mantine/core'; import { useHover } from '@mantine/hooks'; import { IconEdit } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; -import { useCallback, useMemo, useState } from 'react'; +import { ReactNode, useCallback, useMemo, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import { api } from '../../App'; import { YesNoButton } from '../../components/buttons/YesNoButton'; @@ -13,6 +14,8 @@ import { ModelType } from '../../enums/ModelType'; import { UserRoles } from '../../enums/Roles'; import { usePartParameterFields } from '../../forms/PartForms'; import { cancelEvent } from '../../functions/events'; +import { navigateToLink } from '../../functions/navigation'; +import { getDetailUrl } from '../../functions/urls'; import { useCreateApiFormModal, useEditApiFormModal @@ -30,28 +33,32 @@ import { TableHoverCard } from '../TableHoverCard'; function ParameterCell({ record, template, - canEdit, - onEdit + canEdit }: { record: any; template: any; canEdit: boolean; - onEdit: () => void; }) { const { hovered, ref } = useHover(); // Find matching template parameter - let parameter = record.parameters?.find( - (p: any) => p.template == template.pk - ); + const parameter = useMemo(() => { + return record.parameters?.find((p: any) => p.template == template.pk); + }, [record.parameters, template]); let extra: any[] = []; - let value: any = parameter?.data; + // Format the value for display + const value: ReactNode = useMemo(() => { + let v: any = parameter?.data; - if (template?.checkbox && value != undefined) { - value = ; - } + // Handle boolean values + if (template?.checkbox && v != undefined) { + v = ; + } + + return v; + }, [parameter, template]); if ( template.units && @@ -62,30 +69,21 @@ function ParameterCell({ extra.push(`${parameter.data_numeric} [${template.units}]`); } - const handleClick = useCallback((event: any) => { - cancelEvent(event); - onEdit(); - }, []); + if (hovered && canEdit) { + extra.push(t`Click to edit`); + } return (
- + - {hovered && canEdit && ( -
- - - - - -
- )}
); @@ -98,6 +96,7 @@ export default function ParametricPartTable({ }) { const table = useTable('parametric-parts'); const user = useUserState(); + const navigate = useNavigate(); const categoryParmeters = useQuery({ queryKey: ['category-parameters', categoryId], @@ -195,26 +194,25 @@ export default function ParametricPartTable({ record={record} template={template} canEdit={user.hasChangeRole(UserRoles.part)} - onEdit={() => { - setSelectedTemplate(template.pk); - setSelectedPart(record.pk); - let parameter = record.parameters?.find( - (p: any) => p.template == template.pk - ); - - if (parameter) { - setSelectedParameter(parameter.pk); - editParameter.open(); - } else { - addParameter.open(); - } - }} /> ) }; }); }, [user, categoryParmeters.data]); + const onParameterClick = useCallback((template: number, part: any) => { + setSelectedTemplate(template); + setSelectedPart(part.pk); + let parameter = part.parameters?.find((p: any) => p.template == template); + + if (parameter) { + setSelectedParameter(parameter.pk); + editParameter.open(); + } else { + addParameter.open(); + } + }, []); + const tableFilters: TableFilter[] = useMemo(() => { return [ { @@ -268,14 +266,28 @@ export default function ParametricPartTable({ columns={tableColumns} props={{ enableDownload: false, + tableFilters: tableFilters, params: { category: categoryId, cascade: true, category_detail: true, parameters: true }, - modelType: ModelType.part, - tableFilters: tableFilters + onCellClick: ({ event, record, index, column, columnIndex }) => { + cancelEvent(event); + + // Is this a "parameter" cell? + if (column?.accessor?.toString()?.startsWith('parameter_')) { + const col = column as any; + onParameterClick(col.extra.template, record); + } else { + // Navigate through to the part detail page + if (record?.pk) { + const url = getDetailUrl(ModelType.part, record.pk); + navigateToLink(url, navigate, event); + } + } + } }} /> From 47898c5aa1bd7d1cbcf40034a82309b710a15f45 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 20 Aug 2024 01:52:04 +0000 Subject: [PATCH 2/2] Prevent editing of template field --- src/frontend/src/forms/PartForms.tsx | 9 +++++++-- src/frontend/src/tables/part/ParametricPartTable.tsx | 7 ++++--- src/frontend/src/tables/part/PartParameterTable.tsx | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/forms/PartForms.tsx b/src/frontend/src/forms/PartForms.tsx index b891d241e0c4..0241f1207817 100644 --- a/src/frontend/src/forms/PartForms.tsx +++ b/src/frontend/src/forms/PartForms.tsx @@ -141,7 +141,11 @@ export function partCategoryFields(): ApiFormFieldSet { return fields; } -export function usePartParameterFields(): ApiFormFieldSet { +export function usePartParameterFields({ + editTemplate +}: { + editTemplate?: boolean; +}): ApiFormFieldSet { // Valid field choices const [choices, setChoices] = useState([]); @@ -156,6 +160,7 @@ export function usePartParameterFields(): ApiFormFieldSet { disabled: true }, template: { + disabled: editTemplate == false, onValueChange: (value: any, record: any) => { // Adjust the type of the "data" field based on the selected template if (record?.checkbox) { @@ -195,5 +200,5 @@ export function usePartParameterFields(): ApiFormFieldSet { } } }; - }, [fieldType, choices]); + }, [editTemplate, fieldType, choices]); } diff --git a/src/frontend/src/tables/part/ParametricPartTable.tsx b/src/frontend/src/tables/part/ParametricPartTable.tsx index e742afc1f6ca..c5e4cc51fcb9 100644 --- a/src/frontend/src/tables/part/ParametricPartTable.tsx +++ b/src/frontend/src/tables/part/ParametricPartTable.tsx @@ -1,7 +1,6 @@ import { t } from '@lingui/macro'; -import { ActionIcon, Group, Tooltip } from '@mantine/core'; +import { Group } from '@mantine/core'; import { useHover } from '@mantine/hooks'; -import { IconEdit } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { ReactNode, useCallback, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -117,7 +116,9 @@ export default function ParametricPartTable({ const [selectedTemplate, setSelectedTemplate] = useState(0); const [selectedParameter, setSelectedParameter] = useState(0); - const partParameterFields: ApiFormFieldSet = usePartParameterFields(); + const partParameterFields: ApiFormFieldSet = usePartParameterFields({ + editTemplate: false + }); const addParameter = useCreateApiFormModal({ url: ApiEndpoints.part_parameter_list, diff --git a/src/frontend/src/tables/part/PartParameterTable.tsx b/src/frontend/src/tables/part/PartParameterTable.tsx index e08c2bc9f548..27163304d2b4 100644 --- a/src/frontend/src/tables/part/PartParameterTable.tsx +++ b/src/frontend/src/tables/part/PartParameterTable.tsx @@ -105,7 +105,7 @@ export function PartParameterTable({ ]; }, [partId]); - const partParameterFields: ApiFormFieldSet = usePartParameterFields(); + const partParameterFields: ApiFormFieldSet = usePartParameterFields({}); const newParameter = useCreateApiFormModal({ url: ApiEndpoints.part_parameter_list,