mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
Mantine charts (#7419)
* Install @mantine/charts * Import charts styles * Refactor <PricingOverviewPanel /> * Refactor internal price panel * Refactor variant price panel * BOM bar chart * BOM donut * Refactor supplier pricing panel * More refaactoring * Cleanup unused imports * Fix typo * playwright test updates
This commit is contained in:
parent
9f35971db1
commit
713d2ac925
@ -27,6 +27,7 @@
|
|||||||
"@lingui/core": "^4.10.0",
|
"@lingui/core": "^4.10.0",
|
||||||
"@lingui/react": "^4.10.0",
|
"@lingui/react": "^4.10.0",
|
||||||
"@mantine/carousel": "^7.8.0",
|
"@mantine/carousel": "^7.8.0",
|
||||||
|
"@mantine/charts": "^7.10.1",
|
||||||
"@mantine/core": "^7.10.0",
|
"@mantine/core": "^7.10.0",
|
||||||
"@mantine/dates": "^7.8.0",
|
"@mantine/dates": "^7.8.0",
|
||||||
"@mantine/dropzone": "^7.8.0",
|
"@mantine/dropzone": "^7.8.0",
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
export const CHART_COLORS: string[] = [
|
export const CHART_COLORS: string[] = [
|
||||||
'#ffa8a8',
|
'blue',
|
||||||
'#8ce99a',
|
'teal',
|
||||||
'#74c0fc',
|
'lime',
|
||||||
'#ffe066',
|
'yellow',
|
||||||
'#63e6be',
|
'grape',
|
||||||
'#ffc078',
|
'red',
|
||||||
'#d8f5a2',
|
'orange',
|
||||||
'#66d9e8',
|
'green',
|
||||||
'#e599f7',
|
'indigo',
|
||||||
'#dee2e6'
|
'pink'
|
||||||
];
|
];
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { formatCurrency } from '../../defaults/formatters';
|
import { formatCurrency } from '../../defaults/formatters';
|
||||||
|
|
||||||
export function tooltipFormatter(label: any, currency: string) {
|
/*
|
||||||
|
* Render a chart label for a currency graph
|
||||||
|
*/
|
||||||
|
export function tooltipFormatter(value: any, currency?: string) {
|
||||||
return (
|
return (
|
||||||
formatCurrency(label, {
|
formatCurrency(value, {
|
||||||
currency: currency
|
currency: currency
|
||||||
})?.toString() ?? ''
|
})?.toString() ?? value.toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import '@mantine/carousel/styles.css';
|
import '@mantine/carousel/styles.css';
|
||||||
|
import '@mantine/charts/styles.css';
|
||||||
import '@mantine/core/styles.css';
|
import '@mantine/core/styles.css';
|
||||||
import '@mantine/notifications/styles.css';
|
import '@mantine/notifications/styles.css';
|
||||||
import '@mantine/spotlight/styles.css';
|
import '@mantine/spotlight/styles.css';
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart, DonutChart } from '@mantine/charts';
|
||||||
import {
|
import {
|
||||||
|
Center,
|
||||||
Group,
|
Group,
|
||||||
SegmentedControl,
|
SegmentedControl,
|
||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
@ -7,18 +9,6 @@ import {
|
|||||||
Text
|
Text
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { ReactNode, useMemo, useState } from 'react';
|
import { ReactNode, useMemo, useState } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Cell,
|
|
||||||
Legend,
|
|
||||||
Pie,
|
|
||||||
PieChart,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
import { CHART_COLORS } from '../../../components/charts/colors';
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
||||||
@ -44,42 +34,30 @@ function BomPieChart({
|
|||||||
readonly data: any[];
|
readonly data: any[];
|
||||||
readonly currency: string;
|
readonly currency: string;
|
||||||
}) {
|
}) {
|
||||||
|
// Construct donut data
|
||||||
|
const maxPricing = useMemo(() => {
|
||||||
|
return data.map((entry, index) => {
|
||||||
|
return {
|
||||||
|
name: entry.name,
|
||||||
|
value: entry.total_price_max,
|
||||||
|
color: CHART_COLORS[index % CHART_COLORS.length] + '.5'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<Center>
|
||||||
<PieChart>
|
<DonutChart
|
||||||
<Pie
|
data={maxPricing}
|
||||||
data={data}
|
size={500}
|
||||||
dataKey="total_price_min"
|
thickness={80}
|
||||||
nameKey="name"
|
withLabels={false}
|
||||||
innerRadius={20}
|
withLabelsLine={false}
|
||||||
outerRadius={100}
|
tooltipDataSource="segment"
|
||||||
>
|
chartLabel={t`Total Price`}
|
||||||
{data.map((_entry, index) => (
|
valueFormatter={(value) => tooltipFormatter(value, currency)}
|
||||||
<Cell
|
/>
|
||||||
key={`cell-${index}`}
|
</Center>
|
||||||
fill={CHART_COLORS[index % CHART_COLORS.length]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Pie
|
|
||||||
data={data}
|
|
||||||
dataKey="total_price_max"
|
|
||||||
nameKey="name"
|
|
||||||
innerRadius={120}
|
|
||||||
outerRadius={240}
|
|
||||||
>
|
|
||||||
{data.map((_entry, index) => (
|
|
||||||
<Cell
|
|
||||||
key={`cell-${index}`}
|
|
||||||
fill={CHART_COLORS[index % CHART_COLORS.length]}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Pie>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(label, payload) => tooltipFormatter(label, currency)}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,32 +70,18 @@ function BomBarChart({
|
|||||||
readonly currency: string;
|
readonly currency: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={data}>
|
h={500}
|
||||||
<XAxis dataKey="name" />
|
dataKey="name"
|
||||||
<YAxis
|
data={data}
|
||||||
tickFormatter={(value, index) =>
|
xAxisLabel={t`Component`}
|
||||||
formatCurrency(value, {
|
yAxisLabel={t`Price Range`}
|
||||||
currency: currency
|
series={[
|
||||||
})?.toString() ?? ''
|
{ name: 'total_price_min', label: t`Minimum Price`, color: 'blue.6' },
|
||||||
}
|
{ name: 'total_price_max', label: t`Maximum Price`, color: 'teal.6' }
|
||||||
/>
|
]}
|
||||||
<Tooltip
|
valueFormatter={(value) => tooltipFormatter(value, currency)}
|
||||||
formatter={(label, payload) => tooltipFormatter(label, currency)}
|
/>
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="total_price_min"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Minimum Total Price`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="total_price_max"
|
|
||||||
fill={CHART_COLORS[1]}
|
|
||||||
label={t`Maximum Total Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import { SimpleGrid } from '@mantine/core';
|
import { SimpleGrid } from '@mantine/core';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Legend,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { AddItemButton } from '../../../components/buttons/AddItemButton';
|
import { AddItemButton } from '../../../components/buttons/AddItemButton';
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
||||||
import { ApiFormFieldSet } from '../../../components/forms/fields/ApiFormField';
|
import { ApiFormFieldSet } from '../../../components/forms/fields/ApiFormField';
|
||||||
import { formatCurrency } from '../../../defaults/formatters';
|
import { formatCurrency } from '../../../defaults/formatters';
|
||||||
@ -169,29 +160,14 @@ export default function PriceBreakPanel({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{table.records.length > 0 ? (
|
{table.records.length > 0 ? (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={table.records}>
|
dataKey="quantity"
|
||||||
<XAxis dataKey="quantity" />
|
data={table.records}
|
||||||
<YAxis
|
series={[{ name: 'price', label: t`Price`, color: 'blue.6' }]}
|
||||||
tickFormatter={(value, index) =>
|
xAxisLabel={t`Quantity`}
|
||||||
formatCurrency(value, {
|
yAxisLabel={t`Unit Price`}
|
||||||
currency: currency
|
valueFormatter={(value) => tooltipFormatter(value, currency)}
|
||||||
})?.toString() ?? ''
|
/>
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(label, payload) =>
|
|
||||||
tooltipFormatter(label, currency)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="price"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Price Break`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
) : (
|
) : (
|
||||||
<NoPricingData />
|
<NoPricingData />
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Anchor,
|
Anchor,
|
||||||
@ -19,17 +20,7 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { DataTable } from 'mantine-datatable';
|
import { DataTable } from 'mantine-datatable';
|
||||||
import { ReactNode, useMemo } from 'react';
|
import { ReactNode, useMemo } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Legend,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
||||||
import { formatCurrency, renderDate } from '../../../defaults/formatters';
|
import { formatCurrency, renderDate } from '../../../defaults/formatters';
|
||||||
import { panelOptions } from '../PartPricingPanel';
|
import { panelOptions } from '../PartPricingPanel';
|
||||||
@ -192,34 +183,17 @@ export default function PricingOverviewPanel({
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={overviewData} id="pricing-overview-chart">
|
aria-label="pricing-overview-chart"
|
||||||
<XAxis dataKey="title" />
|
dataKey="title"
|
||||||
<YAxis
|
data={overviewData}
|
||||||
tickFormatter={(value, index) =>
|
title={t`Pricing Overview`}
|
||||||
formatCurrency(value, {
|
series={[
|
||||||
currency: pricing?.currency
|
{ name: 'min_value', label: t`Minimum Value`, color: 'blue.6' },
|
||||||
})?.toString() ?? ''
|
{ name: 'max_value', label: t`Maximum Value`, color: 'teal.6' }
|
||||||
}
|
]}
|
||||||
/>
|
valueFormatter={(value) => tooltipFormatter(value, pricing?.currency)}
|
||||||
<Tooltip
|
/>
|
||||||
formatter={(label, payload) =>
|
|
||||||
tooltipFormatter(label, pricing?.currency)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="min_value"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Minimum Price`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="max_value"
|
|
||||||
fill={CHART_COLORS[1]}
|
|
||||||
label={t`Maximum Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
@ -1,18 +1,8 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import { Group, SimpleGrid, Text } from '@mantine/core';
|
import { Group, SimpleGrid, Text } from '@mantine/core';
|
||||||
import { ReactNode, useCallback, useMemo } from 'react';
|
import { ReactNode, useCallback, useMemo } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Legend,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
|
||||||
import { formatCurrency, renderDate } from '../../../defaults/formatters';
|
import { formatCurrency, renderDate } from '../../../defaults/formatters';
|
||||||
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
||||||
import { useTable } from '../../../hooks/UseTable';
|
import { useTable } from '../../../hooks/UseTable';
|
||||||
@ -131,32 +121,13 @@ export default function PurchaseHistoryPanel({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{purchaseHistoryData.length > 0 ? (
|
{purchaseHistoryData.length > 0 ? (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={purchaseHistoryData}>
|
data={purchaseHistoryData}
|
||||||
<XAxis dataKey="name" />
|
dataKey="name"
|
||||||
<YAxis
|
series={[
|
||||||
tickFormatter={(value, index) =>
|
{ name: 'unit_price', label: t`Unit Price`, color: 'blue.5' }
|
||||||
formatCurrency(value, {
|
]}
|
||||||
currency: currency
|
/>
|
||||||
})?.toString() ?? ''
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(label, payload) => tooltipFormatter(label, currency)}
|
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="unit_price"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Unit Price`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="purchase_price"
|
|
||||||
fill={CHART_COLORS[1]}
|
|
||||||
label={t`Purchase Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
) : (
|
) : (
|
||||||
<NoPricingData />
|
<NoPricingData />
|
||||||
)}
|
)}
|
||||||
|
@ -1,18 +1,8 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import { SimpleGrid } from '@mantine/core';
|
import { SimpleGrid } from '@mantine/core';
|
||||||
import { ReactNode, useMemo } from 'react';
|
import { ReactNode, useMemo } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Legend,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
|
||||||
import { formatCurrency } from '../../../defaults/formatters';
|
import { formatCurrency } from '../../../defaults/formatters';
|
||||||
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
||||||
import { useTable } from '../../../hooks/UseTable';
|
import { useTable } from '../../../hooks/UseTable';
|
||||||
@ -95,27 +85,13 @@ export default function SaleHistoryPanel({ part }: { part: any }): ReactNode {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{saleHistoryData.length > 0 ? (
|
{saleHistoryData.length > 0 ? (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={saleHistoryData}>
|
data={saleHistoryData}
|
||||||
<XAxis dataKey="name" />
|
dataKey="name"
|
||||||
<YAxis
|
series={[
|
||||||
tickFormatter={(value, index) =>
|
{ name: 'sale_price', label: t`Sale Price`, color: 'blue.6' }
|
||||||
formatCurrency(value, {
|
]}
|
||||||
currency: currency
|
/>
|
||||||
})?.toString() ?? ''
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Tooltip
|
|
||||||
formatter={(label, payload) => tooltipFormatter(label, currency)}
|
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="sale_price"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Sale Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
) : (
|
) : (
|
||||||
<NoPricingData />
|
<NoPricingData />
|
||||||
)}
|
)}
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import { SimpleGrid } from '@mantine/core';
|
import { SimpleGrid } from '@mantine/core';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
||||||
import { formatCurrency } from '../../../defaults/formatters';
|
|
||||||
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';
|
||||||
@ -64,31 +55,19 @@ export default function SupplierPricingPanel({ part }: { part: any }) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{supplierPricingData.length > 0 ? (
|
{supplierPricingData.length > 0 ? (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={supplierPricingData}>
|
data={supplierPricingData}
|
||||||
<XAxis dataKey="name" />
|
dataKey="name"
|
||||||
<YAxis
|
series={[
|
||||||
tickFormatter={(value, index) =>
|
{ name: 'unit_price', label: t`Unit Price`, color: 'blue.6' },
|
||||||
formatCurrency(value, {
|
{
|
||||||
currency: currency
|
name: 'supplier_price',
|
||||||
})?.toString() ?? ''
|
label: t`Supplier Price`,
|
||||||
}
|
color: 'teal.6'
|
||||||
/>
|
}
|
||||||
<Tooltip
|
]}
|
||||||
formatter={(label, payload) => tooltipFormatter(label, currency)}
|
valueFormatter={(value) => tooltipFormatter(value, currency)}
|
||||||
/>
|
/>
|
||||||
<Bar
|
|
||||||
dataKey="unit_price"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Unit Price`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="supplier_price"
|
|
||||||
fill="#82ca9d"
|
|
||||||
label={t`Supplier Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
) : (
|
) : (
|
||||||
<NoPricingData />
|
<NoPricingData />
|
||||||
)}
|
)}
|
||||||
|
@ -1,17 +1,8 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
|
import { BarChart } from '@mantine/charts';
|
||||||
import { SimpleGrid, Stack } from '@mantine/core';
|
import { SimpleGrid, Stack } from '@mantine/core';
|
||||||
import { ReactNode, useMemo } from 'react';
|
import { ReactNode, useMemo } from 'react';
|
||||||
import {
|
|
||||||
Bar,
|
|
||||||
BarChart,
|
|
||||||
Legend,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis
|
|
||||||
} from 'recharts';
|
|
||||||
|
|
||||||
import { CHART_COLORS } from '../../../components/charts/colors';
|
|
||||||
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
import { tooltipFormatter } from '../../../components/charts/tooltipFormatter';
|
||||||
import { formatCurrency } from '../../../defaults/formatters';
|
import { formatCurrency } from '../../../defaults/formatters';
|
||||||
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../../enums/ApiEndpoints';
|
||||||
@ -97,34 +88,19 @@ export default function VariantPricingPanel({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{variantPricingData.length > 0 ? (
|
{variantPricingData.length > 0 ? (
|
||||||
<ResponsiveContainer width="100%" height={500}>
|
<BarChart
|
||||||
<BarChart data={variantPricingData}>
|
dataKey="name"
|
||||||
<XAxis dataKey="name" />
|
data={variantPricingData}
|
||||||
<YAxis
|
xAxisLabel={t`Variant Part`}
|
||||||
tickFormatter={(value, index) =>
|
yAxisLabel={t`Price Range`}
|
||||||
formatCurrency(value, {
|
series={[
|
||||||
currency: pricing?.currency
|
{ name: 'pmin', label: t`Minimum Price`, color: 'blue.6' },
|
||||||
})?.toString() ?? ''
|
{ name: 'pmax', label: t`Maximum Price`, color: 'teal.6' }
|
||||||
}
|
]}
|
||||||
/>
|
valueFormatter={(value) =>
|
||||||
<Tooltip
|
tooltipFormatter(value, pricing?.currency)
|
||||||
formatter={(label, payload) =>
|
}
|
||||||
tooltipFormatter(label, pricing?.currency)
|
/>
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Legend />
|
|
||||||
<Bar
|
|
||||||
dataKey="pmin"
|
|
||||||
fill={CHART_COLORS[0]}
|
|
||||||
label={t`Minimum Price`}
|
|
||||||
/>
|
|
||||||
<Bar
|
|
||||||
dataKey="pmax"
|
|
||||||
fill={CHART_COLORS[1]}
|
|
||||||
label={t`Maximum Price`}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
) : (
|
) : (
|
||||||
<NoPricingData />
|
<NoPricingData />
|
||||||
)}
|
)}
|
||||||
|
@ -580,8 +580,8 @@ export function InvenTreeTable<T = any>({
|
|||||||
)}
|
)}
|
||||||
<Boundary label={`InvenTreeTable-${tableState.tableKey}`}>
|
<Boundary label={`InvenTreeTable-${tableState.tableKey}`}>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Group justify="apart" grow>
|
<Group justify="apart" grow wrap="nowrap">
|
||||||
<Group justify="left" key="custom-actions" gap={5}>
|
<Group justify="left" key="custom-actions" gap={5} wrap="nowrap">
|
||||||
{tableProps.enableDownload && (
|
{tableProps.enableDownload && (
|
||||||
<DownloadAction
|
<DownloadAction
|
||||||
key="download-action"
|
key="download-action"
|
||||||
@ -617,7 +617,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
))}
|
))}
|
||||||
</Group>
|
</Group>
|
||||||
<Space />
|
<Space />
|
||||||
<Group justify="right" gap={5}>
|
<Group justify="right" gap={5} wrap="nowrap">
|
||||||
{tableProps.enableSearch && (
|
{tableProps.enableSearch && (
|
||||||
<TableSearchInput
|
<TableSearchInput
|
||||||
searchCallback={(term: string) =>
|
searchCallback={(term: string) =>
|
||||||
|
@ -29,25 +29,25 @@ test('PUI - Pages - Part - Pricing (Nothing, BOM)', async ({ page }) => {
|
|||||||
await page.getByRole('button', { name: 'BOM Pricing' }).isEnabled();
|
await page.getByRole('button', { name: 'BOM Pricing' }).isEnabled();
|
||||||
|
|
||||||
// Overview Graph
|
// Overview Graph
|
||||||
let graph = page.locator('#pricing-overview-chart');
|
let graph = page.getByLabel('pricing-overview-chart');
|
||||||
await graph.waitFor();
|
await graph.waitFor();
|
||||||
await graph.getByText('$60').waitFor();
|
await graph.getByText('$60').waitFor();
|
||||||
await graph.getByText('BOM Pricing').waitFor();
|
await graph.locator('tspan').filter({ hasText: 'BOM Pricing' }).waitFor();
|
||||||
await graph.getByText('Overall Pricing').waitFor();
|
await graph.locator('tspan').filter({ hasText: 'Overall Pricing' }).waitFor();
|
||||||
await graph.locator('path').nth(1).hover();
|
|
||||||
await page.getByText('min_value : $50').waitFor();
|
|
||||||
|
|
||||||
// BOM Pricing
|
// BOM Pricing
|
||||||
await page.getByRole('button', { name: 'BOM Pricing' }).click();
|
await page.getByRole('button', { name: 'BOM Pricing' }).click();
|
||||||
await page.getByText('Bar Chart').click();
|
await page.getByText('Bar Chart').click();
|
||||||
await page.getByText('total_price_min').waitFor();
|
|
||||||
await page.getByText('Pie Chart').click();
|
await page.getByText('Pie Chart').click();
|
||||||
await page.getByRole('button', { name: 'Quantity Not sorted' }).waitFor();
|
await page.getByRole('button', { name: 'Quantity Not sorted' }).waitFor();
|
||||||
await page.getByRole('button', { name: 'Unit Price Not sorted' }).waitFor();
|
await page.getByRole('button', { name: 'Unit Price Not sorted' }).waitFor();
|
||||||
|
|
||||||
// BOM Pricing - linkjumping
|
// BOM Pricing - linkjumping
|
||||||
await page.getByText('Wood Screw').waitFor();
|
await page
|
||||||
await page.getByText('Wood Screw').click();
|
.getByLabel('BOM Pricing')
|
||||||
|
.getByRole('table')
|
||||||
|
.getByText('Wood Screw')
|
||||||
|
.click();
|
||||||
await page.waitForURL('**/part/98/pricing');
|
await page.waitForURL('**/part/98/pricing');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1809,6 +1809,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-7.10.0.tgz#ee750504814ec4eff7523e17a0052dc86bec45c8"
|
resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-7.10.0.tgz#ee750504814ec4eff7523e17a0052dc86bec45c8"
|
||||||
integrity sha512-+fP/hyHpXoK5nHR5mgEjPhPqjiurwMDP+aLseaE/mvmoBZEFF3vOPAqYOekNDrdyaqvtHkM82T9mnR4M3BAK0w==
|
integrity sha512-+fP/hyHpXoK5nHR5mgEjPhPqjiurwMDP+aLseaE/mvmoBZEFF3vOPAqYOekNDrdyaqvtHkM82T9mnR4M3BAK0w==
|
||||||
|
|
||||||
|
"@mantine/charts@^7.10.1":
|
||||||
|
version "7.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@mantine/charts/-/charts-7.10.1.tgz#c1b92ccac16d05b87cc103adcd79f0e0c2f87c62"
|
||||||
|
integrity sha512-fMy2EmgegdHVkrtnRO8ync8kqOJoXqixxc1JDmhn9tks4lSvKAKB9ui8OyaTUOWzls/Cs0VfyW51sB/HKe5faw==
|
||||||
|
|
||||||
"@mantine/core@^7.10.0":
|
"@mantine/core@^7.10.0":
|
||||||
version "7.10.0"
|
version "7.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.10.0.tgz#bfaafc92cf2346e5a6cbb49289f577ce3f7c05f7"
|
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-7.10.0.tgz#bfaafc92cf2346e5a6cbb49289f577ce3f7c05f7"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user