Report asset management

This commit is contained in:
Oliver Walters 2026-07-03 08:00:40 +00:00
parent 37a8192c65
commit 8f0ec252a2
2 changed files with 136 additions and 1 deletions

View File

@ -16,6 +16,7 @@ import {
IconListDetails, IconListDetails,
IconMail, IconMail,
IconPackages, IconPackages,
IconPhoto,
IconPlugConnected, IconPlugConnected,
IconQrcode, IconQrcode,
IconReport, IconReport,
@ -107,6 +108,10 @@ const SnippetTable = Loadable(
lazy(() => import('../../../../tables/settings/SnippetTable')) lazy(() => import('../../../../tables/settings/SnippetTable'))
); );
const AssetTable = Loadable(
lazy(() => import('../../../../tables/settings/AssetTable'))
);
export default function AdminCenter() { export default function AdminCenter() {
const user = useUserState(); const user = useUserState();
@ -231,6 +236,12 @@ export default function AdminCenter() {
icon: <IconFileCode />, icon: <IconFileCode />,
content: <SnippetTable /> content: <SnippetTable />
}, },
{
name: 'assets',
label: t`Report Assets`,
icon: <IconPhoto />,
content: <AssetTable />
},
{ {
name: 'location-types', name: 'location-types',
label: t`Location Types`, label: t`Location Types`,
@ -283,7 +294,7 @@ export default function AdminCenter() {
{ {
id: 'reporting', id: 'reporting',
label: t`Reporting`, label: t`Reporting`,
panelIDs: ['labels', 'reports', 'snippets'] panelIDs: ['labels', 'reports', 'snippets', 'assets']
}, },
{ {
id: 'plm', id: 'plm',

View File

@ -0,0 +1,124 @@
import { AddItemButton } from '@lib/components/AddItemButton';
import { type RowAction, RowDeleteAction } from '@lib/components/RowActions';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables';
import { t } from '@lingui/core/macro';
import { Alert, Text } from '@mantine/core';
import { IconInfoCircle } from '@tabler/icons-react';
import { type ReactNode, useCallback, useMemo, useState } from 'react';
import { AttachmentLink } from '../../components/items/AttachmentLink';
import {
useCreateApiFormModal,
useDeleteApiFormModal
} from '../../hooks/UseForm';
import { useUserState } from '../../states/UserState';
import { DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
export type AssetI = {
pk: number;
asset: string;
description: string;
};
export default function AssetTable() {
const table = useTable('report-asset');
const user = useUserState();
const columns: TableColumn<AssetI>[] = useMemo(() => {
return [
{
accessor: 'asset',
title: t`Asset`,
sortable: false,
switchable: false,
render: (record: AssetI) => {
if (!record.asset) {
return '-';
}
return <AttachmentLink attachment={record.asset} />;
},
noContext: true
},
DescriptionColumn({
accessor: 'description',
sortable: false,
switchable: false
})
];
}, []);
const [selectedAsset, setSelectedAsset] = useState<number>(-1);
const rowActions = useCallback(
(record: AssetI): RowAction[] => {
return [
RowDeleteAction({
hidden: !user.isStaff(),
onClick: () => {
setSelectedAsset(record.pk);
deleteAsset.open();
}
})
];
},
[user]
);
const newAssetFields: ApiFormFieldSet = useMemo(() => {
return {
asset: {},
description: {}
};
}, []);
const deleteAsset = useDeleteApiFormModal({
url: ApiEndpoints.report_asset,
pk: selectedAsset,
title: t`Delete Asset`,
table: table
});
const newAsset = useCreateApiFormModal({
url: ApiEndpoints.report_asset,
title: t`Add Asset`,
fields: newAssetFields,
table: table
});
const tableActions: ReactNode[] = useMemo(() => {
return [
<AddItemButton
key='add-asset'
onClick={() => newAsset.open()}
tooltip={t`Add asset`}
hidden={!user.isStaff()}
/>
];
}, [user]);
return (
<>
{newAsset.modal}
{deleteAsset.modal}
<Alert icon={<IconInfoCircle />} title={t`Assets`}>
<Text>{t`Assets are files (such as images) which can be used when rendering reports and labels.`}</Text>
</Alert>
<InvenTreeTable
url={apiUrl(ApiEndpoints.report_asset)}
tableState={table}
columns={columns}
props={{
rowActions: rowActions,
tableActions: tableActions,
enableSearch: false,
enableFilters: false
}}
/>
</>
);
}