2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 19:46:46 +00:00

[PUI] Machines table refactor (#8352)

* Reorganize MachineManagementPanel

- Use Accordion
- More consistent with PluginManagementPanel

* Code cleanup

* Refactor machine drawer display

* Refactor MachineTypeDetailDrawer
This commit is contained in:
Oliver 2024-10-24 15:24:52 +11:00 committed by GitHub
parent 9f9afa1593
commit 328472701d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 357 additions and 293 deletions

View File

@ -1,18 +1,20 @@
import { Trans } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import {
Accordion,
ActionIcon, ActionIcon,
Alert,
Code, Code,
Group, Group,
List, List,
Space,
Stack, Stack,
Text, Text
Title
} from '@mantine/core'; } from '@mantine/core';
import { IconRefresh } from '@tabler/icons-react'; import { IconInfoCircle, IconRefresh } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useMemo } from 'react';
import { api } from '../../../../App'; import { api } from '../../../../App';
import { StylishText } from '../../../../components/items/StylishText';
import { ApiEndpoints } from '../../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../../../enums/ApiEndpoints';
import { apiUrl } from '../../../../states/ApiState'; import { apiUrl } from '../../../../states/ApiState';
import { MachineListTable } from '../../../../tables/machine/MachineListTable'; import { MachineListTable } from '../../../../tables/machine/MachineListTable';
@ -32,36 +34,66 @@ export default function MachineManagementPanel() {
staleTime: 10 * 1000 staleTime: 10 * 1000
}); });
const hasErrors = useMemo(() => {
return ( return (
<Stack> registryStatus?.registry_errors &&
registryStatus.registry_errors.length > 0
);
}, [registryStatus]);
return (
<Accordion multiple defaultValue={['machinelist', 'machinetypes']}>
<Accordion.Item value="machinelist">
<Accordion.Control>
<StylishText size="lg">{t`Machines`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<MachineListTable props={{}} /> <MachineListTable props={{}} />
</Accordion.Panel>
<Space h="10px" /> </Accordion.Item>
<Accordion.Item value="machinetypes">
<Stack gap={'xs'}> <Accordion.Control>
<Title order={5}> <StylishText size="lg">{t`Machine Types`}</StylishText>
<Trans>Machine types</Trans> </Accordion.Control>
</Title> <Accordion.Panel>
<MachineTypeListTable props={{}} /> <MachineTypeListTable props={{}} />
</Stack> </Accordion.Panel>
</Accordion.Item>
<Space h="10px" /> <Accordion.Item value="machineerrors">
<Accordion.Control>
<Stack gap={'xs'}> <StylishText size="lg">{t`Machine Errors`}</StylishText>
<Group> </Accordion.Control>
<Title order={5}> <Accordion.Panel>
<Trans>Machine Error Stack</Trans> <Stack gap="xs">
</Title> <Group
justify="space-beteen"
wrap="nowrap"
style={{ width: '100%' }}
>
{hasErrors ? (
<Alert
flex={10}
color="red"
title={t`Registry Registry Errors`}
icon={<IconInfoCircle />}
>
<Text>{t`There are machine registry errors`}</Text>
</Alert>
) : (
<Alert
flex={10}
color="green"
title={t`Machine Registry Errors`}
icon={<IconInfoCircle />}
>
<Text>{t`There are no machine registry errors`}</Text>
</Alert>
)}
<ActionIcon variant="outline" onClick={() => refetch()}> <ActionIcon variant="outline" onClick={() => refetch()}>
<IconRefresh /> <IconRefresh />
</ActionIcon> </ActionIcon>
</Group> </Group>
{registryStatus?.registry_errors && {hasErrors && (
registryStatus.registry_errors.length === 0 ? (
<Text style={{ fontStyle: 'italic' }}>
<Trans>There are no machine registry errors.</Trans>
</Text>
) : (
<List> <List>
{registryStatus?.registry_errors?.map((error, i) => ( {registryStatus?.registry_errors?.map((error, i) => (
<List.Item key={i}> <List.Item key={i}>
@ -71,6 +103,8 @@ export default function MachineManagementPanel() {
</List> </List>
)} )}
</Stack> </Stack>
</Stack> </Accordion.Panel>
</Accordion.Item>
</Accordion>
); );
} }

View File

@ -1,6 +1,6 @@
import { Trans, t } from '@lingui/macro'; import { Trans, t } from '@lingui/macro';
import { import {
ActionIcon, Accordion,
Badge, Badge,
Box, Box,
Card, Card,
@ -10,7 +10,6 @@ import {
Indicator, Indicator,
List, List,
LoadingOverlay, LoadingOverlay,
Space,
Stack, Stack,
Text, Text,
Title Title
@ -30,6 +29,7 @@ import {
OptionsActionDropdown OptionsActionDropdown
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { InfoItem } from '../../components/items/InfoItem'; import { InfoItem } from '../../components/items/InfoItem';
import { StylishText } from '../../components/items/StylishText';
import { UnavailableIndicator } from '../../components/items/UnavailableIndicator'; import { UnavailableIndicator } from '../../components/items/UnavailableIndicator';
import { import {
DetailDrawer, DetailDrawer,
@ -237,13 +237,12 @@ function MachineDrawer({
}); });
return ( return (
<>
<Stack gap="xs"> <Stack gap="xs">
{machineEditModal.modal} {machineEditModal.modal}
{machineDeleteModal.modal} {machineDeleteModal.modal}
<Group justify="space-between"> <Group justify="space-between">
<Box></Box>
<Group> <Group>
{machine && <MachineStatusIndicator machine={machine} />} {machine && <MachineStatusIndicator machine={machine} />}
<Title order={4}>{machine?.name}</Title> <Title order={4}>{machine?.name}</Title>
@ -284,16 +283,17 @@ function MachineDrawer({
</Group> </Group>
</Group> </Group>
<Accordion
multiple
defaultValue={['machine-info', 'machine-settings', 'driver-settings']}
>
<Accordion.Item value="machine-info">
<Accordion.Control>
<StylishText size="lg">{t`Machine Information`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<Card withBorder> <Card withBorder>
<Stack gap="md"> <Stack gap="md">
<Group justify="space-between">
<Title order={4}>
<Trans>Machine information</Trans>
</Title>
<ActionIcon variant="outline" onClick={() => refetch()}>
<IconRefresh />
</ActionIcon>
</Group>
<Stack pos="relative" gap="xs"> <Stack pos="relative" gap="xs">
<LoadingOverlay <LoadingOverlay
visible={isFetching} visible={isFetching}
@ -322,7 +322,9 @@ function MachineDrawer({
) : ( ) : (
<Text>{machine?.driver}</Text> <Text>{machine?.driver}</Text>
)} )}
{!machine?.is_driver_available && <UnavailableIndicator />} {!machine?.is_driver_available && (
<UnavailableIndicator />
)}
</Group> </Group>
</InfoItem> </InfoItem>
<InfoItem name={t`Initialized`}> <InfoItem name={t`Initialized`}>
@ -368,34 +370,43 @@ function MachineDrawer({
</Stack> </Stack>
</Stack> </Stack>
</Card> </Card>
<Space h="10px" /> </Accordion.Panel>
</Accordion.Item>
{machine?.is_driver_available && ( {machine?.is_driver_available && (
<> <Accordion.Item value="machine-settings">
<Accordion.Control>
<StylishText size="lg">{t`Machine Settings`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<Card withBorder> <Card withBorder>
<Title order={5} pb={4}>
<Trans>Machine Settings</Trans>
</Title>
<MachineSettingList <MachineSettingList
machinePk={machinePk} machinePk={machinePk}
configType="M" configType="M"
onChange={refreshAll} onChange={refreshAll}
/> />
</Card> </Card>
</Accordion.Panel>
</Accordion.Item>
)}
{machine?.is_driver_available && (
<Accordion.Item value="driver-settings">
<Accordion.Control>
<StylishText size="lg">{t`Driver Settings`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<Card withBorder> <Card withBorder>
<Title order={5} pb={4}>
<Trans>Driver Settings</Trans>
</Title>
<MachineSettingList <MachineSettingList
machinePk={machinePk} machinePk={machinePk}
configType="D" configType="D"
onChange={refreshAll} onChange={refreshAll}
/> />
</Card> </Card>
</> </Accordion.Panel>
</Accordion.Item>
)} )}
</Accordion>
</Stack> </Stack>
</>
); );
} }
@ -543,8 +554,8 @@ export function MachineListTable({
const tableActions = useMemo(() => { const tableActions = useMemo(() => {
return [ return [
<AddItemButton <AddItemButton
key="outline" key="add-machine"
variant="outline" tooltip={t`Add machine`}
onClick={() => { onClick={() => {
setCreateFormMachineType(null); setCreateFormMachineType(null);
createMachineForm.open(); createMachineForm.open();
@ -558,8 +569,8 @@ export function MachineListTable({
{createMachineForm.modal} {createMachineForm.modal}
{renderMachineDrawer && ( {renderMachineDrawer && (
<DetailDrawer <DetailDrawer
title={t`Machine detail`} title={t`Machine Detail`}
size={'lg'} size={'xl'}
renderContent={(id) => { renderContent={(id) => {
if (!id || !id.startsWith('machine-')) return false; if (!id || !id.startsWith('machine-')) return false;
return ( return (

View File

@ -1,6 +1,8 @@
import { Trans, t } from '@lingui/macro'; import { Trans, t } from '@lingui/macro';
import { import {
Accordion,
ActionIcon, ActionIcon,
Alert,
Badge, Badge,
Card, Card,
Code, Code,
@ -11,11 +13,12 @@ import {
Text, Text,
Title Title
} from '@mantine/core'; } from '@mantine/core';
import { IconRefresh } from '@tabler/icons-react'; import { IconExclamationCircle, IconRefresh } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { InfoItem } from '../../components/items/InfoItem'; import { InfoItem } from '../../components/items/InfoItem';
import { StylishText } from '../../components/items/StylishText';
import { DetailDrawer } from '../../components/nav/DetailDrawer'; import { DetailDrawer } from '../../components/nav/DetailDrawer';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
@ -79,37 +82,49 @@ function MachineTypeDrawer({
); );
return ( return (
<>
<Stack> <Stack>
<Group justify="center"> <Group wrap="nowrap">
<Title order={4}> <Title order={4}>
{machineType ? machineType.name : machineTypeSlug} {machineType ? machineType.name : machineTypeSlug}
</Title> </Title>
</Group> </Group>
{!machineType && ( {!machineType && (
<Text style={{ fontStyle: 'italic' }}> <Alert
<Trans>Machine type not found.</Trans> color="red"
</Text> title={t`Not Found`}
icon={<IconExclamationCircle />}
>
<Text>{t`Machine type not found.`}</Text>
</Alert>
)} )}
<Accordion
multiple
defaultValue={['machine-type-info', 'machine-drivers']}
>
<Accordion.Item value="machine-type-info">
<Accordion.Control>
<StylishText size="lg">{t`Machine Type Information`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<Card withBorder> <Card withBorder>
<Stack gap="md">
<Group justify="space-between">
<Title order={4}>
<Trans>Machine type information</Trans>
</Title>
<ActionIcon variant="outline" onClick={() => refresh()}>
<IconRefresh />
</ActionIcon>
</Group>
<Stack pos="relative" gap="xs"> <Stack pos="relative" gap="xs">
<LoadingOverlay <LoadingOverlay
visible={isFetching} visible={isFetching}
overlayProps={{ opacity: 0 }} overlayProps={{ opacity: 0 }}
/> />
<InfoItem name={t`Name`} value={machineType?.name} type="text" /> <InfoItem
<InfoItem name={t`Slug`} value={machineType?.slug} type="text" /> name={t`Name`}
value={machineType?.name}
type="text"
/>
<InfoItem
name={t`Slug`}
value={machineType?.slug}
type="text"
/>
<InfoItem <InfoItem
name={t`Description`} name={t`Description`}
value={machineType?.description} value={machineType?.description}
@ -139,15 +154,15 @@ function MachineTypeDrawer({
type="boolean" type="boolean"
/> />
</Stack> </Stack>
</Stack>
</Card> </Card>
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value="machine-drivers">
<Accordion.Control>
<StylishText size="lg">{t`Available Drivers`}</StylishText>
</Accordion.Control>
<Accordion.Panel>
<Card withBorder> <Card withBorder>
<Stack gap="md">
<Title order={4}>
<Trans>Available drivers</Trans>
</Title>
<InvenTreeTable <InvenTreeTable
url={apiUrl(ApiEndpoints.machine_driver_list)} url={apiUrl(ApiEndpoints.machine_driver_list)}
tableState={table} tableState={table}
@ -160,12 +175,16 @@ function MachineTypeDrawer({
}, },
enableDownload: false, enableDownload: false,
enableSearch: false, enableSearch: false,
onRowClick: (machine) => navigate(`../driver-${machine.slug}/`) onRowClick: (machine) =>
navigate(`../driver-${machine.slug}/`)
}} }}
/> />
</Stack>
</Card> </Card>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Stack> </Stack>
</>
); );
} }
@ -335,8 +354,8 @@ export function MachineTypeListTable({
return ( return (
<> <>
<DetailDrawer <DetailDrawer
title={t`Machine type detail`} title={t`Machine Type Detail`}
size={'lg'} size={'xl'}
renderContent={(id) => { renderContent={(id) => {
if (!id || !id.startsWith('type-')) return false; if (!id || !id.startsWith('type-')) return false;
return ( return (
@ -345,8 +364,8 @@ export function MachineTypeListTable({
}} }}
/> />
<DetailDrawer <DetailDrawer
title={t`Machine driver detail`} title={t`Machine Driver Detail`}
size={'lg'} size={'xl'}
renderContent={(id) => { renderContent={(id) => {
if (!id || !id.startsWith('driver-')) return false; if (!id || !id.startsWith('driver-')) return false;
return ( return (