From e3b675c2939b481f5d8cb295bfc77d690492e6d6 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Wed, 21 Aug 2024 01:57:19 +0200 Subject: [PATCH] Add Link/Unlink Barcode action Fixes #7920 --- .../src/components/items/ActionDropdown.tsx | 85 +++++++++++++++---- src/frontend/src/components/items/QRCode.tsx | 60 ++++++++++++- src/frontend/src/enums/ApiEndpoints.tsx | 2 + src/frontend/src/pages/build/BuildDetail.tsx | 6 +- .../src/pages/company/SupplierPartDetail.tsx | 6 +- src/frontend/src/pages/part/PartDetail.tsx | 7 +- .../pages/purchasing/PurchaseOrderDetail.tsx | 6 +- .../src/pages/sales/ReturnOrderDetail.tsx | 6 +- .../src/pages/sales/SalesOrderDetail.tsx | 6 +- .../src/pages/stock/LocationDetail.tsx | 6 +- src/frontend/src/pages/stock/StockDetail.tsx | 6 +- 11 files changed, 161 insertions(+), 35 deletions(-) diff --git a/src/frontend/src/components/items/ActionDropdown.tsx b/src/frontend/src/components/items/ActionDropdown.tsx index 2e8a2df425c1..4dd8dd34990a 100644 --- a/src/frontend/src/components/items/ActionDropdown.tsx +++ b/src/frontend/src/components/items/ActionDropdown.tsx @@ -20,7 +20,7 @@ import { ReactNode, useMemo } from 'react'; import { ModelType } from '../../enums/ModelType'; import { identifierString } from '../../functions/conversion'; import { InvenTreeIcon } from '../../functions/icons'; -import { InvenTreeQRCode } from './QRCode'; +import { InvenTreeQRCode, QRCodeLink, QRCodeUnlink } from './QRCode'; export type ActionDropdownItem = { icon?: ReactNode; @@ -151,28 +151,79 @@ export function ViewBarcodeAction({ }; } -// Common action button for linking a custom barcode -export function LinkBarcodeAction( - props: ActionDropdownItem -): ActionDropdownItem { +function GeneralBarcodeAction({ + hidden = false, + model, + pk, + title, + icon, + tooltip, + ChildItem +}: { + hidden?: boolean; + model: ModelType; + pk: number; + title: string; + icon: ReactNode; + tooltip: string; + ChildItem: any; +}): ActionDropdownItem { + const onClick = () => { + modals.open({ + title: title, + children: + }); + }; + return { - ...props, - icon: , - name: t`Link Barcode`, - tooltip: t`Link custom barcode` + icon: icon, + name: title, + tooltip: tooltip, + onClick: onClick, + hidden: hidden }; } +// Common action button for linking a custom barcode +export function LinkBarcodeAction({ + hidden = false, + model, + pk +}: { + hidden?: boolean; + model: ModelType; + pk: number; +}): ActionDropdownItem { + return GeneralBarcodeAction({ + hidden: hidden, + model: model, + pk: pk, + title: t`Link Barcode`, + icon: , + tooltip: t`Link a custom barcode to this item`, + ChildItem: QRCodeLink + }); +} + // Common action button for un-linking a custom barcode -export function UnlinkBarcodeAction( - props: ActionDropdownItem -): ActionDropdownItem { - return { - ...props, +export function UnlinkBarcodeAction({ + hidden = false, + model, + pk +}: { + hidden?: boolean; + model: ModelType; + pk: number; +}): ActionDropdownItem { + return GeneralBarcodeAction({ + hidden: hidden, + model: model, + pk: pk, + title: t`Unlink Barcode`, icon: , - name: t`Unlink Barcode`, - tooltip: t`Unlink custom barcode` - }; + tooltip: t`Unlink custom barcode`, + ChildItem: QRCodeUnlink + }); } // Common action button for editing an item diff --git a/src/frontend/src/components/items/QRCode.tsx b/src/frontend/src/components/items/QRCode.tsx index 10776923144e..1166b95112ed 100644 --- a/src/frontend/src/components/items/QRCode.tsx +++ b/src/frontend/src/components/items/QRCode.tsx @@ -1,14 +1,17 @@ import { Trans, t } from '@lingui/macro'; import { Box, + Button, Code, Group, Image, Select, Skeleton, Stack, - Text + Text, + TextInput } from '@mantine/core'; +import { modals } from '@mantine/modals'; import { useQuery } from '@tanstack/react-query'; import QR from 'qrcode'; import { useEffect, useMemo, useState } from 'react'; @@ -128,3 +131,58 @@ export const InvenTreeQRCode = ({ ); }; + +export const QRCodeLink = ({ model, pk }: { model: ModelType; pk: number }) => { + const [barcode, setBarcode] = useState(); + function linkBarcode() { + api + .post(apiUrl(ApiEndpoints.barcode_link), { + [model]: pk, + barcode: barcode + }) + .then((response) => { + modals.closeAll(); + location.reload(); + }); + } + return ( + + setBarcode(event.target.value)} + /> + + + ); +}; + +export const QRCodeUnlink = ({ + model, + pk +}: { + model: ModelType; + pk: number; +}) => { + function unlinkBarcode() { + api + .post(apiUrl(ApiEndpoints.barcode_unlink), { [model]: pk }) + .then((response) => { + modals.closeAll(); + location.reload(); + }); + } + return ( + + + This will remove the link to the associated barcode + + + + ); +}; diff --git a/src/frontend/src/enums/ApiEndpoints.tsx b/src/frontend/src/enums/ApiEndpoints.tsx index a7221d62b76d..09faa30dd8cf 100644 --- a/src/frontend/src/enums/ApiEndpoints.tsx +++ b/src/frontend/src/enums/ApiEndpoints.tsx @@ -39,6 +39,8 @@ export enum ApiEndpoints { settings_global_list = 'settings/global/', settings_user_list = 'settings/user/', barcode = 'barcode/', + barcode_link = 'barcode/link/', + barcode_unlink = 'barcode/unlink/', generate_barcode = 'barcode/generate/', news = 'news/', global_status = 'generic/status/', diff --git a/src/frontend/src/pages/build/BuildDetail.tsx b/src/frontend/src/pages/build/BuildDetail.tsx index ff0f30a8c228..293d7002319f 100644 --- a/src/frontend/src/pages/build/BuildDetail.tsx +++ b/src/frontend/src/pages/build/BuildDetail.tsx @@ -479,11 +479,13 @@ export default function BuildDetail() { }), LinkBarcodeAction({ hidden: build?.barcode_hash, - onClick: notYetImplemented + model: ModelType.build, + pk: build.pk }), UnlinkBarcodeAction({ hidden: !build?.barcode_hash, - onClick: notYetImplemented + model: ModelType.build, + pk: build.pk }) ]} />, diff --git a/src/frontend/src/pages/company/SupplierPartDetail.tsx b/src/frontend/src/pages/company/SupplierPartDetail.tsx index a87cb5885738..630aa752151e 100644 --- a/src/frontend/src/pages/company/SupplierPartDetail.tsx +++ b/src/frontend/src/pages/company/SupplierPartDetail.tsx @@ -280,13 +280,15 @@ export default function SupplierPartDetail() { hidden: supplierPart.barcode_hash || !user.hasChangeRole(UserRoles.purchase_order), - onClick: notYetImplemented + model: ModelType.supplierpart, + pk: supplierPart.pk }), UnlinkBarcodeAction({ hidden: !supplierPart.barcode_hash || !user.hasChangeRole(UserRoles.purchase_order), - onClick: notYetImplemented + model: ModelType.supplierpart, + pk: supplierPart.pk }) ]} />, diff --git a/src/frontend/src/pages/part/PartDetail.tsx b/src/frontend/src/pages/part/PartDetail.tsx index 74343e14fb15..ec8133819608 100644 --- a/src/frontend/src/pages/part/PartDetail.tsx +++ b/src/frontend/src/pages/part/PartDetail.tsx @@ -74,7 +74,6 @@ import { useTransferStockItem } from '../../forms/StockForms'; import { InvenTreeIcon } from '../../functions/icons'; -import { notYetImplemented } from '../../functions/notifications'; import { getDetailUrl } from '../../functions/urls'; import { useCreateApiFormModal, @@ -980,11 +979,13 @@ export default function PartDetail() { }), LinkBarcodeAction({ hidden: part?.barcode_hash || !user.hasChangeRole(UserRoles.part), - onClick: notYetImplemented + model: ModelType.part, + pk: part.pk }), UnlinkBarcodeAction({ hidden: !part?.barcode_hash || !user.hasChangeRole(UserRoles.part), - onClick: notYetImplemented + model: ModelType.part, + pk: part.pk }) ]} key="action_dropdown" diff --git a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx index a2eacb9d7bb2..6d9dfb085894 100644 --- a/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx +++ b/src/frontend/src/pages/purchasing/PurchaseOrderDetail.tsx @@ -410,11 +410,13 @@ export default function PurchaseOrderDetail() { }), LinkBarcodeAction({ hidden: order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.purchaseorder, + pk: order.pk }), UnlinkBarcodeAction({ hidden: !order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.purchaseorder, + pk: order.pk }) ]} />, diff --git a/src/frontend/src/pages/sales/ReturnOrderDetail.tsx b/src/frontend/src/pages/sales/ReturnOrderDetail.tsx index f623f3585715..2d11d2283a76 100644 --- a/src/frontend/src/pages/sales/ReturnOrderDetail.tsx +++ b/src/frontend/src/pages/sales/ReturnOrderDetail.tsx @@ -411,11 +411,13 @@ export default function ReturnOrderDetail() { }), LinkBarcodeAction({ hidden: order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.returnorder, + pk: order.pk }), UnlinkBarcodeAction({ hidden: !order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.returnorder, + pk: order.pk }) ]} />, diff --git a/src/frontend/src/pages/sales/SalesOrderDetail.tsx b/src/frontend/src/pages/sales/SalesOrderDetail.tsx index 73c917354596..807a926541d0 100644 --- a/src/frontend/src/pages/sales/SalesOrderDetail.tsx +++ b/src/frontend/src/pages/sales/SalesOrderDetail.tsx @@ -451,11 +451,13 @@ export default function SalesOrderDetail() { }), LinkBarcodeAction({ hidden: order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.salesorder, + pk: order.pk }), UnlinkBarcodeAction({ hidden: !order?.barcode_hash, - onClick: notYetImplemented + model: ModelType.salesorder, + pk: order.pk }) ]} />, diff --git a/src/frontend/src/pages/stock/LocationDetail.tsx b/src/frontend/src/pages/stock/LocationDetail.tsx index b55f49872c09..04cdc9c5c0e9 100644 --- a/src/frontend/src/pages/stock/LocationDetail.tsx +++ b/src/frontend/src/pages/stock/LocationDetail.tsx @@ -293,10 +293,12 @@ export default function Stock() { pk: location.pk }), LinkBarcodeAction({ - onClick: notYetImplemented + model: ModelType.stocklocation, + pk: location.pk }), UnlinkBarcodeAction({ - onClick: notYetImplemented + model: ModelType.stocklocation, + pk: location.pk }), { name: 'Scan in stock items', diff --git a/src/frontend/src/pages/stock/StockDetail.tsx b/src/frontend/src/pages/stock/StockDetail.tsx index 3316b3dd7b76..7f99b0543167 100644 --- a/src/frontend/src/pages/stock/StockDetail.tsx +++ b/src/frontend/src/pages/stock/StockDetail.tsx @@ -485,12 +485,14 @@ export default function StockDetail() { LinkBarcodeAction({ hidden: stockitem?.barcode_hash || !user.hasChangeRole(UserRoles.stock), - onClick: notYetImplemented + model: ModelType.stockitem, + pk: stockitem.pk }), UnlinkBarcodeAction({ hidden: !stockitem?.barcode_hash || !user.hasChangeRole(UserRoles.stock), - onClick: notYetImplemented + model: ModelType.stockitem, + pk: stockitem.pk }) ]} />,