[PUI] Add image based QR code assigment (#7960)

* Add Link/Unlink Barcode action
Fixes #7920

* remove unneeded imports

* remove duplication

* simplify

* add testing

* refactor type

* wait for reload to add coverage

* Add warning if custom barcode is used

* Add Image based assign

* fix action button size

* fix selection to prevent wrapping

* use left section for button
This commit is contained in:
Matthias Mair 2024-08-27 09:25:34 +02:00 committed by GitHub
parent 594c15b3e3
commit 313cb4758e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 6 deletions

View File

@ -1,9 +1,12 @@
import { Trans, t } from '@lingui/macro'; import { Trans, t } from '@lingui/macro';
import { import {
ActionIcon,
Alert, Alert,
Box, Box,
Button, Button,
Code, Code,
Divider,
Flex,
Group, Group,
Image, Image,
Select, Select,
@ -12,13 +15,17 @@ import {
Text, Text,
TextInput TextInput
} from '@mantine/core'; } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { modals } from '@mantine/modals'; import { modals } from '@mantine/modals';
import { IconQrcode } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import QR from 'qrcode'; import QR from 'qrcode';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { set } from 'react-hook-form';
import { api } from '../../App'; import { api } from '../../App';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { InputImageBarcode, ScanItem } from '../../pages/Index/Scan';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useGlobalSettingsState } from '../../states/SettingsState'; import { useGlobalSettingsState } from '../../states/SettingsState';
import { CopyButton } from '../buttons/CopyButton'; import { CopyButton } from '../buttons/CopyButton';
@ -142,27 +149,47 @@ export const InvenTreeQRCode = ({
export const QRCodeLink = ({ mdl_prop }: { mdl_prop: QrCodeType }) => { export const QRCodeLink = ({ mdl_prop }: { mdl_prop: QrCodeType }) => {
const [barcode, setBarcode] = useState(''); const [barcode, setBarcode] = useState('');
const [isScanning, toggleIsScanning] = useDisclosure(false);
function linkBarcode() { function linkBarcode(value?: string) {
api api
.post(apiUrl(ApiEndpoints.barcode_link), { .post(apiUrl(ApiEndpoints.barcode_link), {
[mdl_prop.model]: mdl_prop.pk, [mdl_prop.model]: mdl_prop.pk,
barcode: barcode barcode: value || barcode
}) })
.then((response) => { .then((response) => {
modals.closeAll(); modals.closeAll();
location.reload(); location.reload();
}); });
} }
const actionSubmit = (data: ScanItem[]) => {
linkBarcode(data[0].data);
};
return ( return (
<Box> <Box>
{isScanning ? (
<>
<InputImageBarcode action={actionSubmit} />
<Divider />
</>
) : null}
<TextInput <TextInput
label={t`Barcode`} label={t`Barcode`}
value={barcode} value={barcode}
onChange={(event) => setBarcode(event.currentTarget.value)} onChange={(event) => setBarcode(event.currentTarget.value)}
placeholder={t`Scan barcode data here using barcode scanner`} placeholder={t`Scan barcode data here using barcode scanner`}
leftSection={
<ActionIcon
variant="subtle"
onClick={toggleIsScanning.toggle}
size="input-sm"
>
<IconQrcode />
</ActionIcon>
}
w="100%"
/> />
<Button color="green" onClick={linkBarcode} mt="lg" fullWidth> <Button color="green" onClick={() => linkBarcode()} mt="lg" fullWidth>
<Trans>Link</Trans> <Trans>Link</Trans>
</Button> </Button>
</Box> </Box>

View File

@ -55,7 +55,7 @@ import { notYetImplemented } from '../../functions/notifications';
import { IS_DEV_OR_DEMO } from '../../main'; import { IS_DEV_OR_DEMO } from '../../main';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
interface ScanItem { export interface ScanItem {
id: string; id: string;
ref: string; ref: string;
data: any; data: any;
@ -545,7 +545,7 @@ function InputManual({ action }: Readonly<ScanInputInterface>) {
} }
/* Input that uses QR code detection from images */ /* Input that uses QR code detection from images */
function InputImageBarcode({ action }: Readonly<ScanInputInterface>) { export function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
const [qrCodeScanner, setQrCodeScanner] = useState<Html5Qrcode | null>(null); const [qrCodeScanner, setQrCodeScanner] = useState<Html5Qrcode | null>(null);
const [camId, setCamId] = useLocalStorage<CameraDevice | null>({ const [camId, setCamId] = useLocalStorage<CameraDevice | null>({
key: 'camId', key: 'camId',
@ -714,17 +714,19 @@ function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
return ( return (
<Stack gap="xs"> <Stack gap="xs">
<Group gap="xs"> <Group gap="xs" preventGrowOverflow>
<Select <Select
value={cameraValue} value={cameraValue}
onChange={setCameraValue} onChange={setCameraValue}
data={cameras.map((device) => { data={cameras.map((device) => {
return { value: device.id, label: device.label }; return { value: device.id, label: device.label };
})} })}
maw={200}
size="sm" size="sm"
/> />
{scanningEnabled ? ( {scanningEnabled ? (
<ActionIcon <ActionIcon
size="input-sm"
onClick={btnStopScanning} onClick={btnStopScanning}
title={t`Stop scanning`} title={t`Stop scanning`}
variant="default" variant="default"
@ -733,6 +735,7 @@ function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
</ActionIcon> </ActionIcon>
) : ( ) : (
<ActionIcon <ActionIcon
size="input-sm"
onClick={btnStartScanning} onClick={btnStartScanning}
title={t`Start scanning`} title={t`Start scanning`}
disabled={!camId} disabled={!camId}