2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-12-16 09:18:10 +00:00

Refactor segmented panels

This commit is contained in:
Oliver Walters
2025-11-25 03:54:37 +00:00
parent a65df8b1cb
commit fa081458dd
5 changed files with 154 additions and 153 deletions

View File

@@ -8,7 +8,7 @@ export type PanelType = {
label: string; label: string;
controls?: ReactNode; controls?: ReactNode;
icon?: ReactNode; icon?: ReactNode;
content: ReactNode; content?: ReactNode;
hidden?: boolean; hidden?: boolean;
disabled?: boolean; disabled?: boolean;
showHeadline?: boolean; showHeadline?: boolean;

View File

@@ -0,0 +1,53 @@
import SegmentedIconControl from '../buttons/SegmentedIconControl';
import type { PanelType } from './Panel';
export type SegmentedControlPanelSelection = {
value: string;
label: string;
icon: React.ReactNode;
content: React.ReactNode;
};
interface SegmentedPanelType extends PanelType {
options: SegmentedControlPanelSelection[];
selection: string;
onChange: (value: string) => void;
}
/**
* Display a panel which can be used to display multiple options,
* based on a built-in segmented control.
*/
export default function SegmentedControlPanel(
props: SegmentedPanelType
): PanelType {
// Extract the content based on the selection
let content = null;
for (const option of props.options) {
if (option.value === props.selection) {
content = option.content;
break;
}
}
if (content === null && props.options.length > 0) {
content = props.options[0].content;
}
return {
...props,
content: content,
controls: (
<SegmentedIconControl
value={props.selection}
onChange={props.onChange}
data={props.options.map((option: any) => ({
value: option.value,
label: option.label,
icon: option.icon
}))}
/>
)
};
}

View File

@@ -7,12 +7,12 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles'; import { UserRoles } from '@lib/enums/Roles';
import type { TableFilter } from '@lib/types/Filters'; import type { TableFilter } from '@lib/types/Filters';
import { useLocalStorage } from '@mantine/hooks'; import { useLocalStorage } from '@mantine/hooks';
import SegmentedIconControl from '../../components/buttons/SegmentedIconControl';
import OrderCalendar from '../../components/calendar/OrderCalendar'; import OrderCalendar from '../../components/calendar/OrderCalendar';
import PermissionDenied from '../../components/errors/PermissionDenied'; import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import type { PanelType } from '../../components/panels/Panel'; import type { PanelType } from '../../components/panels/Panel';
import { PanelGroup } from '../../components/panels/PanelGroup'; import { PanelGroup } from '../../components/panels/PanelGroup';
import SegmentedControlPanel from '../../components/panels/SegmentedControlPanel';
import { useGlobalSettingsState } from '../../states/SettingsStates'; import { useGlobalSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { PartCategoryFilter } from '../../tables/Filter'; import { PartCategoryFilter } from '../../tables/Filter';
@@ -43,20 +43,6 @@ function BuildOrderCalendar() {
); );
} }
function BuildOverview({
view
}: {
view: string;
}) {
switch (view) {
case 'calendar':
return <BuildOrderCalendar />;
case 'table':
default:
return <BuildOrderTable />;
}
}
/** /**
* Build Order index page * Build Order index page
*/ */
@@ -64,34 +50,35 @@ export default function BuildIndex() {
const user = useUserState(); const user = useUserState();
const [buildOrderView, setBuildOrderView] = useLocalStorage<string>({ const [buildOrderView, setBuildOrderView] = useLocalStorage<string>({
key: 'buildOrderView', key: 'build-order-view',
defaultValue: 'table' defaultValue: 'table'
}); });
const panels: PanelType[] = useMemo(() => { const panels: PanelType[] = useMemo(() => {
return [ return [
{ SegmentedControlPanel({
name: 'buildorders', name: 'buildorder',
label: t`Build Orders`, label: t`Build Orders`,
content: <BuildOverview view={buildOrderView} />,
icon: <IconTools />, icon: <IconTools />,
controls: ( selection: buildOrderView,
<SegmentedIconControl onChange: setBuildOrderView,
value={buildOrderView} options: [
onChange={setBuildOrderView} {
data={[ value: 'table',
{ value: 'table', label: t`Table View`, icon: <IconTable /> }, label: t`Table View`,
{ icon: <IconTable />,
value: 'calendar', content: <BuildOrderTable />
label: t`Calendar View`, },
icon: <IconCalendar /> {
} value: 'calendar',
]} label: t`Calendar View`,
/> icon: <IconCalendar />,
) content: <BuildOrderCalendar />
} }
]
})
]; ];
}, [buildOrderView, setBuildOrderView]); }, [user, buildOrderView]);
if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.build)) { if (!user.isLoggedIn() || !user.hasViewRole(UserRoles.build)) {
return <PermissionDenied />; return <PermissionDenied />;

View File

@@ -14,68 +14,55 @@ import { useMemo } from 'react';
import { ModelType } from '@lib/enums/ModelType'; import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles'; import { UserRoles } from '@lib/enums/Roles';
import { useLocalStorage } from '@mantine/hooks'; import { useLocalStorage } from '@mantine/hooks';
import SegmentedIconControl from '../../components/buttons/SegmentedIconControl';
import OrderCalendar from '../../components/calendar/OrderCalendar'; import OrderCalendar from '../../components/calendar/OrderCalendar';
import PermissionDenied from '../../components/errors/PermissionDenied'; import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/panels/PanelGroup'; import { PanelGroup } from '../../components/panels/PanelGroup';
import SegmentedControlPanel from '../../components/panels/SegmentedControlPanel';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { CompanyTable } from '../../tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable'; import { ManufacturerPartTable } from '../../tables/purchasing/ManufacturerPartTable';
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable'; import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable'; import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
function PurchaseOrderOverview({
view
}: {
view: string;
}) {
switch (view) {
case 'calendar':
return (
<OrderCalendar
model={ModelType.purchaseorder}
role={UserRoles.purchase_order}
params={{ outstanding: true }}
/>
);
case 'table':
default:
return <PurchaseOrderTable />;
}
}
export default function PurchasingIndex() { export default function PurchasingIndex() {
const user = useUserState(); const user = useUserState();
const [purchaseOrderView, setpurchaseOrderView] = useLocalStorage<string>({ const [purchaseOrderView, setPurchaseOrderView] = useLocalStorage<string>({
key: 'purchaseOrderView', key: 'purchase-order-view',
defaultValue: 'table' defaultValue: 'table'
}); });
const panels = useMemo(() => { const panels = useMemo(() => {
return [ return [
{ SegmentedControlPanel({
name: 'purchaseorders', name: 'purchaseorders',
label: t`Purchase Orders`, label: t`Purchase Orders`,
icon: <IconShoppingCart />, icon: <IconShoppingCart />,
hidden: !user.hasViewRole(UserRoles.purchase_order), hidden: !user.hasViewRole(UserRoles.purchase_order),
content: <PurchaseOrderOverview view={purchaseOrderView} />, selection: purchaseOrderView,
controls: ( onChange: setPurchaseOrderView,
<SegmentedIconControl options: [
value={purchaseOrderView} {
onChange={setpurchaseOrderView} value: 'table',
data={[ label: t`Table View`,
{ value: 'table', label: t`Table View`, icon: <IconTable /> }, icon: <IconTable />,
{ content: <PurchaseOrderTable />
value: 'calendar', },
label: t`Calendar View`, {
icon: <IconCalendar /> value: 'calendar',
} label: t`Calendar View`,
]} icon: <IconCalendar />,
/> content: (
) <OrderCalendar
}, model={ModelType.purchaseorder}
role={UserRoles.purchase_order}
params={{ outstanding: true }}
/>
)
}
]
}),
{ {
name: 'suppliers', name: 'suppliers',
label: t`Suppliers`, label: t`Suppliers`,

View File

@@ -13,57 +13,17 @@ import { useMemo } from 'react';
import { ModelType } from '@lib/enums/ModelType'; import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles'; import { UserRoles } from '@lib/enums/Roles';
import { useLocalStorage } from '@mantine/hooks'; import { useLocalStorage } from '@mantine/hooks';
import SegmentedIconControl from '../../components/buttons/SegmentedIconControl';
import OrderCalendar from '../../components/calendar/OrderCalendar'; import OrderCalendar from '../../components/calendar/OrderCalendar';
import PermissionDenied from '../../components/errors/PermissionDenied'; import PermissionDenied from '../../components/errors/PermissionDenied';
import { PageDetail } from '../../components/nav/PageDetail'; import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup } from '../../components/panels/PanelGroup'; import { PanelGroup } from '../../components/panels/PanelGroup';
import SegmentedControlPanel from '../../components/panels/SegmentedControlPanel';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { CompanyTable } from '../../tables/company/CompanyTable'; import { CompanyTable } from '../../tables/company/CompanyTable';
import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable'; import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable';
import SalesOrderShipmentTable from '../../tables/sales/SalesOrderShipmentTable'; import SalesOrderShipmentTable from '../../tables/sales/SalesOrderShipmentTable';
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable'; import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
function SalesOrderOverview({
view
}: {
view: string;
}) {
switch (view) {
case 'calendar':
return (
<OrderCalendar
model={ModelType.salesorder}
role={UserRoles.sales_order}
params={{ outstanding: true }}
/>
);
case 'table':
default:
return <SalesOrderTable />;
}
}
function ReturnOrderOverview({
view
}: {
view: string;
}) {
switch (view) {
case 'calendar':
return (
<OrderCalendar
model={ModelType.returnorder}
role={UserRoles.return_order}
params={{ outstanding: true }}
/>
);
case 'table':
default:
return <ReturnOrderTable />;
}
}
export default function SalesIndex() { export default function SalesIndex() {
const user = useUserState(); const user = useUserState();
@@ -79,27 +39,34 @@ export default function SalesIndex() {
const panels = useMemo(() => { const panels = useMemo(() => {
return [ return [
{ SegmentedControlPanel({
name: 'salesorders', name: 'salesorders',
label: t`Sales Orders`, label: t`Sales Orders`,
icon: <IconTruckDelivery />, icon: <IconTruckDelivery />,
content: <SalesOrderOverview view={salesOrderView} />, hidden: !user.hasViewRole(UserRoles.sales_order),
controls: ( selection: salesOrderView,
<SegmentedIconControl onChange: setSalesOrderView,
value={salesOrderView} options: [
onChange={setSalesOrderView} {
data={[ value: 'table',
{ value: 'table', label: t`Table View`, icon: <IconTable /> }, label: t`Table View`,
{ icon: <IconTable />,
value: 'calendar', content: <SalesOrderTable />
label: t`Calendar View`, },
icon: <IconCalendar /> {
} value: 'calendar',
]} label: t`Calendar View`,
/> icon: <IconCalendar />,
), content: (
hidden: !user.hasViewRole(UserRoles.sales_order) <OrderCalendar
}, model={ModelType.returnorder}
role={UserRoles.return_order}
params={{ outstanding: true }}
/>
)
}
]
}),
{ {
name: 'shipments', name: 'shipments',
label: t`Pending Shipments`, label: t`Pending Shipments`,
@@ -112,27 +79,34 @@ export default function SalesIndex() {
/> />
) )
}, },
{ SegmentedControlPanel({
name: 'returnorders', name: 'returnorders',
label: t`Return Orders`, label: t`Return Orders`,
icon: <IconTruckReturn />, icon: <IconTruckReturn />,
content: <ReturnOrderOverview view={returnOrderView} />, hidden: !user.hasViewRole(UserRoles.return_order),
controls: ( selection: returnOrderView,
<SegmentedIconControl onChange: setReturnOrderView,
value={returnOrderView} options: [
onChange={setReturnOrderView} {
data={[ value: 'table',
{ value: 'table', label: t`Table View`, icon: <IconTable /> }, label: t`Table View`,
{ icon: <IconTable />,
value: 'calendar', content: <ReturnOrderTable />
label: t`Calendar View`, },
icon: <IconCalendar /> {
} value: 'calendar',
]} label: t`Calendar View`,
/> icon: <IconCalendar />,
), content: (
hidden: !user.hasViewRole(UserRoles.return_order) <OrderCalendar
}, model={ModelType.returnorder}
role={UserRoles.return_order}
params={{ outstanding: true }}
/>
)
}
]
}),
{ {
name: 'customers', name: 'customers',
label: t`Customers`, label: t`Customers`,