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

Request column names from server when loading table (#6375)

* Request column names from server when loading table

- As these are translated by the server, we can make use of them on the client side!
- Reduces duplication of translated titles

* Move tables up one level

* Cache translated table column names

* Clear table column cache whenever we change locale context

* Fix cache behavioue

* Enforce titleCase for table column names

* Refactor BuildOrder table

* Refactor Company table

* Refactor order tables

* More refactoring

- Refactoring more columns

* Update more tables

* Refactor BomTable

* Remove toTitleCase

- We will rely on the server-side translations!

* Remove debug messages

* Update src/frontend/src/tables/InvenTreeTable.tsx

Co-authored-by: Matthias Mair <code@mjmair.com>

* Cleanup

* Update docstring

* Cleanup

* Support nested fields with dot notation

- Powerful code reuse is powerful

* Complete refactor for BuildLine table

- Add some missing field descriptors on the backend

* Cleanup hooks a bit

* Update BomTable

* Allow table filters to make use of the same info

* Add ReferenceColumn helper

* Use queryParams when fetching table OPTIONS

- Required to ensure the same columns are fetched

* More refactoring

* Fix ProjectCodeTable

* Code cleanup

* Fix unused var

---------

Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
Oliver 2024-02-02 10:11:37 +11:00 committed by GitHub
parent 577185cd98
commit ec2a66e7a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 698 additions and 728 deletions

View File

@ -1075,16 +1075,34 @@ class BuildLineSerializer(InvenTreeModelSerializer):
quantity = serializers.FloatField() quantity = serializers.FloatField()
bom_item = serializers.PrimaryKeyRelatedField(label=_('Bom Item'), read_only=True)
# Foreign key fields # Foreign key fields
bom_item_detail = BomItemSerializer(source='bom_item', many=False, read_only=True, pricing=False) bom_item_detail = BomItemSerializer(source='bom_item', many=False, read_only=True, pricing=False)
part_detail = PartSerializer(source='bom_item.sub_part', many=False, read_only=True, pricing=False) part_detail = PartSerializer(source='bom_item.sub_part', many=False, read_only=True, pricing=False)
allocations = BuildItemSerializer(many=True, read_only=True) allocations = BuildItemSerializer(many=True, read_only=True)
# Annotated (calculated) fields # Annotated (calculated) fields
allocated = serializers.FloatField(read_only=True) allocated = serializers.FloatField(
on_order = serializers.FloatField(read_only=True) label=_('Allocated Stock'),
in_production = serializers.FloatField(read_only=True) read_only=True
available_stock = serializers.FloatField(read_only=True) )
on_order = serializers.FloatField(
label=_('On Order'),
read_only=True
)
in_production = serializers.FloatField(
label=_('In Production'),
read_only=True
)
available_stock = serializers.FloatField(
label=_('Available Stock'),
read_only=True
)
available_substitute_stock = serializers.FloatField(read_only=True) available_substitute_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True) available_variant_stock = serializers.FloatField(read_only=True)
total_available_stock = serializers.FloatField(read_only=True) total_available_stock = serializers.FloatField(read_only=True)

View File

@ -1408,8 +1408,9 @@ class BomItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
sub_part_detail = PartBriefSerializer(source='sub_part', many=False, read_only=True) sub_part_detail = PartBriefSerializer(source='sub_part', many=False, read_only=True)
on_order = serializers.FloatField(read_only=True) on_order = serializers.FloatField(label=_('On Order'), read_only=True)
building = serializers.FloatField(read_only=True)
building = serializers.FloatField(label=_('In Production'), read_only=True)
# Cached pricing fields # Cached pricing fields
pricing_min = InvenTree.serializers.InvenTreeMoneySerializer( pricing_min = InvenTree.serializers.InvenTreeMoneySerializer(
@ -1420,7 +1421,8 @@ class BomItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
) )
# Annotated fields for available stock # Annotated fields for available stock
available_stock = serializers.FloatField(read_only=True) available_stock = serializers.FloatField(label=_('Available Stock'), read_only=True)
available_substitute_stock = serializers.FloatField(read_only=True) available_substitute_stock = serializers.FloatField(read_only=True)
available_variant_stock = serializers.FloatField(read_only=True) available_variant_stock = serializers.FloatField(read_only=True)

View File

