mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[PUI] Tweaks (#7673)
* Fix typo * Filter fix for "supplier" field * Fix supplier part actions * Fix actions for manufacturer part * Improve bulk-delete modal - Prevents duplicate copies of modal being displayed * Cleanup admin / settings panels * Adjust playwright test
This commit is contained in:
parent
ca3f5c096c
commit
58807d575c
@ -41,7 +41,8 @@ export function useSupplierPartFields() {
|
||||
},
|
||||
supplier: {
|
||||
filters: {
|
||||
active: true
|
||||
active: true,
|
||||
is_supplier: true
|
||||
}
|
||||
},
|
||||
SKU: {
|
||||
@ -69,7 +70,12 @@ export function useManufacturerPartFields() {
|
||||
return useMemo(() => {
|
||||
const fields: ApiFormFieldSet = {
|
||||
part: {},
|
||||
manufacturer: {},
|
||||
manufacturer: {
|
||||
filters: {
|
||||
active: true,
|
||||
is_manufacturer: true
|
||||
}
|
||||
},
|
||||
MPN: {},
|
||||
description: {},
|
||||
link: {}
|
||||
|
@ -167,7 +167,7 @@ export default function AdminCenter() {
|
||||
},
|
||||
{
|
||||
name: 'location-types',
|
||||
label: t`Location types`,
|
||||
label: t`Location Types`,
|
||||
icon: <IconPackages />,
|
||||
content: <LocationTypesTable />
|
||||
},
|
||||
|
@ -167,12 +167,6 @@ export default function SystemSettings() {
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
label: t`Part Categories`,
|
||||
icon: <IconSitemap />,
|
||||
content: <PlaceholderPanel />
|
||||
},
|
||||
{
|
||||
name: 'parts',
|
||||
label: t`Parts`,
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
IconPaperclip
|
||||
} from '@tabler/icons-react';
|
||||
import { useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import { DetailsField, DetailsTable } from '../../components/details/Details';
|
||||
@ -29,8 +29,10 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { useManufacturerPartFields } from '../../forms/CompanyForms';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal,
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { useInstance } from '../../hooks/UseInstance';
|
||||
@ -43,6 +45,7 @@ import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
|
||||
export default function ManufacturerPartDetail() {
|
||||
const { id } = useParams();
|
||||
const user = useUserState();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
instance: manufacturerPart,
|
||||
@ -218,6 +221,15 @@ export default function ManufacturerPartDetail() {
|
||||
modelType: ModelType.manufacturerpart
|
||||
});
|
||||
|
||||
const deleteManufacturerPart = useDeleteApiFormModal({
|
||||
url: ApiEndpoints.manufacturer_part_list,
|
||||
pk: manufacturerPart?.pk,
|
||||
title: t`Delete Manufacturer Part`,
|
||||
onFormSuccess: () => {
|
||||
navigate(getDetailUrl(ModelType.part, manufacturerPart.part));
|
||||
}
|
||||
});
|
||||
|
||||
const manufacturerPartActions = useMemo(() => {
|
||||
return [
|
||||
<AdminButton
|
||||
@ -237,7 +249,8 @@ export default function ManufacturerPartDetail() {
|
||||
onClick: () => editManufacturerPart.open()
|
||||
}),
|
||||
DeleteItemAction({
|
||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order)
|
||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
||||
onClick: () => deleteManufacturerPart.open()
|
||||
})
|
||||
]}
|
||||
/>
|
||||
@ -259,6 +272,8 @@ export default function ManufacturerPartDetail() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{deleteManufacturerPart.modal}
|
||||
{duplicateManufacturerPart.modal}
|
||||
{editManufacturerPart.modal}
|
||||
<InstanceDetail status={requestStatus} loading={instanceQuery.isFetching}>
|
||||
<Stack gap="xs">
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
IconShoppingCart
|
||||
} from '@tabler/icons-react';
|
||||
import { ReactNode, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import { DetailsField, DetailsTable } from '../../components/details/Details';
|
||||
@ -30,8 +30,10 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { useSupplierPartFields } from '../../forms/CompanyForms';
|
||||
import { getDetailUrl } from '../../functions/urls';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal,
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { useInstance } from '../../hooks/UseInstance';
|
||||
@ -46,6 +48,8 @@ export default function SupplierPartDetail() {
|
||||
|
||||
const user = useUserState();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
instance: supplierPart,
|
||||
instanceQuery,
|
||||
@ -271,10 +275,11 @@ export default function SupplierPartDetail() {
|
||||
}),
|
||||
EditItemAction({
|
||||
hidden: !user.hasChangeRole(UserRoles.purchase_order),
|
||||
onClick: () => editSuppliertPart.open()
|
||||
onClick: () => editSupplierPart.open()
|
||||
}),
|
||||
DeleteItemAction({
|
||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order)
|
||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
||||
onClick: () => deleteSupplierPart.open()
|
||||
})
|
||||
]}
|
||||
/>
|
||||
@ -283,7 +288,7 @@ export default function SupplierPartDetail() {
|
||||
|
||||
const supplierPartFields = useSupplierPartFields();
|
||||
|
||||
const editSuppliertPart = useEditApiFormModal({
|
||||
const editSupplierPart = useEditApiFormModal({
|
||||
url: ApiEndpoints.supplier_part_list,
|
||||
pk: supplierPart?.pk,
|
||||
title: t`Edit Supplier Part`,
|
||||
@ -291,6 +296,15 @@ export default function SupplierPartDetail() {
|
||||
onFormSuccess: refreshInstance
|
||||
});
|
||||
|
||||
const deleteSupplierPart = useDeleteApiFormModal({
|
||||
url: ApiEndpoints.supplier_part_list,
|
||||
pk: supplierPart?.pk,
|
||||
title: t`Delete Supplier Part`,
|
||||
onFormSuccess: () => {
|
||||
navigate(getDetailUrl(ModelType.part, supplierPart.part));
|
||||
}
|
||||
});
|
||||
|
||||
const duplicateSupplierPart = useCreateApiFormModal({
|
||||
url: ApiEndpoints.supplier_part_list,
|
||||
title: t`Add Supplier Part`,
|
||||
@ -327,7 +341,9 @@ export default function SupplierPartDetail() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{editSuppliertPart.modal}
|
||||
{deleteSupplierPart.modal}
|
||||
{duplicateSupplierPart.modal}
|
||||
{editSupplierPart.modal}
|
||||
<InstanceDetail status={requestStatus} loading={instanceQuery.isFetching}>
|
||||
<Stack gap="xs">
|
||||
<PageDetail
|
||||
|
@ -45,6 +45,7 @@ import { cancelEvent } from '../functions/events';
|
||||
import { extractAvailableFields, mapFields } from '../functions/forms';
|
||||
import { navigateToLink } from '../functions/navigation';
|
||||
import { getDetailUrl } from '../functions/urls';
|
||||
import { useDeleteApiFormModal } from '../hooks/UseForm';
|
||||
import { TableState } from '../hooks/UseTable';
|
||||
import { useLocalState } from '../states/LocalState';
|
||||
import { TableColumn } from './Column';
|
||||
@ -495,66 +496,34 @@ export function InvenTreeTable<T = any>({
|
||||
tableState.setRecords(data ?? []);
|
||||
}, [data]);
|
||||
|
||||
// Callback function to delete the selected records in the table
|
||||
const deleteSelectedRecords = useCallback((ids: number[]) => {
|
||||
if (ids.length == 0) {
|
||||
// Ignore if no records are selected
|
||||
return;
|
||||
}
|
||||
|
||||
modals.openConfirmModal({
|
||||
title: t`Delete selected records`,
|
||||
children: (
|
||||
<Alert
|
||||
color="red"
|
||||
title={t`Are you sure you want to delete the selected records?`}
|
||||
>
|
||||
{t`This action cannot be undone!`}
|
||||
</Alert>
|
||||
),
|
||||
labels: {
|
||||
confirm: t`Delete`,
|
||||
cancel: t`Cancel`
|
||||
},
|
||||
confirmProps: {
|
||||
color: 'red'
|
||||
},
|
||||
onConfirm: () => {
|
||||
api
|
||||
.delete(url, {
|
||||
data: {
|
||||
items: ids
|
||||
}
|
||||
})
|
||||
.then((_response) => {
|
||||
// Refresh the table
|
||||
refetch();
|
||||
|
||||
// Show notification
|
||||
showNotification({
|
||||
title: t`Deleted records`,
|
||||
message: t`Records were deleted successfully`,
|
||||
color: 'green'
|
||||
});
|
||||
})
|
||||
.catch((_error) => {
|
||||
console.warn(`Bulk delete operation failed at ${url}`);
|
||||
|
||||
showNotification({
|
||||
title: t`Error`,
|
||||
message: t`Failed to delete records`,
|
||||
color: 'red'
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
tableState.clearSelectedRecords();
|
||||
if (props.afterBulkDelete) {
|
||||
props.afterBulkDelete();
|
||||
}
|
||||
});
|
||||
const deleteRecords = useDeleteApiFormModal({
|
||||
url: url,
|
||||
title: t`Delete Selected Items`,
|
||||
preFormContent: (
|
||||
<Alert
|
||||
color="red"
|
||||
title={t`Are you sure you want to delete the selected items?`}
|
||||
>
|
||||
{t`This action cannot be undone!`}
|
||||
</Alert>
|
||||
),
|
||||
initialData: {
|
||||
items: tableState.selectedIds
|
||||
},
|
||||
fields: {
|
||||
items: {
|
||||
hidden: true
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
},
|
||||
onFormSuccess: () => {
|
||||
tableState.clearSelectedRecords();
|
||||
tableState.refreshTable();
|
||||
|
||||
if (props.afterBulkDelete) {
|
||||
props.afterBulkDelete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Callback when a row is clicked
|
||||
const handleRowClick = useCallback(
|
||||
@ -587,6 +556,7 @@ export function InvenTreeTable<T = any>({
|
||||
|
||||
return (
|
||||
<>
|
||||
{deleteRecords.modal}
|
||||
{tableProps.enableFilters && (filters.length ?? 0) > 0 && (
|
||||
<Boundary label="table-filter-drawer">
|
||||
<FilterSelectDrawer
|
||||
@ -623,7 +593,9 @@ export function InvenTreeTable<T = any>({
|
||||
icon={<IconTrash />}
|
||||
color="red"
|
||||
tooltip={t`Delete selected records`}
|
||||
onClick={() => deleteSelectedRecords(tableState.selectedIds)}
|
||||
onClick={() => {
|
||||
deleteRecords.open();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{tableProps.tableActions?.map((group, idx) => (
|
||||
|
@ -28,7 +28,6 @@ test('PUI - Admin', async ({ page }) => {
|
||||
await page.getByRole('tab', { name: 'Pricing' }).click();
|
||||
await page.getByRole('tab', { name: 'Labels' }).click();
|
||||
await page.getByRole('tab', { name: 'Reporting' }).click();
|
||||
await page.getByRole('tab', { name: 'Part Categories' }).click();
|
||||
|
||||
await page.getByRole('tab', { name: 'Stocktake' }).click();
|
||||
await page.getByRole('tab', { name: 'Build Orders' }).click();
|
||||
|
Loading…
Reference in New Issue
Block a user