From 4599edd375337a0d24dee963c82cd248b1c7f034 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 19 Mar 2026 16:56:13 +1100 Subject: [PATCH] [UI Update image fix (#11557) * Improve thumbnail selector - Center image - Better descriptive text * Updated playwrigth testing --- .../src/components/details/DetailsImage.tsx | 10 ++++-- .../src/tables/part/PartThumbTable.tsx | 21 +++++++++--- src/frontend/tests/pages/pui_part.spec.ts | 32 +++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/frontend/src/components/details/DetailsImage.tsx b/src/frontend/src/components/details/DetailsImage.tsx index 3efdc9386b..98336aab4c 100644 --- a/src/frontend/src/components/details/DetailsImage.tsx +++ b/src/frontend/src/components/details/DetailsImage.tsx @@ -82,8 +82,14 @@ const removeModal = (apiPath: string, setImage: (image: string) => void) => ), labels: { confirm: t`Remove`, cancel: t`Cancel` }, onConfirm: async () => { - await api.patch(apiPath, { image: null }); - setImage(backup_image); + api.patch(apiPath, { image: null }).then(() => { + setImage(backup_image); + showNotification({ + title: t`Image removed`, + message: t`The image has been removed successfully`, + color: 'green' + }); + }); } }); diff --git a/src/frontend/src/tables/part/PartThumbTable.tsx b/src/frontend/src/tables/part/PartThumbTable.tsx index c8e5061a6b..12a50bd337 100644 --- a/src/frontend/src/tables/part/PartThumbTable.tsx +++ b/src/frontend/src/tables/part/PartThumbTable.tsx @@ -3,6 +3,7 @@ import { Trans } from '@lingui/react/macro'; import { AspectRatio, Button, + Center, Divider, Group, Pagination, @@ -21,6 +22,7 @@ import { Suspense, useState } from 'react'; import { ApiEndpoints } from '@lib/enums/ApiEndpoints'; import { apiUrl } from '@lib/functions/Api'; +import { showNotification } from '@mantine/notifications'; import { IconX } from '@tabler/icons-react'; import { api } from '../../App'; import { Thumbnail } from '../../components/images/Thumbnail'; @@ -71,7 +73,8 @@ function PartThumbComponent({ color = hoverColor; } - const src: string | undefined = element?.image ? element?.image : undefined; + const src: string | undefined = element?.image || undefined; + const imageName = element.image?.split('/')?.at(-1) ?? ''; return ( selectImage(element.image)} > - - - +
+ + + +
- {element.image.split('/')[1]} ({element.count}) + {imageName || element.image} ({element.count})
@@ -114,6 +119,11 @@ async function setNewImage( if (response.data.image.includes(image)) { setImage(response.data.image); modals.closeAll(); + showNotification({ + title: t`Image updated`, + message: t`The image has been updated successfully`, + color: 'green' + }); } } @@ -197,6 +207,7 @@ export function PartThumbTable({ pk, setImage }: Readonly) { { setFilterInput(event.currentTarget.value); diff --git a/src/frontend/tests/pages/pui_part.spec.ts b/src/frontend/tests/pages/pui_part.spec.ts index b3516deba0..c8554bba5b 100644 --- a/src/frontend/tests/pages/pui_part.spec.ts +++ b/src/frontend/tests/pages/pui_part.spec.ts @@ -65,6 +65,38 @@ test('Parts - Tabs', async ({ browser }) => { await loadTab(page, 'Build Orders'); }); +test('Parts - Image Selection', async ({ browser }) => { + const page = await doCachedLogin(browser, { url: 'part/911/details' }); + + // Select a new image from the available images + await page + .getByRole('tabpanel', { name: 'Part Details' }) + .locator('img') + .hover(); + await page + .getByRole('button', { name: 'action-button-select-from-' }) + .click(); + await page.getByRole('textbox', { name: 'part-thumb-search' }).fill('red'); + await page + .locator('div') + .filter({ hasText: /^chair_red\.png \(1\)$/ }) + .nth(1) + .click(); + await page.getByRole('button', { name: 'Select' }).click(); + await page.getByText('The image has been updated successfully').waitFor(); + + // Now remove the associated image + await page + .getByRole('tabpanel', { name: 'Part Details' }) + .locator('img') + .hover(); + await page + .getByRole('button', { name: 'action-button-delete-image' }) + .click(); + await page.getByRole('button', { name: 'Remove' }).click(); + await page.getByText('The image has been removed successfully').waitFor(); +}); + test('Parts - Manufacturer Parts', async ({ browser }) => { const page = await doCachedLogin(browser, { url: 'part/84/' });