@ -18,8 +18,8 @@ import { api } from '../../App';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { InvenTreeIcon } from '../../functions/icons'; import { InvenTreeIcon } from '../../functions/icons';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { PartThumbTable } from '../../tables/part/PartThumbTable';
import { ActionButton } from '../buttons/ActionButton'; import { ActionButton } from '../buttons/ActionButton';
import { PartThumbTable } from '../tables/part/PartThumbTable';
import { ApiImage } from './ApiImage'; import { ApiImage } from './ApiImage';
/** /**

View File

@ -92,6 +92,9 @@ export function LanguageContext({ children }: { children: JSX.Element }) {
// Reload server state (refresh status codes) // Reload server state (refresh status codes)
useServerApiState.getState().fetchServerApiState(); useServerApiState.getState().fetchServerApiState();
// Clear out cached table column names
useLocalState.getState().clearTableColumnNames();
}) })
.catch((err) => { .catch((err) => {
console.error('Failed loading translations', err); console.error('Failed loading translations', err);

View File

@ -263,7 +263,6 @@ export function openModalApiForm(props: OpenApiFormProps) {
}); });
}) })
.catch((error) => { .catch((error) => {
console.log('Error:', error);
if (error.response) { if (error.response) {
invalidResponse(error.response.status); invalidResponse(error.response.status);
} else { } else {

View File

@ -1,7 +1,7 @@
import { randomId, useLocalStorage } from '@mantine/hooks'; import { randomId, useLocalStorage } from '@mantine/hooks';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { TableFilter } from '../components/tables/Filter'; import { TableFilter } from '../tables/Filter';
/* /*
* Type definition for representing the state of a table: * Type definition for representing the state of a table:

View File

@ -30,22 +30,19 @@ const PluginManagementPanel = Loadable(
); );
const ErrorReportTable = Loadable( const ErrorReportTable = Loadable(
lazy(() => import('../../../../components/tables/settings/ErrorTable')) lazy(() => import('../../../../tables/settings/ErrorTable'))
); );
const ProjectCodeTable = Loadable( const ProjectCodeTable = Loadable(
lazy(() => import('../../../../components/tables/settings/ProjectCodeTable')) lazy(() => import('../../../../tables/settings/ProjectCodeTable'))
); );
const CustomUnitsTable = Loadable( const CustomUnitsTable = Loadable(
lazy(() => import('../../../../components/tables/settings/CustomUnitsTable')) lazy(() => import('../../../../tables/settings/CustomUnitsTable'))
); );
const PartParameterTemplateTable = Loadable( const PartParameterTemplateTable = Loadable(
lazy( lazy(() => import('../../../../tables/part/PartParameterTemplateTable'))
() =>
import('../../../../components/tables/part/PartParameterTemplateTable')
)
); );
export default function AdminCenter() { export default function AdminCenter() {

View File

@ -3,9 +3,9 @@ import { Alert, Stack, Title } from '@mantine/core';
import { IconInfoCircle } from '@tabler/icons-react'; import { IconInfoCircle } from '@tabler/icons-react';
import { GlobalSettingList } from '../../../../components/settings/SettingList'; import { GlobalSettingList } from '../../../../components/settings/SettingList';
import { PluginErrorTable } from '../../../../components/tables/plugin/PluginErrorTable';
import { PluginListTable } from '../../../../components/tables/plugin/PluginListTable';
import { useServerApiState } from '../../../../states/ApiState'; import { useServerApiState } from '../../../../states/ApiState';
import { PluginErrorTable } from '../../../../tables/plugin/PluginErrorTable';
import { PluginListTable } from '../../../../tables/plugin/PluginListTable';
export default function PluginManagementPanel() { export default function PluginManagementPanel() {
const pluginsEnabled = useServerApiState( const pluginsEnabled = useServerApiState(

View File

@ -6,17 +6,15 @@ import { StylishText } from '../../../../components/items/StylishText';
import { Loadable } from '../../../../functions/loading'; import { Loadable } from '../../../../functions/loading';
const PendingTasksTable = Loadable( const PendingTasksTable = Loadable(
lazy(() => import('../../../../components/tables/settings/PendingTasksTable')) lazy(() => import('../../../../tables/settings/PendingTasksTable'))
); );
const ScheduledTasksTable = Loadable( const ScheduledTasksTable = Loadable(
lazy( lazy(() => import('../../../../tables/settings/ScheduledTasksTable'))
() => import('../../../../components/tables/settings/ScheduledTasksTable')
)
); );
const FailedTasksTable = Loadable( const FailedTasksTable = Loadable(
lazy(() => import('../../../../components/tables/settings/FailedTasksTable')) lazy(() => import('../../../../tables/settings/FailedTasksTable'))
); );
export default function TaskManagementPanel() { export default function TaskManagementPanel() {

View File

@ -3,8 +3,8 @@ import { Anchor, Divider, Group, Stack, Text, Title } from '@mantine/core';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { GlobalSettingList } from '../../../../components/settings/SettingList'; import { GlobalSettingList } from '../../../../components/settings/SettingList';
import { GroupTable } from '../../../../components/tables/settings/GroupTable'; import { GroupTable } from '../../../../tables/settings/GroupTable';
import { UserTable } from '../../../../components/tables/settings/UserTable'; import { UserTable } from '../../../../tables/settings/UserTable';
export default function UserManagementPanel() { export default function UserManagementPanel() {
return ( return (

View File

@ -23,8 +23,8 @@ import { StylishText } from '../../../components/items/StylishText';
import { PanelGroup, PanelType } from '../../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../../components/nav/PanelGroup';
import { SettingsHeader } from '../../../components/nav/SettingsHeader'; import { SettingsHeader } from '../../../components/nav/SettingsHeader';
import { GlobalSettingList } from '../../../components/settings/SettingList'; import { GlobalSettingList } from '../../../components/settings/SettingList';
import { CurrencyTable } from '../../../components/tables/settings/CurrencyTable';
import { useServerApiState } from '../../../states/ApiState'; import { useServerApiState } from '../../../states/ApiState';
import { CurrencyTable } from '../../../tables/settings/CurrencyTable';
/** /**
* System settings page * System settings page

View File

@ -12,10 +12,10 @@ import { useMemo } from 'react';
import { api } from '../App'; import { api } from '../App';
import { PageDetail } from '../components/nav/PageDetail'; import { PageDetail } from '../components/nav/PageDetail';
import { PanelGroup } from '../components/nav/PanelGroup'; import { PanelGroup } from '../components/nav/PanelGroup';
import { NotificationTable } from '../components/tables/notifications/NotificationsTable';
import { ApiEndpoints } from '../enums/ApiEndpoints'; import { ApiEndpoints } from '../enums/ApiEndpoints';
import { useTable } from '../hooks/UseTable'; import { useTable } from '../hooks/UseTable';
import { apiUrl } from '../states/ApiState'; import { apiUrl } from '../states/ApiState';
import { NotificationTable } from '../tables/notifications/NotificationsTable';
export default function NotificationsPage() { export default function NotificationsPage() {
const unreadTable = useTable('unreadnotifications'); const unreadTable = useTable('unreadnotifications');

View File

@ -28,10 +28,6 @@ import {
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { StatusRenderer } from '../../components/render/StatusRenderer'; import { StatusRenderer } from '../../components/render/StatusRenderer';
import BuildLineTable from '../../components/tables/build/BuildLineTable';
import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
@ -41,6 +37,10 @@ import { useEditApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import BuildLineTable from '../../tables/build/BuildLineTable';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
/** /**
* Detail page for a single Build Order * Detail page for a single Build Order

View File

@ -2,7 +2,7 @@ import { t } from '@lingui/macro';
import { Stack } from '@mantine/core'; import { Stack } from '@mantine/core';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable'; import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
/** /**
* Build Order index page * Build Order index page

View File

@ -27,15 +27,6 @@ import { Breadcrumb } from '../../components/nav/BreadcrumbList';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup'; import { PanelGroup } from '../../components/nav/PanelGroup';
import { PanelType } from '../../components/nav/PanelGroup'; import { PanelType } from '../../components/nav/PanelGroup';
import { AddressTable } from '../../components/tables/company/AddressTable';
import { ContactTable } from '../../components/tables/company/ContactTable';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { ManufacturerPartTable } from '../../components/tables/purchasing/ManufacturerPartTable';
import { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable';
import { SupplierPartTable } from '../../components/tables/purchasing/SupplierPartTable';
import { ReturnOrderTable } from '../../components/tables/sales/ReturnOrderTable';
import { SalesOrderTable } from '../../components/tables/sales/SalesOrderTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
@ -44,6 +35,15 @@ import { useEditApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddressTable } from '../../tables/company/AddressTable';
import { ContactTable } from '../../tables/company/ContactTable';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable';
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
export type CompanyDetailProps = { export type CompanyDetailProps = {
title: string; title: string;

View File

@ -11,11 +11,11 @@ import { useParams } from 'react-router-dom';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import ManufacturerPartParameterTable from '../../components/tables/purchasing/ManufacturerPartParameterTable';
import { SupplierPartTable } from '../../components/tables/purchasing/SupplierPartTable';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import ManufacturerPartParameterTable from '../../tables/purchasing/ManufacturerPartParameterTable';
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
export default function ManufacturerPartDetail() { export default function ManufacturerPartDetail() {
const { id } = useParams(); const { id } = useParams();

View File

@ -11,9 +11,9 @@ import { useParams } from 'react-router-dom';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
export default function SupplierPartDetail() { export default function SupplierPartDetail() {
const { id } = useParams(); const { id } = useParams();

View File

@ -12,10 +12,10 @@ import { PlaceholderPanel } from '../../components/items/Placeholder';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { PartCategoryTree } from '../../components/nav/PartCategoryTree'; import { PartCategoryTree } from '../../components/nav/PartCategoryTree';
import { PartCategoryTable } from '../../components/tables/part/PartCategoryTable';
import { PartListTable } from '../../components/tables/part/PartTable';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { PartCategoryTable } from '../../tables/part/PartCategoryTable';
import { PartListTable } from '../../tables/part/PartTable';
/** /**
* Detail view for a single PartCategory instance. * Detail view for a single PartCategory instance.

View File

@ -41,24 +41,6 @@ import {
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { PartCategoryTree } from '../../components/nav/PartCategoryTree'; import { PartCategoryTree } from '../../components/nav/PartCategoryTree';
import { DetailsField } from '../../components/tables/Details';
import {
DetailsImageType,
ItemDetailFields,
ItemDetails
} from '../../components/tables/ItemDetails';
import { BomTable } from '../../components/tables/bom/BomTable';
import { UsedInTable } from '../../components/tables/bom/UsedInTable';
import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { PartParameterTable } from '../../components/tables/part/PartParameterTable';
import PartTestTemplateTable from '../../components/tables/part/PartTestTemplateTable';
import { PartVariantTable } from '../../components/tables/part/PartVariantTable';
import { RelatedPartTable } from '../../components/tables/part/RelatedPartTable';
import { ManufacturerPartTable } from '../../components/tables/purchasing/ManufacturerPartTable';
import { SupplierPartTable } from '../../components/tables/purchasing/SupplierPartTable';
import { SalesOrderTable } from '../../components/tables/sales/SalesOrderTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { formatPriceRange } from '../../defaults/formatters'; import { formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
@ -68,6 +50,24 @@ import { useEditApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { DetailsField } from '../../tables/Details';
import {
DetailsImageType,
ItemDetailFields,
ItemDetails
} from '../../tables/ItemDetails';
import { BomTable } from '../../tables/bom/BomTable';
import { UsedInTable } from '../../tables/bom/UsedInTable';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import { PartParameterTable } from '../../tables/part/PartParameterTable';
import PartTestTemplateTable from '../../tables/part/PartTestTemplateTable';
import { PartVariantTable } from '../../tables/part/PartVariantTable';
import { RelatedPartTable } from '../../tables/part/RelatedPartTable';
import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
/** /**
* Detail view for a single Part instance * Detail view for a single Part instance
@ -353,7 +353,7 @@ export default function PartDetail() {
}); });
} }
}); });
return data.quantity; return data?.quantity;
} }
}, },
{ {
@ -381,7 +381,7 @@ export default function PartDetail() {
}); });
} }
}); });
return data.user; return data?.user;
} }
} }
]); ]);

View File

@ -22,14 +22,14 @@ import {
} from '../../components/items/ActionDropdown'; } from '../../components/items/ActionDropdown';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { PurchaseOrderLineItemTable } from '../../components/tables/purchasing/PurchaseOrderLineItemTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import { PurchaseOrderLineItemTable } from '../../tables/purchasing/PurchaseOrderLineItemTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
/** /**
* Detail page for a single PurchaseOrder * Detail page for a single PurchaseOrder

View File

@ -9,8 +9,8 @@ import { useMemo } from 'react';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup'; import { PanelGroup } from '../../components/nav/PanelGroup';
import { CompanyTable } from '../../components/tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable'; import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
export default function PurchasingIndex() { export default function PurchasingIndex() {
const panels = useMemo(() => { const panels = useMemo(() => {

View File

@ -6,11 +6,11 @@ import { useParams } from 'react-router-dom';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
/** /**
* Detail page for a single ReturnOrder * Detail page for a single ReturnOrder

View File

@ -9,9 +9,9 @@ import { useMemo } from 'react';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup'; import { PanelGroup } from '../../components/nav/PanelGroup';
import { CompanyTable } from '../../components/tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { ReturnOrderTable } from '../../components/tables/sales/ReturnOrderTable'; import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable';
import { SalesOrderTable } from '../../components/tables/sales/SalesOrderTable'; import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
export default function PurchasingIndex() { export default function PurchasingIndex() {
const panels = useMemo(() => { const panels = useMemo(() => {

View File

@ -14,12 +14,12 @@ import { useParams } from 'react-router-dom';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { BuildOrderTable } from '../../tables/build/BuildOrderTable';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
/** /**
* Detail page for a single SalesOrder * Detail page for a single SalesOrder

View File

@ -7,10 +7,10 @@ import { useParams } from 'react-router-dom';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { StockLocationTree } from '../../components/nav/StockLocationTree'; import { StockLocationTree } from '../../components/nav/StockLocationTree';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { StockLocationTable } from '../../components/tables/stock/StockLocationTable';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { StockItemTable } from '../../tables/stock/StockItemTable';
import { StockLocationTable } from '../../tables/stock/StockLocationTable';
export default function Stock() { export default function Stock() {
const { id: _id } = useParams(); const { id: _id } = useParams();

View File

@ -33,14 +33,14 @@ import { PlaceholderPanel } from '../../components/items/Placeholder';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { StockLocationTree } from '../../components/nav/StockLocationTree'; import { StockLocationTree } from '../../components/nav/StockLocationTree';
import { AttachmentTable } from '../../components/tables/general/AttachmentTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useEditStockItem } from '../../forms/StockForms'; import { useEditStockItem } from '../../forms/StockForms';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
import { StockItemTable } from '../../tables/stock/StockItemTable';
export default function StockDetail() { export default function StockDetail() {
const { id } = useParams(); const { id } = useParams();

View File

@ -24,6 +24,12 @@ interface LocalStateProps {
loader: LoaderType; loader: LoaderType;
lastUsedPanels: Record<string, string>; lastUsedPanels: Record<string, string>;
setLastUsedPanel: (panelKey: string) => (value: string) => void; setLastUsedPanel: (panelKey: string) => (value: string) => void;
tableColumnNames: Record<string, Record<string, string>>;
getTableColumnNames: (tableKey: string) => Record<string, string>;
setTableColumnNames: (
tableKey: string
) => (names: Record<string, string>) => void;
clearTableColumnNames: () => void;
} }
export const useLocalState = create<LocalStateProps>()( export const useLocalState = create<LocalStateProps>()(
@ -55,6 +61,22 @@ export const useLocalState = create<LocalStateProps>()(
lastUsedPanels: { ...get().lastUsedPanels, [panelKey]: value } lastUsedPanels: { ...get().lastUsedPanels, [panelKey]: value }
}); });
} }
},
tableColumnNames: {},
getTableColumnNames: (tableKey) => {
return get().tableColumnNames[tableKey] || {};
},
setTableColumnNames: (tableKey) => (names) => {
// Update the table column names for the given table
set({
tableColumnNames: {
...get().tableColumnNames,
[tableKey]: names
}
});
},
clearTableColumnNames: () => {
set({ tableColumnNames: {} });
} }
}), }),
{ {

View File

@ -3,8 +3,8 @@
*/ */
export type TableColumn<T = any> = { export type TableColumn<T = any> = {
accessor: string; // The key in the record to access accessor: string; // The key in the record to access
title?: string; // The title of the column - Note: this may be supplied by the API, and is not required, but it can be overridden if required
ordering?: string; // The key in the record to sort by (defaults to accessor) ordering?: string; // The key in the record to sort by (defaults to accessor)
title: string; // The title of the column
sortable?: boolean; // Whether the column is sortable sortable?: boolean; // Whether the column is sortable
switchable?: boolean; // Whether the column is switchable switchable?: boolean; // Whether the column is switchable
hidden?: boolean; // Whether the column is hidden hidden?: boolean; // Whether the column is hidden

View File

@ -3,13 +3,13 @@
*/ */
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { formatCurrency, renderDate } from '../../defaults/formatters'; import { Thumbnail } from '../components/images/Thumbnail';
import { ModelType } from '../../enums/ModelType'; import { ProgressBar } from '../components/items/ProgressBar';
import { Thumbnail } from '../images/Thumbnail'; import { YesNoButton } from '../components/items/YesNoButton';
import { ProgressBar } from '../items/ProgressBar'; import { TableStatusRenderer } from '../components/render/StatusRenderer';
import { YesNoButton } from '../items/YesNoButton'; import { RenderOwner } from '../components/render/User';
import { TableStatusRenderer } from '../render/StatusRenderer'; import { formatCurrency, renderDate } from '../defaults/formatters';
import { RenderOwner } from '../render/User'; import { ModelType } from '../enums/ModelType';
import { TableColumn } from './Column'; import { TableColumn } from './Column';
import { ProjectCodeHoverCard } from './TableHoverCard'; import { ProjectCodeHoverCard } from './TableHoverCard';
@ -25,7 +25,7 @@ export function BooleanColumn({
switchable switchable
}: { }: {
accessor: string; accessor: string;
title: string; title?: string;
sortable?: boolean; sortable?: boolean;
switchable?: boolean; switchable?: boolean;
}): TableColumn { }): TableColumn {
@ -58,16 +58,29 @@ export function DescriptionColumn({
export function LinkColumn(): TableColumn { export function LinkColumn(): TableColumn {
return { return {
accessor: 'link', accessor: 'link',
title: t`Link`,
sortable: false sortable: false
// TODO: Custom URL hyperlink renderer? // TODO: Custom URL hyperlink renderer?
}; };
} }
export function ReferenceColumn(): TableColumn {
return {
accessor: 'reference',
sortable: true,
switchable: false
};
}
export function NoteColumn(): TableColumn {
return {
accessor: 'note',
sortable: false
};
}
export function LineItemsProgressColumn(): TableColumn { export function LineItemsProgressColumn(): TableColumn {
return { return {
accessor: 'line_items', accessor: 'line_items',
title: t`Line Items`,
sortable: true, sortable: true,
render: (record: any) => ( render: (record: any) => (
<ProgressBar <ProgressBar
@ -82,7 +95,6 @@ export function LineItemsProgressColumn(): TableColumn {
export function ProjectCodeColumn(): TableColumn { export function ProjectCodeColumn(): TableColumn {
return { return {
accessor: 'project_code', accessor: 'project_code',
title: t`Project Code`,
sortable: true, sortable: true,
render: (record: any) => ( render: (record: any) => (
<ProjectCodeHoverCard projectCode={record.project_code_detail} /> <ProjectCodeHoverCard projectCode={record.project_code_detail} />
@ -94,7 +106,6 @@ export function StatusColumn(model: ModelType) {
return { return {
accessor: 'status', accessor: 'status',
sortable: true, sortable: true,
title: t`Status`,
render: TableStatusRenderer(model) render: TableStatusRenderer(model)
}; };
} }
@ -102,7 +113,6 @@ export function StatusColumn(model: ModelType) {
export function ResponsibleColumn(): TableColumn { export function ResponsibleColumn(): TableColumn {
return { return {
accessor: 'responsible', accessor: 'responsible',
title: t`Responsible`,
sortable: true, sortable: true,
render: (record: any) => render: (record: any) =>
record.responsible && RenderOwner({ instance: record.responsible_detail }) record.responsible && RenderOwner({ instance: record.responsible_detail })
@ -112,8 +122,8 @@ export function ResponsibleColumn(): TableColumn {
export function TargetDateColumn(): TableColumn { export function TargetDateColumn(): TableColumn {
return { return {
accessor: 'target_date', accessor: 'target_date',
title: t`Target Date`,
sortable: true, sortable: true,
title: t`Target Date`,
// TODO: custom renderer which alerts user if target date is overdue // TODO: custom renderer which alerts user if target date is overdue
render: (record: any) => renderDate(record.target_date) render: (record: any) => renderDate(record.target_date)
}; };
@ -122,7 +132,6 @@ export function TargetDateColumn(): TableColumn {
export function CreationDateColumn(): TableColumn { export function CreationDateColumn(): TableColumn {
return { return {
accessor: 'creation_date', accessor: 'creation_date',
title: t`Creation Date`,
sortable: true, sortable: true,
render: (record: any) => renderDate(record.creation_date) render: (record: any) => renderDate(record.creation_date)
}; };
@ -131,7 +140,6 @@ export function CreationDateColumn(): TableColumn {
export function ShipmentDateColumn(): TableColumn { export function ShipmentDateColumn(): TableColumn {
return { return {
accessor: 'shipment_date', accessor: 'shipment_date',
title: t`Shipment Date`,
sortable: true, sortable: true,
render: (record: any) => renderDate(record.shipment_date) render: (record: any) => renderDate(record.shipment_date)
}; };

View File

@ -29,7 +29,7 @@ export function TableColumnSelect({
<Checkbox <Checkbox
checked={!col.hidden} checked={!col.hidden}
label={col.title || col.accessor} label={col.title || col.accessor}
onChange={(event) => onToggleColumn(col.accessor)} onChange={() => onToggleColumn(col.accessor)}
radius="sm" radius="sm"
/> />
</Menu.Item> </Menu.Item>

View File

@ -13,12 +13,12 @@ import {
import { useSuspenseQuery } from '@tanstack/react-query'; import { useSuspenseQuery } from '@tanstack/react-query';
import { Suspense } from 'react'; import { Suspense } from 'react';
import { api } from '../../App'; import { api } from '../App';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ProgressBar } from '../components/items/ProgressBar';
import { InvenTreeIcon } from '../../functions/icons'; import { ApiEndpoints } from '../enums/ApiEndpoints';
import { apiUrl } from '../../states/ApiState'; import { InvenTreeIcon } from '../functions/icons';
import { useGlobalSettingsState } from '../../states/SettingsState'; import { apiUrl } from '../states/ApiState';
import { ProgressBar } from '../items/ProgressBar'; import { useGlobalSettingsState } from '../states/SettingsState';
export type PartIconsType = { export type PartIconsType = {
assembly: boolean; assembly: boolean;

View File

@ -1,7 +1,7 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../enums/ModelType';
import { useServerApiState } from '../../states/ApiState'; import { useServerApiState } from '../states/ApiState';
/** /**
* Interface for the table filter choice * Interface for the table filter choice
@ -20,7 +20,7 @@ export type TableFilterChoice = {
*/ */
export type TableFilter = { export type TableFilter = {
name: string; name: string;
label: string; label?: string;
description?: string; description?: string;
type?: string; type?: string;
choices?: TableFilterChoice[]; choices?: TableFilterChoice[];

View File

@ -14,8 +14,8 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'; import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
import { TableState } from '../../hooks/UseTable'; import { StylishText } from '../components/items/StylishText';
import { StylishText } from '../items/StylishText'; import { TableState } from '../hooks/UseTable';
import { import {
TableFilter, TableFilter,
TableFilterChoice, TableFilterChoice,

View File

@ -2,7 +2,9 @@ import { t } from '@lingui/macro';
import { import {
ActionIcon, ActionIcon,
Alert, Alert,
Box,
Indicator, Indicator,
LoadingOverlay,
Space, Space,
Stack, Stack,
Tooltip Tooltip
@ -16,10 +18,13 @@ import { useQuery } from '@tanstack/react-query';
import { DataTable, DataTableSortStatus } from 'mantine-datatable'; import { DataTable, DataTableSortStatus } from 'mantine-datatable';
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; import { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
import { api } from '../../App'; import { api } from '../App';
import { TableState } from '../../hooks/UseTable'; import { ActionButton } from '../components/buttons/ActionButton';
import { ActionButton } from '../buttons/ActionButton'; import { ButtonMenu } from '../components/buttons/ButtonMenu';
import { ButtonMenu } from '../buttons/ButtonMenu'; import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { extractAvailableFields, mapFields } from '../functions/forms';
import { TableState } from '../hooks/UseTable';
import { useLocalState } from '../states/LocalState';
import { TableColumn } from './Column'; import { TableColumn } from './Column';
import { TableColumnSelect } from './ColumnSelect'; import { TableColumnSelect } from './ColumnSelect';
import { DownloadAction } from './DownloadAction'; import { DownloadAction } from './DownloadAction';
@ -93,8 +98,7 @@ const defaultInvenTreeTableProps: InvenTreeTableProps = {
barcodeActions: [], barcodeActions: [],
tableFilters: [], tableFilters: [],
tableActions: [], tableActions: [],
idAccessor: 'pk', idAccessor: 'pk'
onRowClick: (record: any, index: number, event: any) => {}
}; };
/** /**
@ -111,6 +115,73 @@ export function InvenTreeTable<T = any>({
columns: TableColumn<T>[]; columns: TableColumn<T>[];
props: InvenTreeTableProps<T>; props: InvenTreeTableProps<T>;
}) { }) {
const { getTableColumnNames, setTableColumnNames } = useLocalState();
const [fieldNames, setFieldNames] = useState<Record<string, string>>({});
// Construct table filters - note that we can introspect filter labels from column names
const filters: TableFilter[] = useMemo(() => {
return (
props.tableFilters?.map((filter) => {
return {
...filter,
label: filter.label ?? fieldNames[filter.name] ?? `? ${filter.name} ?`
};
}) ?? []
);
}, [props.tableFilters, fieldNames]);
// Request OPTIONS data from the API, before we load the table
const tableOptionQuery = useQuery({
enabled: false,
queryKey: ['options', url, tableState.tableKey],
queryFn: async () => {
return api
.options(url, {
params: tableProps.params
})
.then((response) => {
if (response.status == 200) {
// Extract field information from the API
let names: Record<string, string> = {};
let fields: ApiFormFieldSet =
extractAvailableFields(response, 'POST') || {};
// Extract flattened map of fields
mapFields(fields, (path, field) => {
if (field.label) {
names[path] = field.label;
}
});
const cacheKey = tableState.tableKey.split('-')[0];
setFieldNames(names);
setTableColumnNames(cacheKey)(names);
}
return null;
});
}
});
// Rebuild set of translated column names
useEffect(() => {
const cacheKey = tableState.tableKey.split('-')[0];
// First check the local cache
const cachedNames = getTableColumnNames(cacheKey);
if (Object.keys(cachedNames).length > 0) {
// Cached names are available - use them!
setFieldNames(cachedNames);
return;
}
// Otherwise, fetch the data from the API
tableOptionQuery.refetch();
}, [url, tableState.tableKey, props.params]);
// Build table properties based on provided props (and default props) // Build table properties based on provided props (and default props)
const tableProps: InvenTreeTableProps<T> = useMemo(() => { const tableProps: InvenTreeTableProps<T> = useMemo(() => {
return { return {
@ -139,7 +210,8 @@ export function InvenTreeTable<T = any>({
return { return {
...col, ...col,
hidden: hidden hidden: hidden,
title: col.title ?? fieldNames[col.accessor] ?? `? ${col.accessor} ?`
}; };
}); });
@ -165,6 +237,7 @@ export function InvenTreeTable<T = any>({
return cols; return cols;
}, [ }, [
columns, columns,
fieldNames,
tableProps.rowActions, tableProps.rowActions,
tableProps.enableSelection, tableProps.enableSelection,
tableState.hiddenColumns, tableState.hiddenColumns,
@ -289,7 +362,7 @@ export function InvenTreeTable<T = any>({
let queryParams = getTableFilters(true); let queryParams = getTableFilters(true);
return api return api
.get(`${url}`, { .get(url, {
params: queryParams, params: queryParams,
timeout: 30 * 1000 timeout: 30 * 1000
}) })
@ -424,10 +497,9 @@ export function InvenTreeTable<T = any>({
return ( return (
<> <>
{tableProps.enableFilters && {tableProps.enableFilters && (filters.length ?? 0) > 0 && (
(tableProps.tableFilters?.length ?? 0) > 0 && (
<FilterSelectDrawer <FilterSelectDrawer
availableFilters={tableProps.tableFilters ?? []} availableFilters={filters}
tableState={tableState} tableState={tableState}
opened={filtersVisible} opened={filtersVisible}
onClose={() => setFiltersVisible(false)} onClose={() => setFiltersVisible(false)}
@ -489,8 +561,7 @@ export function InvenTreeTable<T = any>({
onToggleColumn={toggleColumn} onToggleColumn={toggleColumn}
/> />
)} )}
{tableProps.enableFilters && {tableProps.enableFilters && filters.length > 0 && (
(tableProps.tableFilters?.length ?? 0 > 0) && (
<Indicator <Indicator
size="xs" size="xs"
label={tableState.activeFilters.length} label={tableState.activeFilters.length}
@ -513,6 +584,11 @@ export function InvenTreeTable<T = any>({
)} )}
</Group> </Group>
</Group> </Group>
<Box pos="relative">
<LoadingOverlay
visible={tableOptionQuery.isLoading || tableOptionQuery.isFetching}
/>
<DataTable <DataTable
withBorder withBorder
striped striped
@ -528,7 +604,9 @@ export function InvenTreeTable<T = any>({
sortStatus={sortStatus} sortStatus={sortStatus}
onSortStatusChange={handleSortStatusChange} onSortStatusChange={handleSortStatusChange}
selectedRecords={ selectedRecords={
tableProps.enableSelection ? tableState.selectedRecords : undefined tableProps.enableSelection
? tableState.selectedRecords
: undefined
} }
onSelectedRecordsChange={ onSelectedRecordsChange={
tableProps.enableSelection ? onSelectedRecordsChange : undefined tableProps.enableSelection ? onSelectedRecordsChange : undefined
@ -542,11 +620,12 @@ export function InvenTreeTable<T = any>({
noWrap: true, noWrap: true,
textAlignment: 'left', textAlignment: 'left',
cellsStyle: { cellsStyle: {
// TODO: Need a better way of handling "wide" cells, // TODO @SchrodingersGat : Need a better way of handling "wide" cells,
overflow: 'hidden' overflow: 'hidden'
} }
}} }}
/> />
</Box>
</Stack> </Stack>
</> </>
); );

View File

@ -1,7 +1,10 @@
import { Paper } from '@mantine/core'; import { Paper } from '@mantine/core';
import { UserRoles } from '../../enums/Roles'; import {
import { DetailImageButtonProps, DetailsImage } from '../images/DetailsImage'; DetailImageButtonProps,
DetailsImage
} from '../components/images/DetailsImage';
import { UserRoles } from '../enums/Roles';
import { DetailsField, DetailsTable } from './Details'; import { DetailsField, DetailsTable } from './Details';
/** /**

View File

@ -4,7 +4,7 @@ import { Menu } from '@mantine/core';
import { IconCopy, IconDots, IconEdit, IconTrash } from '@tabler/icons-react'; import { IconCopy, IconDots, IconEdit, IconTrash } from '@tabler/icons-react';
import { ReactNode, useMemo, useState } from 'react'; import { ReactNode, useMemo, useState } from 'react';
import { notYetImplemented } from '../../functions/notifications'; import { notYetImplemented } from '../functions/notifications';
// Type definition for a table row action // Type definition for a table row action
export type RowAction = { export type RowAction = {

View File

@ -1,3 +1,4 @@
import { t } from '@lingui/macro';
import { CloseButton, TextInput } from '@mantine/core'; import { CloseButton, TextInput } from '@mantine/core';
import { useDebouncedValue } from '@mantine/hooks'; import { useDebouncedValue } from '@mantine/hooks';
import { IconSearch } from '@tabler/icons-react'; import { IconSearch } from '@tabler/icons-react';
@ -19,11 +20,11 @@ export function TableSearchInput({
<TextInput <TextInput
value={value} value={value}
icon={<IconSearch />} icon={<IconSearch />}
placeholder="Search" placeholder={t`Search`}
onChange={(event) => setValue(event.target.value)} onChange={(event) => setValue(event.target.value)}
rightSection={ rightSection={
value.length > 0 ? ( value.length > 0 ? (
<CloseButton size="xs" onClick={(event) => setValue('')} /> <CloseButton size="xs" onClick={() => setValue('')} />
) : null ) : null
} }
/> />

View File

@ -8,20 +8,25 @@ import {
import { ReactNode, useCallback, useMemo } from 'react'; import { ReactNode, useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { formatPriceRange } from '../../../defaults/formatters'; import { Thumbnail } from '../../components/images/Thumbnail';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { YesNoButton } from '../../components/items/YesNoButton';
import { ModelType } from '../../../enums/ModelType'; import { formatPriceRange } from '../../defaults/formatters';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { bomItemFields } from '../../../forms/BomForms'; import { ModelType } from '../../enums/ModelType';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; import { UserRoles } from '../../enums/Roles';
import { getDetailUrl } from '../../../functions/urls'; import { bomItemFields } from '../../forms/BomForms';
import { useTable } from '../../../hooks/UseTable'; import { openDeleteApiForm, openEditApiForm } from '../../functions/forms';
import { apiUrl } from '../../../states/ApiState'; import { getDetailUrl } from '../../functions/urls';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { Thumbnail } from '../../images/Thumbnail'; import { apiUrl } from '../../states/ApiState';
import { YesNoButton } from '../../items/YesNoButton'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { BooleanColumn } from '../ColumnRenderers'; import {
BooleanColumn,
DescriptionColumn,
NoteColumn,
ReferenceColumn
} from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
@ -58,10 +63,8 @@ export function BomTable({
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [
// TODO: Improve column rendering
{ {
accessor: 'part', accessor: 'part',
title: t`Part`,
switchable: false, switchable: false,
sortable: true, sortable: true,
render: (record) => { render: (record) => {
@ -91,18 +94,12 @@ export function BomTable({
); );
} }
}, },
{ DescriptionColumn({
accessor: 'description', accessor: 'sub_part_detail.description'
title: t`Description`, }),
render: (row) => row?.sub_part_detail?.description ReferenceColumn(),
},
{
accessor: 'reference',
title: t`Reference`
},
{ {
accessor: 'quantity', accessor: 'quantity',
title: t`Quantity`,
switchable: false, switchable: false,
sortable: true sortable: true
// TODO: Custom quantity renderer // TODO: Custom quantity renderer
@ -110,7 +107,6 @@ export function BomTable({
}, },
{ {
accessor: 'substitutes', accessor: 'substitutes',
title: t`Substitutes`,
// TODO: Show hovercard with list of substitutes // TODO: Show hovercard with list of substitutes
render: (row) => { render: (row) => {
let substitutes = row.substitutes ?? []; let substitutes = row.substitutes ?? [];
@ -123,20 +119,16 @@ export function BomTable({
} }
}, },
BooleanColumn({ BooleanColumn({
accessor: 'optional', accessor: 'optional'
title: t`Optional`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'consumable', accessor: 'consumable'
title: t`Consumable`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'allow_variants', accessor: 'allow_variants'
title: t`Allow Variants`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'inherited', accessor: 'inherited'
title: t`Gets Inherited`
// TODO: Custom renderer for this column // TODO: Custom renderer for this column
// TODO: See bom.js for existing implementation // TODO: See bom.js for existing implementation
}), }),
@ -150,7 +142,6 @@ export function BomTable({
}, },
{ {
accessor: 'available_stock', accessor: 'available_stock',
title: t`Available`,
render: (record) => { render: (record) => {
let extra: ReactNode[] = []; let extra: ReactNode[] = [];
@ -225,11 +216,7 @@ export function BomTable({
); );
} }
}, },
{ NoteColumn()
accessor: 'note',
title: t`Notes`,
switchable: true
}
]; ];
}, [partId, params]); }, [partId, params]);
@ -247,32 +234,26 @@ export function BomTable({
}, },
{ {
name: 'available_stock', name: 'available_stock',
label: t`Has Available Stock`,
description: t`Show items with available stock` description: t`Show items with available stock`
}, },
{ {
name: 'on_order', name: 'on_order',
label: t`On Order`,
description: t`Show items on order` description: t`Show items on order`
}, },
{ {
name: 'validated', name: 'validated',
label: t`Validated`,
description: t`Show validated items` description: t`Show validated items`
}, },
{ {
name: 'inherited', name: 'inherited',
label: t`Gets Inherited`,
description: t`Show inherited items` description: t`Show inherited items`
}, },
{ {
name: 'optional', name: 'optional',
label: t`Optional`,
description: t`Show optional items` description: t`Show optional items`
}, },
{ {
name: 'consumable', name: 'consumable',
label: t`Consumable`,
description: t`Show consumable items` description: t`Show consumable items`
}, },
{ {

View File

@ -2,13 +2,14 @@ import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { PartHoverCard } from '../../components/images/Thumbnail';
import { ModelType } from '../../../enums/ModelType'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { getDetailUrl } from '../../../functions/urls'; import { ModelType } from '../../enums/ModelType';
import { useTable } from '../../../hooks/UseTable'; import { getDetailUrl } from '../../functions/urls';
import { apiUrl } from '../../../states/ApiState'; import { useTable } from '../../hooks/UseTable';
import { PartHoverCard } from '../../images/Thumbnail'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { ReferenceColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
@ -30,30 +31,23 @@ export function UsedInTable({
return [ return [
{ {
accessor: 'part', accessor: 'part',
title: t`Assembled Part`,
switchable: false, switchable: false,
sortable: true, sortable: true,
render: (record: any) => <PartHoverCard part={record.part_detail} /> render: (record: any) => <PartHoverCard part={record.part_detail} />
}, },
{ {
accessor: 'sub_part', accessor: 'sub_part',
title: t`Required Part`,
sortable: true, sortable: true,
render: (record: any) => <PartHoverCard part={record.sub_part_detail} /> render: (record: any) => <PartHoverCard part={record.sub_part_detail} />
}, },
{ {
accessor: 'quantity', accessor: 'quantity',
title: t`Quantity`,
render: (record: any) => { render: (record: any) => {
// TODO: render units if appropriate // TODO: render units if appropriate
return record.quantity; return record.quantity;
} }
}, },
{ ReferenceColumn()
accessor: 'reference',
title: t`Reference`,
sortable: true
}
]; ];
}, [partId]); }, [partId]);
@ -61,12 +55,10 @@ export function UsedInTable({
return [ return [
{ {
name: 'inherited', name: 'inherited',
label: t`Gets Inherited`,
description: t`Show inherited items` description: t`Show inherited items`
}, },
{ {
name: 'optional', name: 'optional',
label: t`Optional`,
description: t`Show optional items` description: t`Show optional items`
}, },
{ {

View File

@ -8,14 +8,14 @@ import {
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { PartHoverCard } from '../../components/images/Thumbnail';
import { ModelType } from '../../../enums/ModelType'; import { ProgressBar } from '../../components/items/ProgressBar';
import { getDetailUrl } from '../../../functions/urls'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../../hooks/UseTable'; import { ModelType } from '../../enums/ModelType';
import { apiUrl } from '../../../states/ApiState'; import { getDetailUrl } from '../../functions/urls';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { PartHoverCard } from '../../images/Thumbnail'; import { apiUrl } from '../../states/ApiState';
import { ProgressBar } from '../../items/ProgressBar'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { BooleanColumn } from '../ColumnRenderers'; import { BooleanColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -31,7 +31,6 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
return [ return [
{ {
name: 'allocated', name: 'allocated',
label: t`Allocated`,
description: t`Show allocated lines` description: t`Show allocated lines`
}, },
{ {
@ -114,28 +113,24 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
return [ return [
{ {
accessor: 'bom_item', accessor: 'bom_item',
title: t`Part`,
sortable: true, sortable: true,
switchable: false, switchable: false,
render: (record: any) => <PartHoverCard part={record.part_detail} /> render: (record: any) => <PartHoverCard part={record.part_detail} />
}, },
{ {
accessor: 'reference', accessor: 'bom_item_detail.reference'
title: t`Reference`,
render: (record: any) => record.bom_item_detail.reference
}, },
BooleanColumn({ BooleanColumn({
accessor: 'bom_item_detail.consumable', accessor: 'bom_item_detail.consumable'
title: t`Consumable`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'bom_item_detail.optional', accessor: 'bom_item_detail.optional'
title: t`Optional`
}), }),
{ {
accessor: 'unit_quantity', accessor: 'bom_item_detail.quantity',
title: t`Unit Quantity`,
sortable: true, sortable: true,
title: t`Unit Quantity`,
ordering: 'unit_quantity',
render: (record: any) => { render: (record: any) => {
return ( return (
<Group position="apart"> <Group position="apart">
@ -149,7 +144,6 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
}, },
{ {
accessor: 'quantity', accessor: 'quantity',
title: t`Required Quantity`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
return ( return (
@ -164,14 +158,12 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
}, },
{ {
accessor: 'available_stock', accessor: 'available_stock',
title: t`Available`,
sortable: true, sortable: true,
switchable: false, switchable: false,
render: renderAvailableColumn render: renderAvailableColumn
}, },
{ {
accessor: 'allocated', accessor: 'allocated',
title: t`Allocated`,
switchable: false, switchable: false,
render: (record: any) => { render: (record: any) => {
return record?.bom_item_detail?.consumable ? ( return record?.bom_item_detail?.consumable ? (

View File

@ -2,24 +2,25 @@ import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { renderDate } from '../../../defaults/formatters'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { PartHoverCard } from '../../components/images/Thumbnail';
import { ModelType } from '../../../enums/ModelType'; import { ProgressBar } from '../../components/items/ProgressBar';
import { UserRoles } from '../../../enums/Roles'; import { RenderUser } from '../../components/render/User';
import { buildOrderFields } from '../../../forms/BuildForms'; import { renderDate } from '../../defaults/formatters';
import { getDetailUrl } from '../../../functions/urls'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { ModelType } from '../../enums/ModelType';
import { useTable } from '../../../hooks/UseTable'; import { UserRoles } from '../../enums/Roles';
import { apiUrl } from '../../../states/ApiState'; import { buildOrderFields } from '../../forms/BuildForms';
import { useUserState } from '../../../states/UserState'; import { getDetailUrl } from '../../functions/urls';
import { AddItemButton } from '../../buttons/AddItemButton'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { PartHoverCard } from '../../images/Thumbnail'; import { useTable } from '../../hooks/UseTable';
import { ProgressBar } from '../../items/ProgressBar'; import { apiUrl } from '../../states/ApiState';
import { RenderUser } from '../../render/User'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { import {
CreationDateColumn, CreationDateColumn,
ProjectCodeColumn, ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn, ResponsibleColumn,
StatusColumn, StatusColumn,
TargetDateColumn TargetDateColumn
@ -32,29 +33,21 @@ import { InvenTreeTable } from '../InvenTreeTable';
*/ */
function buildOrderTableColumns(): TableColumn[] { function buildOrderTableColumns(): TableColumn[] {
return [ return [
{ ReferenceColumn(),
accessor: 'reference',
sortable: true,
switchable: false,
title: t`Reference`
},
{ {
accessor: 'part', accessor: 'part',
sortable: true, sortable: true,
switchable: false, switchable: false,
title: t`Part`,
render: (record: any) => <PartHoverCard part={record.part_detail} /> render: (record: any) => <PartHoverCard part={record.part_detail} />
}, },
{ {
accessor: 'title', accessor: 'title',
sortable: false, sortable: false
title: t`Description`
}, },
{ {
accessor: 'completed', accessor: 'completed',
sortable: true, sortable: true,
switchable: false, switchable: false,
title: t`Progress`,
render: (record: any) => ( render: (record: any) => (
<ProgressBar <ProgressBar
progressLabel={true} progressLabel={true}
@ -67,7 +60,6 @@ function buildOrderTableColumns(): TableColumn[] {
ProjectCodeColumn(), ProjectCodeColumn(),
{ {
accessor: 'priority', accessor: 'priority',
title: t`Priority`,
sortable: true sortable: true
}, },
CreationDateColumn(), CreationDateColumn(),
@ -75,13 +67,11 @@ function buildOrderTableColumns(): TableColumn[] {
{ {
accessor: 'completion_date', accessor: 'completion_date',
sortable: true, sortable: true,
title: t`Completed`,
render: (record: any) => renderDate(record.completion_date) render: (record: any) => renderDate(record.completion_date)
}, },
{ {
accessor: 'issued_by', accessor: 'issued_by',
sortable: true, sortable: true,
title: t`Issued By`,
render: (record: any) => ( render: (record: any) => (
<RenderUser instance={record?.issued_by_detail} /> <RenderUser instance={record?.issued_by_detail} />
) )
@ -114,14 +104,12 @@ export function BuildOrderTable({
}, },
{ {
name: 'status', name: 'status',
label: t`Status`,
description: t`Filter by order status`, description: t`Filter by order status`,
choiceFunction: StatusFilterOptions(ModelType.build) choiceFunction: StatusFilterOptions(ModelType.build)
}, },
{ {
name: 'overdue', name: 'overdue',
type: 'boolean', type: 'boolean',
label: t`Overdue`,
description: t`Show overdue status` description: t`Show overdue status`
}, },
{ {

View File

@ -1,19 +1,19 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { YesNoButton } from '../../components/items/YesNoButton';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { YesNoButton } from '../../items/YesNoButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions'; import { RowDeleteAction, RowEditAction } from '../RowActions';
@ -33,13 +33,11 @@ export function AddressTable({
return [ return [
{ {
accessor: 'title', accessor: 'title',
title: t`Title`,
sortable: true, sortable: true,
switchable: false switchable: false
}, },
{ {
accessor: 'primary', accessor: 'primary',
title: t`Primary`,
switchable: false, switchable: false,
sortable: false, sortable: false,
render: (record: any) => YesNoButton({ value: record.primary }) render: (record: any) => YesNoButton({ value: record.primary })
@ -65,43 +63,36 @@ export function AddressTable({
}, },
{ {
accessor: 'postal_code', accessor: 'postal_code',
title: t`Postal Code`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'postal_city', accessor: 'postal_city',
title: t`City`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'province', accessor: 'province',
title: t`State / Province`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'country', accessor: 'country',
title: t`Country`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'shipping_notes', accessor: 'shipping_notes',
title: t`Courier Notes`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'internal_shipping_notes', accessor: 'internal_shipping_notes',
title: t`Internal Notes`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'link', accessor: 'link',
title: t`Link`,
sortable: false, sortable: false,
switchable: true switchable: true
} }

View File

@ -3,15 +3,15 @@ import { Group, Text } from '@mantine/core';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { Thumbnail } from '../../components/images/Thumbnail';
import { companyFields } from '../../../forms/CompanyForms'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { UserRoles } from '../../enums/Roles';
import { useTable } from '../../../hooks/UseTable'; import { companyFields } from '../../forms/CompanyForms';
import { apiUrl } from '../../../states/ApiState'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { DescriptionColumn } from '../ColumnRenderers'; import { DescriptionColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
@ -35,7 +35,6 @@ export function CompanyTable({
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Company Name`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
return ( return (
@ -53,7 +52,6 @@ export function CompanyTable({
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'website', accessor: 'website',
title: t`Website`,
sortable: false sortable: false
} }
]; ];
@ -65,7 +63,6 @@ export function CompanyTable({
fields: companyFields(), fields: companyFields(),
initialData: params, initialData: params,
onFormSuccess: (response) => { onFormSuccess: (response) => {
console.log('onFormSuccess:', response);
if (response.pk) { if (response.pk) {
let base = path ?? 'company'; let base = path ?? 'company';
navigate(`/${base}/${response.pk}`); navigate(`/${base}/${response.pk}`);

View File

@ -1,18 +1,18 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions'; import { RowDeleteAction, RowEditAction } from '../RowActions';
@ -32,25 +32,21 @@ export function ContactTable({
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Name`,
sortable: true, sortable: true,
switchable: false switchable: false
}, },
{ {
accessor: 'phone', accessor: 'phone',
title: t`Phone`,
switchable: true, switchable: true,
sortable: false sortable: false
}, },
{ {
accessor: 'email', accessor: 'email',
title: t`Email`,
switchable: true, switchable: true,
sortable: false sortable: false
}, },
{ {
accessor: 'role', accessor: 'role',
title: t`Role`,
switchable: true, switchable: true,
sortable: false sortable: false
} }

View File

@ -6,16 +6,16 @@ import { notifications } from '@mantine/notifications';
import { IconExternalLink, IconFileUpload } from '@tabler/icons-react'; import { IconExternalLink, IconFileUpload } from '@tabler/icons-react';
import { ReactNode, useEffect, useMemo, useState } from 'react'; import { ReactNode, useEffect, useMemo, useState } from 'react';
import { api } from '../../../App'; import { api } from '../../App';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AttachmentLink } from '../../components/items/AttachmentLink';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { import {
addAttachment, addAttachment,
deleteAttachment, deleteAttachment,
editAttachment editAttachment
} from '../../../forms/AttachmentForms'; } from '../../forms/AttachmentForms';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { AttachmentLink } from '../../items/AttachmentLink';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
@ -27,7 +27,6 @@ function attachmentTableColumns(): TableColumn[] {
return [ return [
{ {
accessor: 'attachment', accessor: 'attachment',
title: t`Attachment`,
sortable: false, sortable: false,
switchable: false, switchable: false,
noWrap: true, noWrap: true,
@ -44,7 +43,6 @@ function attachmentTableColumns(): TableColumn[] {
}, },
{ {
accessor: 'comment', accessor: 'comment',
title: t`Comment`,
sortable: false, sortable: false,
render: function (record: any) { render: function (record: any) {
@ -52,9 +50,8 @@ function attachmentTableColumns(): TableColumn[] {
} }
}, },
{ {
accessor: 'uploaded', accessor: 'upload_date',
title: t`Uploaded`, sortable: true,
sortable: false,
render: function (record: any) { render: function (record: any) {
return ( return (

View File

@ -1,9 +1,9 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { TableState } from '../../../hooks/UseTable'; import { TableState } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction } from '../RowActions'; import { RowAction } from '../RowActions';

View File

@ -2,20 +2,20 @@ import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { YesNoButton } from '../../components/items/YesNoButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { partCategoryFields } from '../../../forms/PartForms'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { UserRoles } from '../../enums/Roles';
import { partCategoryFields } from '../../forms/PartForms';
import { getDetailUrl } from '../../functions/urls';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { YesNoButton } from '../../items/YesNoButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn } from '../ColumnRenderers'; import { DescriptionColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -35,19 +35,16 @@ export function PartCategoryTable({ parentId }: { parentId?: any }) {
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Name`,
sortable: true, sortable: true,
switchable: false switchable: false
}, },
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'pathstring', accessor: 'pathstring',
title: t`Path`,
sortable: false sortable: false
}, },
{ {
accessor: 'structural', accessor: 'structural',
title: t`Structural`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
return <YesNoButton value={record.structural} />; return <YesNoButton value={record.structural} />;
@ -55,7 +52,6 @@ export function PartCategoryTable({ parentId }: { parentId?: any }) {
}, },
{ {
accessor: 'part_count', accessor: 'part_count',
title: t`Parts`,
sortable: true sortable: true
} }
]; ];

View File

@ -2,21 +2,21 @@ import { t } from '@lingui/macro';
import { Text } from '@mantine/core'; import { Text } from '@mantine/core';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { YesNoButton } from '../../components/items/YesNoButton';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { YesNoButton } from '../../items/YesNoButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { PartColumn } from '../ColumnRenderers'; import { DescriptionColumn, PartColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions'; import { RowDeleteAction, RowEditAction } from '../RowActions';
@ -32,20 +32,16 @@ export function PartParameterTable({ partId }: { partId: any }) {
return [ return [
{ {
accessor: 'part', accessor: 'part',
title: t`Part`,
sortable: true, sortable: true,
render: (record: any) => PartColumn(record?.part_detail) render: (record: any) => PartColumn(record?.part_detail)
}, },
{ {
accessor: 'part_detail.IPN', accessor: 'part_detail.IPN',
title: t`IPN`,
sortable: false, sortable: false,
switchable: true switchable: true
}, },
{ {
accessor: 'name', accessor: 'template_detail.name',
title: t`Parameter`,
switchable: false, switchable: false,
sortable: true, sortable: true,
render: (record) => { render: (record) => {
@ -54,16 +50,11 @@ export function PartParameterTable({ partId }: { partId: any }) {
return <Text italic={variant}>{record.template_detail?.name}</Text>; return <Text italic={variant}>{record.template_detail?.name}</Text>;
} }
}, },
{ DescriptionColumn({
accessor: 'description', accessor: 'template_detail.description'
title: t`Description`, }),
sortable: false,
render: (record) => record.template_detail?.description
},
{ {
accessor: 'data', accessor: 'data',
title: t`Value`,
switchable: false, switchable: false,
sortable: true, sortable: true,
render: (record) => { render: (record) => {
@ -83,11 +74,8 @@ export function PartParameterTable({ partId }: { partId: any }) {
} }
}, },
{ {
accessor: 'units', accessor: 'template_detail.units',
title: t`Units`, sortable: false
sortable: true,
render: (record) => record.template_detail?.units
} }
]; ];
}, [partId]); }, [partId]);

View File

@ -1,18 +1,18 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn } from '../ColumnRenderers'; import { DescriptionColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -48,23 +48,19 @@ export default function PartParameterTemplateTable() {
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Name`,
sortable: true, sortable: true,
switchable: false switchable: false
}, },
{ {
accessor: 'units', accessor: 'units',
title: t`Units`,
sortable: true sortable: true
}, },
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'checkbox', accessor: 'checkbox'
title: t`Checkbox`
}, },
{ {
accessor: 'choices', accessor: 'choices'
title: t`Choices`
} }
]; ];
}, []); }, []);

View File

@ -3,14 +3,14 @@ import { Group, Text } from '@mantine/core';
import { ReactNode, useMemo } from 'react'; import { ReactNode, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { formatPriceRange } from '../../../defaults/formatters'; import { Thumbnail } from '../../components/images/Thumbnail';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { formatPriceRange } from '../../defaults/formatters';
import { ModelType } from '../../../enums/ModelType'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { shortenString } from '../../../functions/tables'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { shortenString } from '../../functions/tables';
import { useTable } from '../../../hooks/UseTable'; import { getDetailUrl } from '../../functions/urls';
import { apiUrl } from '../../../states/ApiState'; import { useTable } from '../../hooks/UseTable';
import { Thumbnail } from '../../images/Thumbnail'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn, LinkColumn } from '../ColumnRenderers'; import { DescriptionColumn, LinkColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -26,7 +26,6 @@ function partTableColumns(): TableColumn[] {
accessor: 'name', accessor: 'name',
sortable: true, sortable: true,
noWrap: true, noWrap: true,
title: t`Part`,
render: function (record: any) { render: function (record: any) {
return ( return (
<Thumbnail <Thumbnail
@ -39,18 +38,15 @@ function partTableColumns(): TableColumn[] {
}, },
{ {
accessor: 'IPN', accessor: 'IPN',
title: t`IPN`,
sortable: true sortable: true
}, },
{ {
accessor: 'units', accessor: 'units',
sortable: true, sortable: true
title: t`Units`
}, },
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'category', accessor: 'category',
title: t`Category`,
sortable: true, sortable: true,
render: function (record: any) { render: function (record: any) {
@ -62,7 +58,6 @@ function partTableColumns(): TableColumn[] {
}, },
{ {
accessor: 'total_in_stock', accessor: 'total_in_stock',
title: t`Stock`,
sortable: true, sortable: true,
render: (record) => { render: (record) => {

View File

@ -1,18 +1,18 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers'; import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
@ -27,7 +27,6 @@ export default function PartTestTemplateTable({ partId }: { partId: number }) {
return [ return [
{ {
accessor: 'test_name', accessor: 'test_name',
title: t`Test Name`,
switchable: false, switchable: false,
sortable: true sortable: true
}, },
@ -35,16 +34,13 @@ export default function PartTestTemplateTable({ partId }: { partId: number }) {
switchable: false switchable: false
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'required', accessor: 'required'
title: t`Required`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'requires_value', accessor: 'requires_value'
title: t`Requires Value`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'requires_attachment', accessor: 'requires_attachment'
title: t`Requires Attachment`
}) })
]; ];
}, []); }, []);
@ -53,17 +49,14 @@ export default function PartTestTemplateTable({ partId }: { partId: number }) {
return [ return [
{ {
name: 'required', name: 'required',
label: t`Required`,
description: t`Show required tests` description: t`Show required tests`
}, },
{ {
name: 'requires_value', name: 'requires_value',
label: t`Requires Value`,
description: t`Show tests that require a value` description: t`Show tests that require a value`
}, },
{ {
name: 'requires_attachment', name: 'requires_attachment',
label: t`Requires Attachment`,
description: t`Show tests that require an attachment` description: t`Show tests that require an attachment`
} }
]; ];

View File

@ -4,10 +4,10 @@ import { useHover } from '@mantine/hooks';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import React, { Suspense, useEffect, useState } from 'react'; import React, { Suspense, useEffect, useState } from 'react';
import { api } from '../../../App'; import { api } from '../../App';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { Thumbnail } from '../../components/images/Thumbnail';
import { apiUrl } from '../../../states/ApiState'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { Thumbnail } from '../../images/Thumbnail'; import { apiUrl } from '../../states/ApiState';
/** /**
* Input props to table * Input props to table

View File

@ -3,18 +3,18 @@ import { Group, Text } from '@mantine/core';
import { ReactNode, useCallback, useMemo, useState } from 'react'; import { ReactNode, useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { Thumbnail } from '../../components/images/Thumbnail';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal useDeleteApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { ApiFormFieldSet } from '../../forms/fields/ApiFormField';
import { Thumbnail } from '../../images/Thumbnail';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction } from '../RowActions'; import { RowDeleteAction } from '../RowActions';

View File

@ -2,9 +2,9 @@ import { t } from '@lingui/macro';
import { Code } from '@mantine/core'; import { Code } from '@mantine/core';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable'; import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';

View File

@ -23,20 +23,23 @@ import { IconDots } from '@tabler/icons-react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { api } from '../../../App'; import { api } from '../../App';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ActionButton } from '../../components/buttons/ActionButton';
import { openEditApiForm } from '../../../functions/forms'; import {
import { useCreateApiFormModal } from '../../../hooks/UseForm'; ActionDropdown,
import { useInstance } from '../../../hooks/UseInstance'; EditItemAction
import { useTable } from '../../../hooks/UseTable'; } from '../../components/items/ActionDropdown';
import { apiUrl, useServerApiState } from '../../../states/ApiState'; import { InfoItem } from '../../components/items/InfoItem';
import { useUserState } from '../../../states/UserState'; import { StylishText } from '../../components/items/StylishText';
import { ActionButton } from '../../buttons/ActionButton'; import { DetailDrawer } from '../../components/nav/DetailDrawer';
import { ActionDropdown, EditItemAction } from '../../items/ActionDropdown'; import { PluginSettingList } from '../../components/settings/SettingList';
import { InfoItem } from '../../items/InfoItem'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { StylishText } from '../../items/StylishText'; import { openEditApiForm } from '../../functions/forms';
import { DetailDrawer } from '../../nav/DetailDrawer'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { PluginSettingList } from '../../settings/SettingList'; import { useInstance } from '../../hooks/UseInstance';
import { useTable } from '../../hooks/UseTable';
import { apiUrl, useServerApiState } from '../../states/ApiState';
import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable'; import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';
import { RowAction } from '../RowActions'; import { RowAction } from '../RowActions';

View File

@ -1,13 +1,13 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles'; import { UserRoles } from '../../enums/Roles';
import { useManufacturerPartParameterFields } from '../../../forms/CompanyForms'; import { useManufacturerPartParameterFields } from '../../forms/CompanyForms';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; import { openDeleteApiForm, openEditApiForm } from '../../functions/forms';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions'; import { RowDeleteAction, RowEditAction } from '../RowActions';

View File

@ -2,18 +2,18 @@ import { t } from '@lingui/macro';
import { ReactNode, useCallback, useMemo } from 'react'; import { ReactNode, useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useManufacturerPartFields } from '../../../forms/CompanyForms'; import { ModelType } from '../../enums/ModelType';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; import { UserRoles } from '../../enums/Roles';
import { notYetImplemented } from '../../../functions/notifications'; import { useManufacturerPartFields } from '../../forms/CompanyForms';
import { getDetailUrl } from '../../../functions/urls'; import { openDeleteApiForm, openEditApiForm } from '../../functions/forms';
import { useTable } from '../../../hooks/UseTable'; import { notYetImplemented } from '../../functions/notifications';
import { apiUrl } from '../../../states/ApiState'; import { getDetailUrl } from '../../functions/urls';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn, LinkColumn, PartColumn } from '../ColumnRenderers'; import { DescriptionColumn, LinkColumn, PartColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
@ -33,14 +33,12 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode {
return [ return [
{ {
accessor: 'part', accessor: 'part',
title: t`Part`,
switchable: 'part' in params, switchable: 'part' in params,
sortable: true, sortable: true,
render: (record: any) => PartColumn(record?.part_detail) render: (record: any) => PartColumn(record?.part_detail)
}, },
{ {
accessor: 'manufacturer', accessor: 'manufacturer',
title: t`Manufacturer`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
let manufacturer = record?.manufacturer_detail ?? {}; let manufacturer = record?.manufacturer_detail ?? {};

View File

@ -4,27 +4,28 @@ import { IconSquareArrowRight } from '@tabler/icons-react';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ProgressBar } from '../../../components/items/ProgressBar'; import { ActionButton } from '../../components/buttons/ActionButton';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ProgressBar } from '../../components/items/ProgressBar';
import { purchaseOrderLineItemFields } from '../../../forms/PurchaseOrderForms'; import { RenderStockLocation } from '../../components/render/Stock';
import { getDetailUrl } from '../../../functions/urls'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles';
import { purchaseOrderLineItemFields } from '../../forms/PurchaseOrderForms';
import { getDetailUrl } from '../../functions/urls';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { ActionButton } from '../../buttons/ActionButton';
import { AddItemButton } from '../../buttons/AddItemButton';
import { Thumbnail } from '../../images/Thumbnail';
import { RenderStockLocation } from '../../render/Stock';
import { import {
CurrencyColumn, CurrencyColumn,
LinkColumn, LinkColumn,
ReferenceColumn,
TargetDateColumn, TargetDateColumn,
TotalPriceColumn TotalPriceColumn
} from '../ColumnRenderers'; } from '../ColumnRenderers';
@ -74,11 +75,7 @@ export function PurchaseOrderLineItemTable({
sortable: false, sortable: false,
render: (record: any) => record?.part_detail?.description render: (record: any) => record?.part_detail?.description
}, },
{ ReferenceColumn(),
accessor: 'reference',
title: t`Reference`,
sortable: true
},
{ {
accessor: 'quantity', accessor: 'quantity',
title: t`Quantity`, title: t`Quantity`,

View File

@ -2,22 +2,23 @@ import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { purchaseOrderFields } from '../../../forms/PurchaseOrderForms'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { UserRoles } from '../../enums/Roles';
import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { purchaseOrderFields } from '../../forms/PurchaseOrderForms';
import { useTable } from '../../../hooks/UseTable'; import { getDetailUrl } from '../../functions/urls';
import { apiUrl } from '../../../states/ApiState'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { import {
CreationDateColumn, CreationDateColumn,
DescriptionColumn, DescriptionColumn,
LineItemsProgressColumn, LineItemsProgressColumn,
ProjectCodeColumn, ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn, ResponsibleColumn,
StatusColumn, StatusColumn,
TargetDateColumn, TargetDateColumn,
@ -65,13 +66,7 @@ export function PurchaseOrderTable({
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {
return [ return [
{ ReferenceColumn(),
accessor: 'reference',
title: t`Reference`,
sortable: true,
switchable: false
// TODO: Display extra information if order is overdue
},
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'supplier__name', accessor: 'supplier__name',
@ -90,8 +85,7 @@ export function PurchaseOrderTable({
} }
}, },
{ {
accessor: 'supplier_reference', accessor: 'supplier_reference'
title: t`Supplier Reference`
}, },
LineItemsProgressColumn(), LineItemsProgressColumn(),
StatusColumn(ModelType.purchaseorder), StatusColumn(ModelType.purchaseorder),

View File

@ -3,20 +3,25 @@ import { Text } from '@mantine/core';
import { ReactNode, useCallback, useMemo } from 'react'; import { ReactNode, useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useSupplierPartFields } from '../../../forms/CompanyForms'; import { ModelType } from '../../enums/ModelType';
import { openDeleteApiForm, openEditApiForm } from '../../../functions/forms'; import { UserRoles } from '../../enums/Roles';
import { getDetailUrl } from '../../../functions/urls'; import { useSupplierPartFields } from '../../forms/CompanyForms';
import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { openDeleteApiForm, openEditApiForm } from '../../functions/forms';
import { useTable } from '../../../hooks/UseTable'; import { getDetailUrl } from '../../functions/urls';
import { apiUrl } from '../../../states/ApiState'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn, LinkColumn, PartColumn } from '../ColumnRenderers'; import {
DescriptionColumn,
LinkColumn,
NoteColumn,
PartColumn
} from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowDeleteAction, RowEditAction } from '../RowActions'; import { RowDeleteAction, RowEditAction } from '../RowActions';
import { TableHoverCard } from '../TableHoverCard'; import { TableHoverCard } from '../TableHoverCard';
@ -36,14 +41,12 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
return [ return [
{ {
accessor: 'part', accessor: 'part',
title: t`Part`,
switchable: 'part' in params, switchable: 'part' in params,
sortable: true, sortable: true,
render: (record: any) => PartColumn(record?.part_detail) render: (record: any) => PartColumn(record?.part_detail)
}, },
{ {
accessor: 'supplier', accessor: 'supplier',
title: t`Supplier`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
let supplier = record?.supplier_detail ?? {}; let supplier = record?.supplier_detail ?? {};
@ -68,7 +71,6 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
accessor: 'manufacturer', accessor: 'manufacturer',
sortable: true, sortable: true,
title: t`Manufacturer`,
render: (record: any) => { render: (record: any) => {
let manufacturer = record?.manufacturer_detail ?? {}; let manufacturer = record?.manufacturer_detail ?? {};
@ -91,17 +93,14 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
}, },
{ {
accessor: 'in_stock', accessor: 'in_stock',
title: t`In Stock`,
sortable: true sortable: true
}, },
{ {
accessor: 'packaging', accessor: 'packaging',
title: t`Packaging`,
sortable: true sortable: true
}, },
{ {
accessor: 'pack_quantity', accessor: 'pack_quantity',
title: t`Pack Quantity`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {
@ -127,14 +126,9 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
} }
}, },
LinkColumn(), LinkColumn(),
{ NoteColumn(),
accessor: 'note',
title: t`Notes`,
sortable: false
},
{ {
accessor: 'available', accessor: 'available',
title: t`Availability`,
sortable: true, sortable: true,
render: (record: any) => { render: (record: any) => {

View File

@ -2,24 +2,26 @@ import { t } from '@lingui/macro';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { notYetImplemented } from '../../../functions/notifications'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { UserRoles } from '../../enums/Roles';
import { useTable } from '../../../hooks/UseTable'; import { notYetImplemented } from '../../functions/notifications';
import { apiUrl } from '../../../states/ApiState'; import { getDetailUrl } from '../../functions/urls';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { import {
CreationDateColumn, CreationDateColumn,
DescriptionColumn, DescriptionColumn,
LineItemsProgressColumn, LineItemsProgressColumn,
ProjectCodeColumn, ProjectCodeColumn,
ReferenceColumn,
ResponsibleColumn, ResponsibleColumn,
StatusColumn, StatusColumn,
TargetDateColumn TargetDateColumn,
TotalPriceColumn
} from '../ColumnRenderers'; } from '../ColumnRenderers';
import { import {
AssignedToMeFilter, AssignedToMeFilter,
@ -56,12 +58,7 @@ export function ReturnOrderTable({ params }: { params?: any }) {
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {
return [ return [
{ ReferenceColumn(),
accessor: 'reference',
title: t`Return Order`,
sortable: true
// TODO: Display extra information if order is overdue
},
{ {
accessor: 'customer__name', accessor: 'customer__name',
title: t`Customer`, title: t`Customer`,
@ -79,8 +76,7 @@ export function ReturnOrderTable({ params }: { params?: any }) {
} }
}, },
{ {
accessor: 'customer_reference', accessor: 'customer_reference'
title: t`Customer Reference`
}, },
DescriptionColumn({}), DescriptionColumn({}),
LineItemsProgressColumn(), LineItemsProgressColumn(),
@ -89,10 +85,7 @@ export function ReturnOrderTable({ params }: { params?: any }) {
CreationDateColumn(), CreationDateColumn(),
TargetDateColumn(), TargetDateColumn(),
ResponsibleColumn(), ResponsibleColumn(),
{ TotalPriceColumn()
accessor: 'total_cost',
title: t`Total Cost`
}
]; ];
}, []); }, []);

View File

@ -2,22 +2,23 @@ import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { Thumbnail } from '../../components/images/Thumbnail';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { salesOrderFields } from '../../../forms/SalesOrderForms'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { UserRoles } from '../../enums/Roles';
import { useCreateApiFormModal } from '../../../hooks/UseForm'; import { salesOrderFields } from '../../forms/SalesOrderForms';
import { useTable } from '../../../hooks/UseTable'; import { getDetailUrl } from '../../functions/urls';
import { apiUrl } from '../../../states/ApiState'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useUserState } from '../../../states/UserState'; import { useTable } from '../../hooks/UseTable';
import { AddItemButton } from '../../buttons/AddItemButton'; import { apiUrl } from '../../states/ApiState';
import { Thumbnail } from '../../images/Thumbnail'; import { useUserState } from '../../states/UserState';
import { import {
CreationDateColumn, CreationDateColumn,
DescriptionColumn, DescriptionColumn,
LineItemsProgressColumn, LineItemsProgressColumn,
ProjectCodeColumn, ProjectCodeColumn,
ReferenceColumn,
ShipmentDateColumn, ShipmentDateColumn,
StatusColumn, StatusColumn,
TargetDateColumn, TargetDateColumn,
@ -88,13 +89,7 @@ export function SalesOrderTable({
const tableColumns = useMemo(() => { const tableColumns = useMemo(() => {
return [ return [
{ ReferenceColumn(),
accessor: 'reference',
title: t`Sales Order`,
sortable: true,
switchable: false
// TODO: Display extra information if order is overdue
},
{ {
accessor: 'customer__name', accessor: 'customer__name',
title: t`Customer`, title: t`Customer`,

View File

@ -3,11 +3,11 @@ import { showNotification } from '@mantine/notifications';
import { IconReload } from '@tabler/icons-react'; import { IconReload } from '@tabler/icons-react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { api } from '../../../App'; import { api } from '../../App';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ActionButton } from '../../components/buttons/ActionButton';
import { useTable } from '../../../hooks/UseTable'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { apiUrl } from '../../../states/ApiState'; import { useTable } from '../../hooks/UseTable';
import { ActionButton } from '../../buttons/ActionButton'; import { apiUrl } from '../../states/ApiState';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
/* /*

View File

@ -1,18 +1,18 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { customUnitsFields } from '../../../forms/CommonForms'; import { UserRoles } from '../../enums/Roles';
import { customUnitsFields } from '../../forms/CommonForms';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
@ -29,19 +29,16 @@ export default function CustomUnitsTable() {
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Name`,
switchable: false, switchable: false,
sortable: true sortable: true
}, },
{ {
accessor: 'definition', accessor: 'definition',
title: t`Definition`,
switchable: false, switchable: false,
sortable: false sortable: false
}, },
{ {
accessor: 'symbol', accessor: 'symbol',
title: t`Symbol`,
switchable: false, switchable: false,
sortable: true sortable: true
} }

View File

@ -3,11 +3,11 @@ import { Drawer, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { StylishText } from '../../components/items/StylishText';
import { openDeleteApiForm } from '../../../functions/forms'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../../hooks/UseTable'; import { openDeleteApiForm } from '../../functions/forms';
import { apiUrl } from '../../../states/ApiState'; import { useTable } from '../../hooks/UseTable';
import { StylishText } from '../../items/StylishText'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction } from '../RowActions'; import { RowAction, RowDeleteAction } from '../RowActions';

View File

@ -3,10 +3,10 @@ import { Drawer, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks'; import { useDisclosure } from '@mantine/hooks';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { StylishText } from '../../components/items/StylishText';
import { useTable } from '../../../hooks/UseTable'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { apiUrl } from '../../../states/ApiState'; import { useTable } from '../../hooks/UseTable';
import { StylishText } from '../../items/StylishText'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';

View File

@ -3,18 +3,18 @@ import { Group, LoadingOverlay, Stack, Text, Title } from '@mantine/core';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { EditApiForm } from '../../components/forms/ApiForm';
import { PlaceholderPill } from '../../components/items/Placeholder';
import { DetailDrawer } from '../../components/nav/DetailDrawer';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal useDeleteApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useInstance } from '../../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { EditApiForm } from '../../forms/ApiForm';
import { PlaceholderPill } from '../../items/Placeholder';
import { DetailDrawer } from '../../nav/DetailDrawer';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions'; import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';

View File

@ -1,9 +1,9 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';

View File

@ -1,18 +1,18 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { UserRoles } from '../../../enums/Roles'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { projectCodeFields } from '../../../forms/CommonForms'; import { UserRoles } from '../../enums/Roles';
import { projectCodeFields } from '../../forms/CommonForms';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn, ResponsibleColumn } from '../ColumnRenderers'; import { DescriptionColumn, ResponsibleColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
@ -30,8 +30,7 @@ export default function ProjectCodeTable() {
return [ return [
{ {
accessor: 'code', accessor: 'code',
sortable: true, sortable: true
title: t`Project Code`
}, },
DescriptionColumn({}), DescriptionColumn({}),
ResponsibleColumn() ResponsibleColumn()

View File

@ -3,9 +3,9 @@ import { Group, Text } from '@mantine/core';
import { IconCircleCheck, IconCircleX } from '@tabler/icons-react'; import { IconCircleCheck, IconCircleX } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';

View File

@ -5,15 +5,15 @@ import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms'; import { EditApiForm } from '../../components/forms/ApiForm';
import { useInstance } from '../../../hooks/UseInstance'; import { DetailDrawer } from '../../components/nav/DetailDrawer';
import { useTable } from '../../../hooks/UseTable'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { apiUrl } from '../../../states/ApiState'; import { openCreateApiForm, openDeleteApiForm } from '../../functions/forms';
import { useUserState } from '../../../states/UserState'; import { useInstance } from '../../hooks/UseInstance';
import { AddItemButton } from '../../buttons/AddItemButton'; import { useTable } from '../../hooks/UseTable';
import { EditApiForm } from '../../forms/ApiForm'; import { apiUrl } from '../../states/ApiState';
import { DetailDrawer } from '../../nav/DetailDrawer'; import { useUserState } from '../../states/UserState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { BooleanColumn } from '../ColumnRenderers'; import { BooleanColumn } from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
@ -153,45 +153,37 @@ export function UserTable() {
return [ return [
{ {
accessor: 'email', accessor: 'email',
sortable: true, sortable: true
title: t`Email`
}, },
{ {
accessor: 'username', accessor: 'username',
sortable: true, sortable: true,
switchable: false, switchable: false
title: t`Username`
}, },
{ {
accessor: 'first_name', accessor: 'first_name',
sortable: true, sortable: true
title: t`First Name`
}, },
{ {
accessor: 'last_name', accessor: 'last_name',
sortable: true, sortable: true
title: t`Last Name`
}, },
{ {
accessor: 'groups', accessor: 'groups',
sortable: true, sortable: true,
switchable: true, switchable: true,
title: t`Groups`,
render: (record: any) => { render: (record: any) => {
return record.groups.length; return record.groups.length;
} }
}, },
BooleanColumn({ BooleanColumn({
accessor: 'is_staff', accessor: 'is_staff'
title: t`Staff`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'is_superuser', accessor: 'is_superuser'
title: t`Superuser`
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'is_active', accessor: 'is_active'
title: t`Active`
}) })
]; ];
}, []); }, []);

View File

@ -3,17 +3,21 @@ import { Group, Text } from '@mantine/core';
import { ReactNode, useMemo } from 'react'; import { ReactNode, useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { formatCurrency, renderDate } from '../../../defaults/formatters'; import { formatCurrency, renderDate } from '../../defaults/formatters';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../../functions/urls'; import { getDetailUrl } from '../../functions/urls';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { PartColumn, StatusColumn } from '../ColumnRenderers'; import {
DescriptionColumn,
PartColumn,
StatusColumn
} from '../ColumnRenderers';
import { StatusFilterOptions, TableFilter } from '../Filter'; import { StatusFilterOptions, TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable';
import { TableHoverCard } from '../TableHoverCard'; import { TableHoverCard } from '../TableHoverCard';
import { InvenTreeTable } from './../InvenTreeTable';
/** /**
* Construct a list of columns for the stock item table * Construct a list of columns for the stock item table
@ -23,14 +27,11 @@ function stockItemTableColumns(): TableColumn[] {
{ {
accessor: 'part', accessor: 'part',
sortable: true, sortable: true,
title: t`Part`,
render: (record: any) => PartColumn(record?.part_detail) render: (record: any) => PartColumn(record?.part_detail)
}, },
{ DescriptionColumn({
accessor: 'part_detail.description', accessor: 'part_detail.description'
sortable: false, }),
title: t`Description`
},
{ {
accessor: 'quantity', accessor: 'quantity',
sortable: true, sortable: true,
@ -176,15 +177,11 @@ function stockItemTableColumns(): TableColumn[] {
StatusColumn(ModelType.stockitem), StatusColumn(ModelType.stockitem),
{ {
accessor: 'batch', accessor: 'batch',
sortable: true, sortable: true
title: t`Batch`
}, },
{ {
accessor: 'location', accessor: 'location',
sortable: true, sortable: true,
title: t`Location`,
render: function (record: any) { render: function (record: any) {
// TODO: Custom renderer for location // TODO: Custom renderer for location
// TODO: Note, if not "In stock" we don't want to display the actual location here // TODO: Note, if not "In stock" we don't want to display the actual location here
@ -195,14 +192,12 @@ function stockItemTableColumns(): TableColumn[] {
{ {
accessor: 'expiry_date', accessor: 'expiry_date',
sortable: true, sortable: true,
title: t`Expiry Date`,
switchable: true, switchable: true,
render: (record: any) => renderDate(record.expiry_date) render: (record: any) => renderDate(record.expiry_date)
}, },
{ {
accessor: 'updated', accessor: 'updated',
sortable: true, sortable: true,
title: t`Last Updated`,
switchable: true, switchable: true,
render: (record: any) => renderDate(record.updated) render: (record: any) => renderDate(record.updated)
}, },
@ -211,7 +206,6 @@ function stockItemTableColumns(): TableColumn[] {
{ {
accessor: 'purchase_price', accessor: 'purchase_price',
sortable: true, sortable: true,
title: t`Purchase Price`,
switchable: true, switchable: true,
render: (record: any) => render: (record: any) =>
formatCurrency(record.purchase_price, { formatCurrency(record.purchase_price, {

View File

@ -2,22 +2,21 @@ import { t } from '@lingui/macro';
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ApiEndpoints } from '../../../enums/ApiEndpoints'; import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ModelType } from '../../../enums/ModelType'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../../enums/Roles'; import { ModelType } from '../../enums/ModelType';
import { stockLocationFields } from '../../../forms/StockForms'; import { UserRoles } from '../../enums/Roles';
import { getDetailUrl } from '../../../functions/urls'; import { stockLocationFields } from '../../forms/StockForms';
import { getDetailUrl } from '../../functions/urls';
import { import {
useCreateApiFormModal, useCreateApiFormModal,
useEditApiFormModal useEditApiFormModal
} from '../../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useTable } from '../../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../../states/UserState'; import { useUserState } from '../../states/UserState';
import { AddItemButton } from '../../buttons/AddItemButton';
import { YesNoButton } from '../../items/YesNoButton';
import { TableColumn } from '../Column'; import { TableColumn } from '../Column';
import { DescriptionColumn } from '../ColumnRenderers'; import { BooleanColumn, DescriptionColumn } from '../ColumnRenderers';
import { TableFilter } from '../Filter'; import { TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable'; import { InvenTreeTable } from '../InvenTreeTable';
import { RowEditAction } from '../RowActions'; import { RowEditAction } from '../RowActions';
@ -40,12 +39,10 @@ export function StockLocationTable({ parentId }: { parentId?: any }) {
}, },
{ {
name: 'structural', name: 'structural',
label: t`Structural`,
description: t`Show structural locations` description: t`Show structural locations`
}, },
{ {
name: 'external', name: 'external',
label: t`External`,
description: t`Show external locations` description: t`Show external locations`
}, },
{ {
@ -60,39 +57,25 @@ export function StockLocationTable({ parentId }: { parentId?: any }) {
return [ return [
{ {
accessor: 'name', accessor: 'name',
title: t`Name`,
switchable: false switchable: false
}, },
DescriptionColumn({}), DescriptionColumn({}),
{ {
accessor: 'pathstring', accessor: 'pathstring',
title: t`Path`,
sortable: true sortable: true
}, },
{ {
accessor: 'items', accessor: 'items',
title: t`Stock Items`,
sortable: true sortable: true
}, },
{ BooleanColumn({
accessor: 'structural', accessor: 'structural'
title: t`Structural`, }),
BooleanColumn({
sortable: true, accessor: 'external'
render: (record: any) => <YesNoButton value={record.structural} /> }),
},
{
accessor: 'external',
title: t`External`,
sortable: true,
render: (record: any) => <YesNoButton value={record.external} />
},
{ {
accessor: 'location_type', accessor: 'location_type',
title: t`Location Type`,
sortable: false, sortable: false,
render: (record: any) => record.location_type_detail?.name render: (record: any) => record.location_type_detail?.name
} }

View File

@ -35,7 +35,6 @@ export default function DesktopAppView() {
const [token] = sessionState.token ? [sessionState.token] : [null]; const [token] = sessionState.token ? [sessionState.token] : [null];
useEffect(() => { useEffect(() => {
if (Object.keys(hostList).length === 0) { if (Object.keys(hostList).length === 0) {
console.log('Loading default host list', defaultHostList);
useLocalState.setState({ hostList: defaultHostList }); useLocalState.setState({ hostList: defaultHostList });
} }