diff --git a/src/frontend/src/components/forms/ApiForm.tsx b/src/frontend/src/components/forms/ApiForm.tsx
index 0231f8c649..b7475eb278 100644
--- a/src/frontend/src/components/forms/ApiForm.tsx
+++ b/src/frontend/src/components/forms/ApiForm.tsx
@@ -70,6 +70,8 @@ export interface ApiFormProps {
fetchInitialData?: boolean;
ignorePermissionCheck?: boolean;
preFormContent?: JSX.Element;
+ preFormWarning?: string;
+ preFormSuccess?: string;
postFormContent?: JSX.Element;
successMessage?: string;
onFormSuccess?: (data: any) => void;
@@ -287,7 +289,10 @@ export function ApiForm({ id, props }: { id: string; props: ApiFormProps }) {
// Optionally show a success message
if (props.successMessage) {
+ notifications.hide('form-success');
+
notifications.show({
+ id: 'form-success',
title: t`Success`,
message: props.successMessage,
color: 'green'
@@ -371,6 +376,16 @@ export function ApiForm({ id, props }: { id: string; props: ApiFormProps }) {
)}
{props.preFormContent}
+ {props.preFormSuccess && (
+
+ {props.preFormSuccess}
+
+ )}
+ {props.preFormWarning && (
+
+ {props.preFormWarning}
+
+ )}
{Object.entries(props.fields ?? {}).map(([fieldName, field]) => (
- {value ? t`Yes` : t`No`}
+ {v ? t`Yes` : t`No`}
);
}
diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx
index 17efca6512..490874b4af 100644
--- a/src/frontend/src/components/render/Instance.tsx
+++ b/src/frontend/src/components/render/Instance.tsx
@@ -110,8 +110,8 @@ export function RenderInlineModel({
// TODO: Handle URL
return (
-
-
+
+
{image && Thumbnail({ src: image, size: 18 })}
{primary}
{secondary && {secondary}}
diff --git a/src/frontend/src/components/tables/bom/BomTable.tsx b/src/frontend/src/components/tables/bom/BomTable.tsx
index ee7f340615..a9bc316fa6 100644
--- a/src/frontend/src/components/tables/bom/BomTable.tsx
+++ b/src/frontend/src/components/tables/bom/BomTable.tsx
@@ -306,9 +306,7 @@ export function BomTable({
title: t`Delete Bom Item`,
successMessage: t`Bom item deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to remove this BOM item?`}
- )
+ preFormWarning: t`Are you sure you want to remove this BOM item?`
});
}
})
diff --git a/src/frontend/src/components/tables/company/AddressTable.tsx b/src/frontend/src/components/tables/company/AddressTable.tsx
new file mode 100644
index 0000000000..35e0cbdeab
--- /dev/null
+++ b/src/frontend/src/components/tables/company/AddressTable.tsx
@@ -0,0 +1,196 @@
+import { t } from '@lingui/macro';
+import { useCallback, useMemo } from 'react';
+
+import { ApiPaths } from '../../../enums/ApiEndpoints';
+import { UserRoles } from '../../../enums/Roles';
+import { addressFields } from '../../../forms/CompanyForms';
+import {
+ openCreateApiForm,
+ openDeleteApiForm,
+ openEditApiForm
+} from '../../../functions/forms';
+import { useTable } from '../../../hooks/UseTable';
+import { apiUrl } from '../../../states/ApiState';
+import { useUserState } from '../../../states/UserState';
+import { AddItemButton } from '../../buttons/AddItemButton';
+import { YesNoButton } from '../../items/YesNoButton';
+import { TableColumn } from '../Column';
+import { InvenTreeTable } from '../InvenTreeTable';
+import { RowDeleteAction, RowEditAction } from '../RowActions';
+
+export function AddressTable({
+ companyId,
+ params
+}: {
+ companyId: number;
+ params?: any;
+}) {
+ const user = useUserState();
+
+ const table = useTable('address');
+
+ const columns: TableColumn[] = useMemo(() => {
+ return [
+ {
+ accessor: 'title',
+ title: t`Title`,
+ sortable: true,
+ switchable: false
+ },
+ {
+ accessor: 'primary',
+ title: t`Primary`,
+ switchable: false,
+ sortable: false,
+ render: (record: any) => YesNoButton({ value: record.primary })
+ },
+ {
+ accessor: 'address',
+ title: t`Address`,
+ sortable: false,
+ switchable: false,
+ render: (record: any) => {
+ let address = '';
+
+ if (record?.line1) {
+ address += record.line1;
+ }
+
+ if (record?.line2) {
+ address += ' ' + record.line2;
+ }
+
+ return address.trim();
+ }
+ },
+ {
+ accessor: 'postal_code',
+ title: t`Postal Code`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'postal_city',
+ title: t`City`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'province',
+ title: t`State / Province`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'country',
+ title: t`Country`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'shipping_notes',
+ title: t`Courier Notes`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'internal_shipping_notes',
+ title: t`Internal Notes`,
+ sortable: false,
+ switchable: true
+ },
+ {
+ accessor: 'link',
+ title: t`Link`,
+ sortable: false,
+ switchable: true
+ }
+ ];
+ }, []);
+
+ const rowActions = useCallback(
+ (record: any) => {
+ let can_edit =
+ user.hasChangeRole(UserRoles.purchase_order) ||
+ user.hasChangeRole(UserRoles.sales_order);
+
+ let can_delete =
+ user.hasDeleteRole(UserRoles.purchase_order) ||
+ user.hasDeleteRole(UserRoles.sales_order);
+
+ return [
+ RowEditAction({
+ hidden: !can_edit,
+ onClick: () => {
+ openEditApiForm({
+ url: ApiPaths.address_list,
+ pk: record.pk,
+ title: t`Edit Address`,
+ fields: addressFields(),
+ successMessage: t`Address updated`,
+ onFormSuccess: table.refreshTable
+ });
+ }
+ }),
+ RowDeleteAction({
+ hidden: !can_delete,
+ onClick: () => {
+ openDeleteApiForm({
+ url: ApiPaths.address_list,
+ pk: record.pk,
+ title: t`Delete Address`,
+ successMessage: t`Address deleted`,
+ onFormSuccess: table.refreshTable,
+ preFormWarning: t`Are you sure you want to delete this address?`
+ });
+ }
+ })
+ ];
+ },
+ [user]
+ );
+
+ const addAddress = useCallback(() => {
+ let fields = addressFields();
+
+ fields['company'].value = companyId;
+
+ openCreateApiForm({
+ url: ApiPaths.address_list,
+ title: t`Add Address`,
+ fields: fields,
+ successMessage: t`Address created`,
+ onFormSuccess: table.refreshTable
+ });
+ }, [companyId]);
+
+ const tableActions = useMemo(() => {
+ let can_add =
+ user.hasChangeRole(UserRoles.purchase_order) ||
+ user.hasChangeRole(UserRoles.sales_order);
+
+ return [
+
+ ];
+ }, [user]);
+
+ return (
+
+ );
+}
diff --git a/src/frontend/src/components/tables/general/CompanyTable.tsx b/src/frontend/src/components/tables/company/CompanyTable.tsx
similarity index 100%
rename from src/frontend/src/components/tables/general/CompanyTable.tsx
rename to src/frontend/src/components/tables/company/CompanyTable.tsx
diff --git a/src/frontend/src/components/tables/company/ContactTable.tsx b/src/frontend/src/components/tables/company/ContactTable.tsx
new file mode 100644
index 0000000000..7005abea09
--- /dev/null
+++ b/src/frontend/src/components/tables/company/ContactTable.tsx
@@ -0,0 +1,144 @@
+import { t } from '@lingui/macro';
+import { useCallback, useMemo } from 'react';
+
+import { ApiPaths } from '../../../enums/ApiEndpoints';
+import { UserRoles } from '../../../enums/Roles';
+import { contactFields } from '../../../forms/CompanyForms';
+import {
+ openCreateApiForm,
+ openDeleteApiForm,
+ openEditApiForm
+} from '../../../functions/forms';
+import { useTable } from '../../../hooks/UseTable';
+import { apiUrl } from '../../../states/ApiState';
+import { useUserState } from '../../../states/UserState';
+import { AddItemButton } from '../../buttons/AddItemButton';
+import { TableColumn } from '../Column';
+import { InvenTreeTable } from '../InvenTreeTable';
+import { RowDeleteAction, RowEditAction } from '../RowActions';
+
+export function ContactTable({
+ companyId,
+ params
+}: {
+ companyId: number;
+ params?: any;
+}) {
+ const user = useUserState();
+
+ const table = useTable('contact');
+
+ const columns: TableColumn[] = useMemo(() => {
+ return [
+ {
+ accessor: 'name',
+ title: t`Name`,
+ sortable: true,
+ switchable: false
+ },
+ {
+ accessor: 'phone',
+ title: t`Phone`,
+ switchable: true,
+ sortable: false
+ },
+ {
+ accessor: 'email',
+ title: t`Email`,
+ switchable: true,
+ sortable: false
+ },
+ {
+ accessor: 'role',
+ title: t`Role`,
+ switchable: true,
+ sortable: false
+ }
+ ];
+ }, []);
+
+ const rowActions = useCallback(
+ (record: any) => {
+ let can_edit =
+ user.hasChangeRole(UserRoles.purchase_order) ||
+ user.hasChangeRole(UserRoles.sales_order);
+ let can_delete =
+ user.hasDeleteRole(UserRoles.purchase_order) ||
+ user.hasDeleteRole(UserRoles.sales_order);
+
+ return [
+ RowEditAction({
+ hidden: !can_edit,
+ onClick: () => {
+ openEditApiForm({
+ url: ApiPaths.contact_list,
+ pk: record.pk,
+ title: t`Edit Contact`,
+ fields: contactFields(),
+ successMessage: t`Contact updated`,
+ onFormSuccess: table.refreshTable
+ });
+ }
+ }),
+ RowDeleteAction({
+ hidden: !can_delete,
+ onClick: () => {
+ openDeleteApiForm({
+ url: ApiPaths.contact_list,
+ pk: record.pk,
+ title: t`Delete Contact`,
+ successMessage: t`Contact deleted`,
+ onFormSuccess: table.refreshTable,
+ preFormWarning: t`Are you sure you want to delete this contact?`
+ });
+ }
+ })
+ ];
+ },
+ [user]
+ );
+
+ const addContact = useCallback(() => {
+ var fields = contactFields();
+
+ fields['company'].value = companyId;
+
+ openCreateApiForm({
+ url: ApiPaths.contact_list,
+ title: t`Create Contact`,
+ fields: fields,
+ successMessage: t`Contact created`,
+ onFormSuccess: table.refreshTable
+ });
+ }, [companyId]);
+
+ const tableActions = useMemo(() => {
+ let can_add =
+ user.hasAddRole(UserRoles.purchase_order) ||
+ user.hasAddRole(UserRoles.sales_order);
+
+ return [
+
+ ];
+ }, [user]);
+
+ return (
+
+ );
+}
diff --git a/src/frontend/src/components/tables/part/PartParameterTable.tsx b/src/frontend/src/components/tables/part/PartParameterTable.tsx
index 62141499a4..54788134b1 100644
--- a/src/frontend/src/components/tables/part/PartParameterTable.tsx
+++ b/src/frontend/src/components/tables/part/PartParameterTable.tsx
@@ -140,9 +140,7 @@ export function PartParameterTable({ partId }: { partId: any }) {
title: t`Delete Part Parameter`,
successMessage: t`Part parameter deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to remove this parameter?`}
- )
+ preFormWarning: t`Are you sure you want to remove this parameter?`
});
}
})
diff --git a/src/frontend/src/components/tables/part/PartParameterTemplateTable.tsx b/src/frontend/src/components/tables/part/PartParameterTemplateTable.tsx
index 7610b2f655..e9de3cf6f3 100644
--- a/src/frontend/src/components/tables/part/PartParameterTemplateTable.tsx
+++ b/src/frontend/src/components/tables/part/PartParameterTemplateTable.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { useCallback, useMemo } from 'react';
import { ApiPaths } from '../../../enums/ApiEndpoints';
@@ -39,7 +38,7 @@ export function PartParameterTemplateTable() {
{
accessor: 'description',
title: t`Description`,
- sortbale: false
+ sortable: false
},
{
accessor: 'checkbox',
@@ -78,7 +77,7 @@ export function PartParameterTemplateTable() {
title: t`Delete Parameter Template`,
successMessage: t`Parameter template deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: {t`Remove parameter template`}
+ preFormWarning: t`Are you sure you want to remove this parameter template?`
});
}
})
diff --git a/src/frontend/src/components/tables/part/PartVariantTable.tsx b/src/frontend/src/components/tables/part/PartVariantTable.tsx
index 169711570d..9f768a0d9d 100644
--- a/src/frontend/src/components/tables/part/PartVariantTable.tsx
+++ b/src/frontend/src/components/tables/part/PartVariantTable.tsx
@@ -1,7 +1,7 @@
import { PartListTable } from './PartTable';
/**
- * Display variant parts for thespecified parent part
+ * Display variant parts for the specified parent part
*/
export function PartVariantTable({ partId }: { partId: string }) {
return (
diff --git a/src/frontend/src/components/tables/part/RelatedPartTable.tsx b/src/frontend/src/components/tables/part/RelatedPartTable.tsx
index 7ce2454c9e..1a35f82fac 100644
--- a/src/frontend/src/components/tables/part/RelatedPartTable.tsx
+++ b/src/frontend/src/components/tables/part/RelatedPartTable.tsx
@@ -112,9 +112,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
pk: record.pk,
title: t`Delete Related Part`,
successMessage: t`Related part deleted`,
- preFormContent: (
- {t`Are you sure you want to remove this relationship?`}
- ),
+ preFormWarning: t`Are you sure you want to remove this relationship?`,
onFormSuccess: table.refreshTable
});
}
diff --git a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx
index 6dd65efc22..3ac913ef14 100644
--- a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx
+++ b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx
@@ -210,9 +210,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode {
title: t`Delete Supplier Part`,
successMessage: t`Supplier part deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to remove this supplier part?`}
- )
+ preFormWarning: t`Are you sure you want to remove this supplier part?`
});
}
})
diff --git a/src/frontend/src/components/tables/settings/CustomUnitsTable.tsx b/src/frontend/src/components/tables/settings/CustomUnitsTable.tsx
index 64ddc27f31..e5f8bdd2a8 100644
--- a/src/frontend/src/components/tables/settings/CustomUnitsTable.tsx
+++ b/src/frontend/src/components/tables/settings/CustomUnitsTable.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { useCallback, useMemo } from 'react';
import { ApiPaths } from '../../../enums/ApiEndpoints';
@@ -77,9 +76,7 @@ export function CustomUnitsTable() {
title: t`Delete custom unit`,
successMessage: t`Custom unit deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to remove this custom unit?`}
- )
+ preFormWarning: t`Are you sure you want to remove this custom unit?`
});
}
})
diff --git a/src/frontend/src/components/tables/settings/GroupTable.tsx b/src/frontend/src/components/tables/settings/GroupTable.tsx
index 2a862560de..5b35cd0968 100644
--- a/src/frontend/src/components/tables/settings/GroupTable.tsx
+++ b/src/frontend/src/components/tables/settings/GroupTable.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { useCallback, useMemo } from 'react';
import { ApiPaths } from '../../../enums/ApiEndpoints';
@@ -55,9 +54,7 @@ export function GroupTable() {
title: t`Delete group`,
successMessage: t`Group deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to delete this group?`}
- )
+ preFormWarning: t`Are you sure you want to delete this group?`
});
}
})
diff --git a/src/frontend/src/components/tables/settings/ProjectCodeTable.tsx b/src/frontend/src/components/tables/settings/ProjectCodeTable.tsx
index a7044f1d4e..27fa83c2b1 100644
--- a/src/frontend/src/components/tables/settings/ProjectCodeTable.tsx
+++ b/src/frontend/src/components/tables/settings/ProjectCodeTable.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { useCallback, useMemo } from 'react';
import { ApiPaths } from '../../../enums/ApiEndpoints';
@@ -67,9 +66,7 @@ export function ProjectCodeTable() {
title: t`Delete project code`,
successMessage: t`Project code deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to remove this project code?`}
- )
+ preFormWarning: t`Are you sure you want to remove this project code?`
});
}
})
diff --git a/src/frontend/src/components/tables/settings/UserTable.tsx b/src/frontend/src/components/tables/settings/UserTable.tsx
index e0a5be495e..5058d5c0f9 100644
--- a/src/frontend/src/components/tables/settings/UserTable.tsx
+++ b/src/frontend/src/components/tables/settings/UserTable.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { useCallback, useMemo, useState } from 'react';
@@ -116,9 +115,7 @@ export function UserTable() {
title: t`Delete user`,
successMessage: t`User deleted`,
onFormSuccess: table.refreshTable,
- preFormContent: (
- {t`Are you sure you want to delete this user?`}
- )
+ preFormWarning: t`Are you sure you want to delete this user?`
});
}
})
diff --git a/src/frontend/src/forms/AttachmentForms.tsx b/src/frontend/src/forms/AttachmentForms.tsx
index 3a57c6af98..deaa0b00b7 100644
--- a/src/frontend/src/forms/AttachmentForms.tsx
+++ b/src/frontend/src/forms/AttachmentForms.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/macro';
-import { Text } from '@mantine/core';
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { ApiPaths } from '../enums/ApiEndpoints';
@@ -126,8 +125,6 @@ export function deleteAttachment({
successMessage: t`Attachment deleted`,
onFormSuccess: callback,
fields: {},
- preFormContent: (
- {t`Are you sure you want to delete this attachment?`}
- )
+ preFormWarning: t`Are you sure you want to delete this attachment?`
});
}
diff --git a/src/frontend/src/forms/CompanyForms.tsx b/src/frontend/src/forms/CompanyForms.tsx
index 0cc178cc67..344b6056b6 100644
--- a/src/frontend/src/forms/CompanyForms.tsx
+++ b/src/frontend/src/forms/CompanyForms.tsx
@@ -125,3 +125,34 @@ export function editCompany({
onFormSuccess: callback
});
}
+
+export function contactFields(): ApiFormFieldSet {
+ return {
+ company: {
+ hidden: true
+ },
+ name: {},
+ phone: {},
+ email: {},
+ role: {}
+ };
+}
+
+export function addressFields(): ApiFormFieldSet {
+ return {
+ company: {
+ hidden: true
+ },
+ title: {},
+ primary: {},
+ line1: {},
+ line2: {},
+ postal_code: {},
+ postal_city: {},
+ province: {},
+ country: {},
+ shipping_notes: {},
+ internal_shipping_notes: {},
+ link: {}
+ };
+}
diff --git a/src/frontend/src/pages/company/CompanyDetail.tsx b/src/frontend/src/pages/company/CompanyDetail.tsx
index 74db811658..38c4c27f93 100644
--- a/src/frontend/src/pages/company/CompanyDetail.tsx
+++ b/src/frontend/src/pages/company/CompanyDetail.tsx
@@ -27,6 +27,8 @@ import { Breadcrumb } from '../../components/nav/BreadcrumbList';
import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } 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 { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable';
import { ReturnOrderTable } from '../../components/tables/sales/ReturnOrderTable';
@@ -128,12 +130,14 @@ export default function CompanyDetail(props: CompanyDetailProps) {
{
name: 'contacts',
label: t`Contacts`,
- icon:
+ icon: ,
+ content: company?.pk &&
},
{
name: 'addresses',
label: t`Addresses`,
- icon:
+ icon: ,
+ content: company?.pk &&
},
{
name: 'attachments',
diff --git a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx
index 4209d76a1e..31a7234e33 100644
--- a/src/frontend/src/pages/purchasing/PurchasingIndex.tsx
+++ b/src/frontend/src/pages/purchasing/PurchasingIndex.tsx
@@ -9,7 +9,7 @@ import { useMemo } from 'react';
import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup';
-import { CompanyTable } from '../../components/tables/general/CompanyTable';
+import { CompanyTable } from '../../components/tables/company/CompanyTable';
import { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable';
export default function PurchasingIndex() {
diff --git a/src/frontend/src/pages/sales/SalesIndex.tsx b/src/frontend/src/pages/sales/SalesIndex.tsx
index 0bfe2a5b74..441ba0c5bd 100644
--- a/src/frontend/src/pages/sales/SalesIndex.tsx
+++ b/src/frontend/src/pages/sales/SalesIndex.tsx
@@ -9,7 +9,7 @@ import { useMemo } from 'react';
import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/nav/PanelGroup';
-import { CompanyTable } from '../../components/tables/general/CompanyTable';
+import { CompanyTable } from '../../components/tables/company/CompanyTable';
import { ReturnOrderTable } from '../../components/tables/sales/ReturnOrderTable';
import { SalesOrderTable } from '../../components/tables/sales/SalesOrderTable';