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/' });