mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	[PUI] Small updates (#6320)
* Ensure .ts files are generated - "yarn run compile" before "yarn run dev" - ensures that .ts locale files are all generated * Implement "Add Part Category" button * Create new stock location * Rename customActionGroups to tableActions * Rename customFilters to tableFilters * Edit category from table * Edit stock location from table * Add some placeholder buttons * More placeholders
This commit is contained in:
		| @@ -20,8 +20,10 @@ export type ActionButtonProps = { | ||||
|  * Construct a simple action button with consistent styling | ||||
|  */ | ||||
| export function ActionButton(props: ActionButtonProps) { | ||||
|   const hidden = props.hidden ?? false; | ||||
|  | ||||
|   return ( | ||||
|     !props.hidden && ( | ||||
|     !hidden && ( | ||||
|       <Tooltip | ||||
|         key={`tooltip-${props.key}`} | ||||
|         disabled={!props.tooltip && !props.text} | ||||
|   | ||||
| @@ -234,7 +234,6 @@ export function SearchDrawer({ | ||||
|  | ||||
|   // Re-fetch data whenever the search term is updated | ||||
|   useEffect(() => { | ||||
|     // TODO: Implement search functionality | ||||
|     searchQuery.refetch(); | ||||
|   }, [searchText]); | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { ReactNode } from 'react'; | ||||
|  | ||||
| import { RenderInlineModel } from './Instance'; | ||||
| @@ -6,10 +7,13 @@ import { RenderInlineModel } from './Instance'; | ||||
|  * Inline rendering of a single Part instance | ||||
|  */ | ||||
| export function RenderPart({ instance }: { instance: any }): ReactNode { | ||||
|   const stock = t`Stock` + `: ${instance.in_stock}`; | ||||
|  | ||||
|   return ( | ||||
|     <RenderInlineModel | ||||
|       primary={instance.name} | ||||
|       secondary={instance.description} | ||||
|       suffix={stock} | ||||
|       image={instance.thumnbnail || instance.image} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -46,8 +46,8 @@ const defaultPageSize: number = 25; | ||||
|  * @param enableRefresh : boolean - Enable refresh actions | ||||
|  * @param pageSize : number - Number of records per page | ||||
|  * @param barcodeActions : any[] - List of barcode actions | ||||
|  * @param customFilters : TableFilter[] - List of custom filters | ||||
|  * @param customActionGroups : any[] - List of custom action groups | ||||
|  * @param tableFilters : TableFilter[] - List of custom filters | ||||
|  * @param tableActions : any[] - List of custom action groups | ||||
|  * @param printingActions : any[] - List of printing actions | ||||
|  * @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format) | ||||
|  * @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions | ||||
| @@ -66,8 +66,8 @@ export type InvenTreeTableProps<T = any> = { | ||||
|   enableRefresh?: boolean; | ||||
|   pageSize?: number; | ||||
|   barcodeActions?: any[]; | ||||
|   customFilters?: TableFilter[]; | ||||
|   customActionGroups?: React.ReactNode[]; | ||||
|   tableFilters?: TableFilter[]; | ||||
|   tableActions?: React.ReactNode[]; | ||||
|   printingActions?: any[]; | ||||
|   idAccessor?: string; | ||||
|   dataFormatter?: (data: T) => any; | ||||
| @@ -91,8 +91,8 @@ const defaultInvenTreeTableProps: InvenTreeTableProps = { | ||||
|   defaultSortColumn: '', | ||||
|   printingActions: [], | ||||
|   barcodeActions: [], | ||||
|   customFilters: [], | ||||
|   customActionGroups: [], | ||||
|   tableFilters: [], | ||||
|   tableActions: [], | ||||
|   idAccessor: 'pk', | ||||
|   onRowClick: (record: any, index: number, event: any) => {} | ||||
| }; | ||||
| @@ -425,9 +425,9 @@ export function InvenTreeTable<T = any>({ | ||||
|   return ( | ||||
|     <> | ||||
|       {tableProps.enableFilters && | ||||
|         (tableProps.customFilters?.length ?? 0) > 0 && ( | ||||
|         (tableProps.tableFilters?.length ?? 0) > 0 && ( | ||||
|           <FilterSelectDrawer | ||||
|             availableFilters={tableProps.customFilters ?? []} | ||||
|             availableFilters={tableProps.tableFilters ?? []} | ||||
|             tableState={tableState} | ||||
|             opened={filtersVisible} | ||||
|             onClose={() => setFiltersVisible(false)} | ||||
| @@ -436,7 +436,7 @@ export function InvenTreeTable<T = any>({ | ||||
|       <Stack spacing="sm"> | ||||
|         <Group position="apart"> | ||||
|           <Group position="left" key="custom-actions" spacing={5}> | ||||
|             {tableProps.customActionGroups?.map((group, idx) => ( | ||||
|             {tableProps.tableActions?.map((group, idx) => ( | ||||
|               <Fragment key={idx}>{group}</Fragment> | ||||
|             ))} | ||||
|             {(tableProps.barcodeActions?.length ?? 0 > 0) && ( | ||||
| @@ -490,7 +490,7 @@ export function InvenTreeTable<T = any>({ | ||||
|               /> | ||||
|             )} | ||||
|             {tableProps.enableFilters && | ||||
|               (tableProps.customFilters?.length ?? 0 > 0) && ( | ||||
|               (tableProps.tableFilters?.length ?? 0 > 0) && ( | ||||
|                 <Indicator | ||||
|                   size="xs" | ||||
|                   label={tableState.activeFilters.length} | ||||
|   | ||||
| @@ -363,7 +363,7 @@ export function BomTable({ | ||||
|           part_detail: true, | ||||
|           sub_part_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         onRowClick: (row) => navigate(`/part/${row.sub_part}`), | ||||
|         rowActions: rowActions | ||||
|       }} | ||||
|   | ||||
| @@ -116,7 +116,7 @@ export function UsedInTable({ | ||||
|           part_detail: true, | ||||
|           sub_part_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         onRowClick: (row) => navigate(`/part/${row.part}`) | ||||
|       }} | ||||
|     /> | ||||
|   | ||||
| @@ -155,7 +155,7 @@ export function BuildOrderTable({ params = {} }: { params?: any }) { | ||||
|           ...params, | ||||
|           part_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         onRowClick: (row) => navigate(`/build/${row.pk}`) | ||||
|       }} | ||||
|     /> | ||||
|   | ||||
| @@ -185,7 +185,7 @@ export function AddressTable({ | ||||
|       columns={columns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions, | ||||
|         tableActions: tableActions, | ||||
|         params: { | ||||
|           ...params, | ||||
|           company: companyId | ||||
|   | ||||
| @@ -133,7 +133,7 @@ export function ContactTable({ | ||||
|       columns={columns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions, | ||||
|         tableActions: tableActions, | ||||
|         params: { | ||||
|           ...params, | ||||
|           company: companyId | ||||
|   | ||||
| @@ -178,7 +178,7 @@ export function AttachmentTable({ | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   const customActionGroups: ReactNode[] = useMemo(() => { | ||||
|   const tableActions: ReactNode[] = useMemo(() => { | ||||
|     let actions = []; | ||||
|  | ||||
|     if (allowEdit) { | ||||
| @@ -235,7 +235,7 @@ export function AttachmentTable({ | ||||
|           props={{ | ||||
|             noRecordsText: t`No attachments found`, | ||||
|             enableSelection: true, | ||||
|             customActionGroups: customActionGroups, | ||||
|             tableActions: tableActions, | ||||
|             rowActions: allowEdit && allowDelete ? rowActions : undefined, | ||||
|             params: { | ||||
|               [model]: pk | ||||
|   | ||||
| @@ -1,23 +1,30 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { useMemo } from 'react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
|  | ||||
| import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { partCategoryFields } from '../../../forms/PartForms'; | ||||
| import { openCreateApiForm, openEditApiForm } from '../../../functions/forms'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { YesNoButton } from '../../items/YesNoButton'; | ||||
| import { TableColumn } from '../Column'; | ||||
| import { DescriptionColumn } from '../ColumnRenderers'; | ||||
| import { TableFilter } from '../Filter'; | ||||
| import { InvenTreeTable } from '../InvenTreeTable'; | ||||
| import { RowEditAction } from '../RowActions'; | ||||
|  | ||||
| /** | ||||
|  * PartCategoryTable - Displays a table of part categories | ||||
|  */ | ||||
| export function PartCategoryTable({ params = {} }: { params?: any }) { | ||||
| export function PartCategoryTable({ parentId }: { parentId?: any }) { | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   const table = useTable('partcategory'); | ||||
|   const user = useUserState(); | ||||
|  | ||||
|   const tableColumns: TableColumn[] = useMemo(() => { | ||||
|     return [ | ||||
| @@ -64,6 +71,62 @@ export function PartCategoryTable({ params = {} }: { params?: any }) { | ||||
|     ]; | ||||
|   }, []); | ||||
|  | ||||
|   const addCategory = useCallback(() => { | ||||
|     let fields = partCategoryFields({}); | ||||
|  | ||||
|     if (parentId) { | ||||
|       fields['parent'].value = parentId; | ||||
|     } | ||||
|  | ||||
|     openCreateApiForm({ | ||||
|       url: apiUrl(ApiPaths.category_list), | ||||
|       title: t`Add Part Category`, | ||||
|       fields: fields, | ||||
|       onFormSuccess(data: any) { | ||||
|         if (data.pk) { | ||||
|           navigate(`/part/category/${data.pk}`); | ||||
|         } else { | ||||
|           table.refreshTable(); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   }, [parentId]); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     let can_add = user.hasAddRole(UserRoles.part_category); | ||||
|  | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Part Category`} | ||||
|         onClick={addCategory} | ||||
|         disabled={!can_add} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   const rowActions = useCallback( | ||||
|     (record: any) => { | ||||
|       let can_edit = user.hasChangeRole(UserRoles.part_category); | ||||
|  | ||||
|       return [ | ||||
|         RowEditAction({ | ||||
|           hidden: !can_edit, | ||||
|           onClick: () => { | ||||
|             openEditApiForm({ | ||||
|               url: ApiPaths.category_list, | ||||
|               pk: record.pk, | ||||
|               title: t`Edit Part Category`, | ||||
|               fields: partCategoryFields({}), | ||||
|               successMessage: t`Part category updated`, | ||||
|               onFormSuccess: table.refreshTable | ||||
|             }); | ||||
|           } | ||||
|         }) | ||||
|       ]; | ||||
|     }, | ||||
|     [user] | ||||
|   ); | ||||
|  | ||||
|   return ( | ||||
|     <InvenTreeTable | ||||
|       url={apiUrl(ApiPaths.category_list)} | ||||
| @@ -71,11 +134,12 @@ export function PartCategoryTable({ params = {} }: { params?: any }) { | ||||
|       columns={tableColumns} | ||||
|       props={{ | ||||
|         enableDownload: true, | ||||
|         enableSelection: true, | ||||
|         params: { | ||||
|           ...params | ||||
|           parent: parentId ?? 'null' | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         rowActions: rowActions, | ||||
|         onRowClick: (record, index, event) => { | ||||
|           navigate(`/part/category/${record.pk}`); | ||||
|         } | ||||
|   | ||||
| @@ -180,8 +180,8 @@ export function PartParameterTable({ partId }: { partId: any }) { | ||||
|       columns={tableColumns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions, | ||||
|         customFilters: [ | ||||
|         tableActions: tableActions, | ||||
|         tableFilters: [ | ||||
|           { | ||||
|             name: 'include_variants', | ||||
|             label: t`Include Variants`, | ||||
|   | ||||
| @@ -131,8 +131,8 @@ export default function PartParameterTemplateTable() { | ||||
|       columns={tableColumns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customFilters: tableFilters, | ||||
|         customActionGroups: tableActions | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -275,7 +275,7 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) { | ||||
|       props={{ | ||||
|         ...props, | ||||
|         enableDownload: true, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         params: { | ||||
|           ...props.params, | ||||
|           category_detail: true | ||||
|   | ||||
| @@ -140,8 +140,8 @@ export default function PartTestTemplateTable({ partId }: { partId: number }) { | ||||
|         params: { | ||||
|           part: partId | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         customActionGroups: tableActions, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         rowActions: rowActions | ||||
|       }} | ||||
|     /> | ||||
|   | ||||
| @@ -37,7 +37,7 @@ export function PartVariantTable({ partId }: { partId: string }) { | ||||
|     <PartListTable | ||||
|       props={{ | ||||
|         enableDownload: false, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         params: { | ||||
|           ancestor: partId | ||||
|         } | ||||
|   | ||||
| @@ -133,7 +133,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode { | ||||
|           category_detail: true | ||||
|         }, | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: customActions | ||||
|         tableActions: customActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -493,8 +493,8 @@ export function PluginListTable({ props }: { props: InvenTreeTableProps }) { | ||||
|           }, | ||||
|           rowActions: rowActions, | ||||
|           onRowClick: (plugin) => navigate(`${plugin.pk}/`), | ||||
|           customActionGroups: tableActions, | ||||
|           customFilters: [ | ||||
|           tableActions: tableActions, | ||||
|           tableFilters: [ | ||||
|             { | ||||
|               name: 'active', | ||||
|               label: t`Active`, | ||||
|   | ||||
| @@ -5,9 +5,11 @@ import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { useManufacturerPartFields } from '../../../forms/CompanyForms'; | ||||
| import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; | ||||
| import { notYetImplemented } from '../../../functions/notifications'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { Thumbnail } from '../../images/Thumbnail'; | ||||
| import { TableColumn } from '../Column'; | ||||
| import { DescriptionColumn, LinkColumn, PartColumn } from '../ColumnRenderers'; | ||||
| @@ -57,9 +59,22 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode { | ||||
|     ]; | ||||
|   }, [params]); | ||||
|  | ||||
|   const addManufacturerPart = useCallback(() => { | ||||
|     notYetImplemented(); | ||||
|   }, []); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     // TODO: Custom actions | ||||
|     return []; | ||||
|     let can_add = | ||||
|       user.hasAddRole(UserRoles.purchase_order) && | ||||
|       user.hasAddRole(UserRoles.part); | ||||
|  | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Manufacturer Part`} | ||||
|         onClick={addManufacturerPart} | ||||
|         hidden={!can_add} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   const editManufacturerPartFields = useManufacturerPartFields(); | ||||
| @@ -112,7 +127,7 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode { | ||||
|           manufacturer_detail: true | ||||
|         }, | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions | ||||
|         tableActions: tableActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -260,7 +260,7 @@ export function PurchaseOrderLineItemTable({ | ||||
|           part_detail: true | ||||
|         }, | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions | ||||
|         tableActions: tableActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { useMemo } from 'react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
|  | ||||
| import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { ModelType } from '../../../enums/ModelType'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { notYetImplemented } from '../../../functions/notifications'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { Thumbnail } from '../../images/Thumbnail'; | ||||
| import { | ||||
|   CreationDateColumn, | ||||
| @@ -33,6 +37,7 @@ export function PurchaseOrderTable({ params }: { params?: any }) { | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   const table = useTable('purchase-order'); | ||||
|   const user = useUserState(); | ||||
|  | ||||
|   const tableFilters: TableFilter[] = useMemo(() => { | ||||
|     return [ | ||||
| @@ -94,6 +99,20 @@ export function PurchaseOrderTable({ params }: { params?: any }) { | ||||
|     ]; | ||||
|   }, []); | ||||
|  | ||||
|   const addPurchaseOrder = useCallback(() => { | ||||
|     notYetImplemented(); | ||||
|   }, []); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Purchase Order`} | ||||
|         onClick={addPurchaseOrder} | ||||
|         hidden={!user.hasAddRole(UserRoles.purchase_order)} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   return ( | ||||
|     <InvenTreeTable | ||||
|       url={apiUrl(ApiPaths.purchase_order_list)} | ||||
| @@ -104,7 +123,8 @@ export function PurchaseOrderTable({ params }: { params?: any }) { | ||||
|           ...params, | ||||
|           supplier_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         onRowClick: (row: any) => { | ||||
|           if (row.pk) { | ||||
|             navigate(`/purchasing/purchase-order/${row.pk}`); | ||||
|   | ||||
| @@ -229,7 +229,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode { | ||||
|             manufacturer_detail: true | ||||
|           }, | ||||
|           rowActions: rowActions, | ||||
|           customActionGroups: tableActions | ||||
|           tableActions: tableActions | ||||
|         }} | ||||
|       /> | ||||
|     </> | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { useMemo } from 'react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
|  | ||||
| import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { ModelType } from '../../../enums/ModelType'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { notYetImplemented } from '../../../functions/notifications'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { Thumbnail } from '../../images/Thumbnail'; | ||||
| import { | ||||
|   CreationDateColumn, | ||||
| @@ -27,6 +31,7 @@ import { InvenTreeTable } from '../InvenTreeTable'; | ||||
|  | ||||
| export function ReturnOrderTable({ params }: { params?: any }) { | ||||
|   const table = useTable('return-orders'); | ||||
|   const user = useUserState(); | ||||
|  | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
| @@ -90,6 +95,20 @@ export function ReturnOrderTable({ params }: { params?: any }) { | ||||
|     ]; | ||||
|   }, []); | ||||
|  | ||||
|   const addReturnOrder = useCallback(() => { | ||||
|     notYetImplemented(); | ||||
|   }, []); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Return Order`} | ||||
|         onClick={addReturnOrder} | ||||
|         hidden={!user.hasAddRole(UserRoles.sales_order)} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   return ( | ||||
|     <InvenTreeTable | ||||
|       url={apiUrl(ApiPaths.return_order_list)} | ||||
| @@ -100,7 +119,8 @@ export function ReturnOrderTable({ params }: { params?: any }) { | ||||
|           ...params, | ||||
|           customer_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         onRowClick: (row: any) => { | ||||
|           if (row.pk) { | ||||
|             navigate(`/sales/return-order/${row.pk}/`); | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { useMemo } from 'react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
|  | ||||
| import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { ModelType } from '../../../enums/ModelType'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { notYetImplemented } from '../../../functions/notifications'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { Thumbnail } from '../../images/Thumbnail'; | ||||
| import { | ||||
|   CreationDateColumn, | ||||
| @@ -28,6 +32,7 @@ import { InvenTreeTable } from '../InvenTreeTable'; | ||||
|  | ||||
| export function SalesOrderTable({ params }: { params?: any }) { | ||||
|   const table = useTable('sales-order'); | ||||
|   const user = useUserState(); | ||||
|  | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
| @@ -91,6 +96,20 @@ export function SalesOrderTable({ params }: { params?: any }) { | ||||
|     ]; | ||||
|   }, []); | ||||
|  | ||||
|   const addSalesOrder = useCallback(() => { | ||||
|     notYetImplemented(); | ||||
|   }, []); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Sales Order`} | ||||
|         onClick={addSalesOrder} | ||||
|         hidden={!user.hasAddRole(UserRoles.sales_order)} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   return ( | ||||
|     <InvenTreeTable | ||||
|       url={apiUrl(ApiPaths.sales_order_list)} | ||||
| @@ -101,7 +120,8 @@ export function SalesOrderTable({ params }: { params?: any }) { | ||||
|           ...params, | ||||
|           customer_detail: true | ||||
|         }, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         onRowClick: (row: any) => { | ||||
|           if (row.pk) { | ||||
|             navigate(`/sales/sales-order/${row.pk}/`); | ||||
|   | ||||
| @@ -66,7 +66,7 @@ export function CurrencyTable() { | ||||
|       tableState={table} | ||||
|       columns={columns} | ||||
|       props={{ | ||||
|         customActionGroups: tableActions, | ||||
|         tableActions: tableActions, | ||||
|         dataFormatter: (data) => { | ||||
|           let rates = data?.exchange_rates ?? {}; | ||||
|  | ||||
|   | ||||
| @@ -117,7 +117,7 @@ export default function CustomUnitsTable() { | ||||
|       columns={columns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions | ||||
|         tableActions: tableActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -166,7 +166,7 @@ export function GroupTable() { | ||||
|         columns={columns} | ||||
|         props={{ | ||||
|           rowActions: rowActions, | ||||
|           customActionGroups: tableActions, | ||||
|           tableActions: tableActions, | ||||
|           onRowClick: (record) => openDetailDrawer(record.pk) | ||||
|         }} | ||||
|       /> | ||||
|   | ||||
| @@ -106,7 +106,7 @@ export default function ProjectCodeTable() { | ||||
|       columns={columns} | ||||
|       props={{ | ||||
|         rowActions: rowActions, | ||||
|         customActionGroups: tableActions | ||||
|         tableActions: tableActions | ||||
|       }} | ||||
|     /> | ||||
|   ); | ||||
|   | ||||
| @@ -261,7 +261,7 @@ export function UserTable() { | ||||
|         columns={columns} | ||||
|         props={{ | ||||
|           rowActions: rowActions, | ||||
|           customActionGroups: tableActions, | ||||
|           tableActions: tableActions, | ||||
|           onRowClick: (record) => openDetailDrawer(record.pk) | ||||
|         }} | ||||
|       /> | ||||
|   | ||||
| @@ -344,7 +344,7 @@ export function StockItemTable({ params = {} }: { params?: any }) { | ||||
|       props={{ | ||||
|         enableDownload: true, | ||||
|         enableSelection: true, | ||||
|         customFilters: tableFilters, | ||||
|         tableFilters: tableFilters, | ||||
|         onRowClick: (record) => navigate(`/stock/item/${record.pk}`), | ||||
|         params: { | ||||
|           ...params, | ||||
|   | ||||
| @@ -1,21 +1,28 @@ | ||||
| import { t } from '@lingui/macro'; | ||||
| import { useMemo } from 'react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
|  | ||||
| import { ApiPaths } from '../../../enums/ApiEndpoints'; | ||||
| import { UserRoles } from '../../../enums/Roles'; | ||||
| import { stockLocationFields } from '../../../forms/StockForms'; | ||||
| import { openCreateApiForm, openEditApiForm } from '../../../functions/forms'; | ||||
| import { useTable } from '../../../hooks/UseTable'; | ||||
| import { apiUrl } from '../../../states/ApiState'; | ||||
| import { useUserState } from '../../../states/UserState'; | ||||
| import { AddItemButton } from '../../buttons/AddItemButton'; | ||||
| import { YesNoButton } from '../../items/YesNoButton'; | ||||
| import { TableColumn } from '../Column'; | ||||
| import { DescriptionColumn } from '../ColumnRenderers'; | ||||
| import { TableFilter } from '../Filter'; | ||||
| import { InvenTreeTable } from '../InvenTreeTable'; | ||||
| import { RowEditAction } from '../RowActions'; | ||||
|  | ||||
| /** | ||||
|  * Stock location table | ||||
|  */ | ||||
| export function StockLocationTable({ params = {} }: { params?: any }) { | ||||
| export function StockLocationTable({ parentId }: { parentId?: any }) { | ||||
|   const table = useTable('stocklocation'); | ||||
|   const user = useUserState(); | ||||
|  | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
| @@ -85,7 +92,63 @@ export function StockLocationTable({ params = {} }: { params?: any }) { | ||||
|         render: (record: any) => record.location_type_detail?.name | ||||
|       } | ||||
|     ]; | ||||
|   }, [params]); | ||||
|   }, []); | ||||
|  | ||||
|   const addLocation = useCallback(() => { | ||||
|     let fields = stockLocationFields({}); | ||||
|  | ||||
|     if (parentId) { | ||||
|       fields['parent'].value = parentId; | ||||
|     } | ||||
|  | ||||
|     openCreateApiForm({ | ||||
|       url: apiUrl(ApiPaths.stock_location_list), | ||||
|       title: t`Add Stock Location`, | ||||
|       fields: fields, | ||||
|       onFormSuccess(data: any) { | ||||
|         if (data.pk) { | ||||
|           navigate(`/stock/location/${data.pk}`); | ||||
|         } else { | ||||
|           table.refreshTable(); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   }, [parentId]); | ||||
|  | ||||
|   const tableActions = useMemo(() => { | ||||
|     let can_add = user.hasAddRole(UserRoles.stock_location); | ||||
|  | ||||
|     return [ | ||||
|       <AddItemButton | ||||
|         tooltip={t`Add Stock Location`} | ||||
|         onClick={addLocation} | ||||
|         disabled={!can_add} | ||||
|       /> | ||||
|     ]; | ||||
|   }, [user]); | ||||
|  | ||||
|   const rowActions = useCallback( | ||||
|     (record: any) => { | ||||
|       let can_edit = user.hasChangeRole(UserRoles.stock_location); | ||||
|  | ||||
|       return [ | ||||
|         RowEditAction({ | ||||
|           hidden: !can_edit, | ||||
|           onClick: () => { | ||||
|             openEditApiForm({ | ||||
|               url: ApiPaths.stock_location_list, | ||||
|               pk: record.pk, | ||||
|               title: t`Edit Stock Location`, | ||||
|               fields: stockLocationFields({}), | ||||
|               successMessage: t`Stock location updated`, | ||||
|               onFormSuccess: table.refreshTable | ||||
|             }); | ||||
|           } | ||||
|         }) | ||||
|       ]; | ||||
|     }, | ||||
|     [user] | ||||
|   ); | ||||
|  | ||||
|   return ( | ||||
|     <InvenTreeTable | ||||
| @@ -94,8 +157,12 @@ export function StockLocationTable({ params = {} }: { params?: any }) { | ||||
|       columns={tableColumns} | ||||
|       props={{ | ||||
|         enableDownload: true, | ||||
|         params: params, | ||||
|         customFilters: tableFilters, | ||||
|         params: { | ||||
|           parent: parentId ?? 'null' | ||||
|         }, | ||||
|         tableFilters: tableFilters, | ||||
|         tableActions: tableActions, | ||||
|         rowActions: rowActions, | ||||
|         onRowClick: (record) => { | ||||
|           navigate(`/stock/location/${record.pk}`); | ||||
|         } | ||||
|   | ||||
| @@ -133,3 +133,19 @@ export function useEditStockItem({ | ||||
|     onFormSuccess: callback | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export function stockLocationFields({}: {}): ApiFormFieldSet { | ||||
|   let fields: ApiFormFieldSet = { | ||||
|     parent: { | ||||
|       description: t`Parent stock location`, | ||||
|       required: false | ||||
|     }, | ||||
|     name: {}, | ||||
|     description: {}, | ||||
|     structural: {}, | ||||
|     external: {}, | ||||
|     location_type: {} | ||||
|   }; | ||||
|  | ||||
|   return fields; | ||||
| } | ||||
|   | ||||
| @@ -64,13 +64,7 @@ export default function CategoryDetail({}: {}) { | ||||
|         name: 'subcategories', | ||||
|         label: t`Part Categories`, | ||||
|         icon: <IconSitemap />, | ||||
|         content: ( | ||||
|           <PartCategoryTable | ||||
|             params={{ | ||||
|               parent: id | ||||
|             }} | ||||
|           /> | ||||
|         ) | ||||
|         content: <PartCategoryTable parentId={id} /> | ||||
|       }, | ||||
|       { | ||||
|         name: 'parameters', | ||||
|   | ||||
| @@ -53,13 +53,7 @@ export default function Stock() { | ||||
|         name: 'sublocations', | ||||
|         label: t`Stock Locations`, | ||||
|         icon: <IconSitemap />, | ||||
|         content: ( | ||||
|           <StockLocationTable | ||||
|             params={{ | ||||
|               parent: id | ||||
|             }} | ||||
|           /> | ||||
|         ) | ||||
|         content: <StockLocationTable parentId={id} /> | ||||
|       } | ||||
|     ]; | ||||
|   }, [location, id]); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user