mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[React] Currency table (#5858)
* Add basic table for displaying exchange rates - Needed to extend current <InvenTreeTable> functionality for non-standard API endpoint data * Add heading * Add button to reload exchange rates
This commit is contained in:
parent
361fc097a7
commit
1640f605a0
@ -131,7 +131,7 @@ export function PanelGroup({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack spacing="md">
|
<Stack spacing="md">
|
||||||
<StylishText size="lg">{panel.label}</StylishText>
|
<StylishText size="xl">{panel.label}</StylishText>
|
||||||
<Divider />
|
<Divider />
|
||||||
{panel.content ?? <PlaceholderPanel />}
|
{panel.content ?? <PlaceholderPanel />}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -40,6 +40,7 @@ const defaultPageSize: number = 25;
|
|||||||
* @param customFilters : TableFilter[] - List of custom filters
|
* @param customFilters : TableFilter[] - List of custom filters
|
||||||
* @param customActionGroups : any[] - List of custom action groups
|
* @param customActionGroups : any[] - List of custom action groups
|
||||||
* @param printingActions : any[] - List of printing actions
|
* @param printingActions : any[] - List of printing actions
|
||||||
|
* @param dataFormatter : (data: any) => any - Callback function to reformat data returned by server (if not in default format)
|
||||||
* @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions
|
* @param rowActions : (record: any) => RowAction[] - Callback function to generate row actions
|
||||||
* @param onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked
|
* @param onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked
|
||||||
*/
|
*/
|
||||||
@ -59,6 +60,7 @@ export type InvenTreeTableProps = {
|
|||||||
customActionGroups?: any[];
|
customActionGroups?: any[];
|
||||||
printingActions?: any[];
|
printingActions?: any[];
|
||||||
idAccessor?: string;
|
idAccessor?: string;
|
||||||
|
dataFormatter?: (data: any) => any;
|
||||||
rowActions?: (record: any) => RowAction[];
|
rowActions?: (record: any) => RowAction[];
|
||||||
onRowClick?: (record: any, index: number, event: any) => void;
|
onRowClick?: (record: any, index: number, event: any) => void;
|
||||||
};
|
};
|
||||||
@ -356,8 +358,15 @@ export function InvenTreeTable({
|
|||||||
tableProps.noRecordsText ?? t`No records found`
|
tableProps.noRecordsText ?? t`No records found`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extract returned data (accounting for pagination) and ensure it is a list
|
let results = [];
|
||||||
let results = response.data?.results ?? response.data ?? [];
|
|
||||||
|
if (props.dataFormatter) {
|
||||||
|
// Custom data formatter provided
|
||||||
|
results = props.dataFormatter(response.data);
|
||||||
|
} else {
|
||||||
|
// Extract returned data (accounting for pagination) and ensure it is a list
|
||||||
|
results = response.data?.results ?? response.data ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
if (!Array.isArray(results)) {
|
if (!Array.isArray(results)) {
|
||||||
setMissingRecordsText(t`Server returned incorrect data type`);
|
setMissingRecordsText(t`Server returned incorrect data type`);
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { showNotification } from '@mantine/notifications';
|
||||||
|
import { IconReload } from '@tabler/icons-react';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { api } from '../../../App';
|
||||||
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
|
import { ActionButton } from '../../buttons/ActionButton';
|
||||||
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table for displaying available currencies
|
||||||
|
*/
|
||||||
|
export function CurrencyTable() {
|
||||||
|
const { tableKey, refreshTable } = useTableRefresh('currency');
|
||||||
|
|
||||||
|
const columns = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
accessor: 'currency',
|
||||||
|
title: t`Currency`,
|
||||||
|
switchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'rate',
|
||||||
|
title: t`Rate`,
|
||||||
|
switchable: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const refreshCurrencies = useCallback(() => {
|
||||||
|
api
|
||||||
|
.post(apiUrl(ApiPaths.currency_refresh), {})
|
||||||
|
.then(() => {
|
||||||
|
refreshTable();
|
||||||
|
showNotification({
|
||||||
|
message: t`Exchange rates updated`,
|
||||||
|
color: 'green'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
showNotification({
|
||||||
|
title: t`Exchange rate update error`,
|
||||||
|
message: error,
|
||||||
|
color: 'red'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const tableActions = useMemo(() => {
|
||||||
|
return [
|
||||||
|
<ActionButton
|
||||||
|
onClick={refreshCurrencies}
|
||||||
|
tooltip={t`Refresh currency exchange rates`}
|
||||||
|
icon={<IconReload />}
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InvenTreeTable
|
||||||
|
url={apiUrl(ApiPaths.currency_list)}
|
||||||
|
tableKey={tableKey}
|
||||||
|
columns={columns}
|
||||||
|
props={{
|
||||||
|
customActionGroups: tableActions,
|
||||||
|
dataFormatter: (data) => {
|
||||||
|
let rates = data?.exchange_rates ?? {};
|
||||||
|
|
||||||
|
return Object.entries(rates).map(([currency, rate]) => {
|
||||||
|
return {
|
||||||
|
currency: currency,
|
||||||
|
rate: rate
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -21,10 +21,11 @@ import {
|
|||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { PlaceholderPill } from '../../../components/items/Placeholder';
|
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 { CustomUnitsTable } from '../../../components/tables/settings/CustomUnitsTable';
|
import { CustomUnitsTable } from '../../../components/tables/settings/CustomUnitsTable';
|
||||||
import { ProjectCodeTable } from '../../../components/tables/settings/ProjectCodeTable';
|
import { ProjectCodeTable } from '../../../components/tables/settings/ProjectCodeTable';
|
||||||
import { useServerApiState } from '../../../states/ApiState';
|
import { useServerApiState } from '../../../states/ApiState';
|
||||||
@ -152,7 +153,9 @@ export default function SystemSettings() {
|
|||||||
<GlobalSettingList
|
<GlobalSettingList
|
||||||
keys={['CURRENCY_UPDATE_PLUGIN', 'CURRENCY_UPDATE_INTERVAL']}
|
keys={['CURRENCY_UPDATE_PLUGIN', 'CURRENCY_UPDATE_INTERVAL']}
|
||||||
/>
|
/>
|
||||||
<PlaceholderPill />
|
<StylishText size="xl">{t`Exchange Rates`}</StylishText>
|
||||||
|
<Divider />
|
||||||
|
<CurrencyTable />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -71,6 +71,9 @@ export enum ApiPaths {
|
|||||||
settings_user_list = 'api-settings-user-list',
|
settings_user_list = 'api-settings-user-list',
|
||||||
notifications_list = 'api-notifications-list',
|
notifications_list = 'api-notifications-list',
|
||||||
|
|
||||||
|
currency_list = 'api-currency-list',
|
||||||
|
currency_refresh = 'api-currency-refresh',
|
||||||
|
|
||||||
barcode = 'api-barcode',
|
barcode = 'api-barcode',
|
||||||
news = 'news',
|
news = 'news',
|
||||||
global_status = 'api-global-status',
|
global_status = 'api-global-status',
|
||||||
@ -165,6 +168,10 @@ export function apiEndpoint(path: ApiPaths): string {
|
|||||||
return 'auth/emails/$id/verify/';
|
return 'auth/emails/$id/verify/';
|
||||||
case ApiPaths.user_email_primary:
|
case ApiPaths.user_email_primary:
|
||||||
return 'auth/emails/$id/primary/';
|
return 'auth/emails/$id/primary/';
|
||||||
|
case ApiPaths.currency_list:
|
||||||
|
return 'currency/exchange/';
|
||||||
|
case ApiPaths.currency_refresh:
|
||||||
|
return 'currency/refresh/';
|
||||||
case ApiPaths.api_search:
|
case ApiPaths.api_search:
|
||||||
return 'search/';
|
return 'search/';
|
||||||
case ApiPaths.settings_global_list:
|
case ApiPaths.settings_global_list:
|
||||||
|
Loading…
Reference in New Issue
Block a user