[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:
Oliver 2023-11-04 17:47:39 +11:00 committed by GitHub
parent 361fc097a7
commit 1640f605a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 5 deletions

View File

@ -131,7 +131,7 @@ export function PanelGroup({
}}
>
<Stack spacing="md">
<StylishText size="lg">{panel.label}</StylishText>
<StylishText size="xl">{panel.label}</StylishText>
<Divider />
{panel.content ?? <PlaceholderPanel />}
</Stack>

View File

@ -40,6 +40,7 @@ const defaultPageSize: number = 25;
* @param customFilters : TableFilter[] - List of custom filters
* @param customActionGroups : any[] - List of custom action groups
* @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 onRowClick : (record: any, index: number, event: any) => void - Callback function when a row is clicked
*/
@ -59,6 +60,7 @@ export type InvenTreeTableProps = {
customActionGroups?: any[];
printingActions?: any[];
idAccessor?: string;
dataFormatter?: (data: any) => any;
rowActions?: (record: any) => RowAction[];
onRowClick?: (record: any, index: number, event: any) => void;
};
@ -356,8 +358,15 @@ export function InvenTreeTable({
tableProps.noRecordsText ?? t`No records found`
);
// Extract returned data (accounting for pagination) and ensure it is a list
let results = response.data?.results ?? response.data ?? [];
let results = [];
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)) {
setMissingRecordsText(t`Server returned incorrect data type`);

View File

@ -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
};
});
}
}}
/>
);
}

View File

@ -21,10 +21,11 @@ import {
} from '@tabler/icons-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 { SettingsHeader } from '../../../components/nav/SettingsHeader';
import { GlobalSettingList } from '../../../components/settings/SettingList';
import { CurrencyTable } from '../../../components/tables/settings/CurrencyTable';
import { CustomUnitsTable } from '../../../components/tables/settings/CustomUnitsTable';
import { ProjectCodeTable } from '../../../components/tables/settings/ProjectCodeTable';
import { useServerApiState } from '../../../states/ApiState';
@ -152,7 +153,9 @@ export default function SystemSettings() {
<GlobalSettingList
keys={['CURRENCY_UPDATE_PLUGIN', 'CURRENCY_UPDATE_INTERVAL']}
/>
<PlaceholderPill />
<StylishText size="xl">{t`Exchange Rates`}</StylishText>
<Divider />
<CurrencyTable />
</>
)
},

View File

@ -71,6 +71,9 @@ export enum ApiPaths {
settings_user_list = 'api-settings-user-list',
notifications_list = 'api-notifications-list',
currency_list = 'api-currency-list',
currency_refresh = 'api-currency-refresh',
barcode = 'api-barcode',
news = 'news',
global_status = 'api-global-status',
@ -165,6 +168,10 @@ export function apiEndpoint(path: ApiPaths): string {
return 'auth/emails/$id/verify/';
case ApiPaths.user_email_primary:
return 'auth/emails/$id/primary/';
case ApiPaths.currency_list:
return 'currency/exchange/';
case ApiPaths.currency_refresh:
return 'currency/refresh/';
case ApiPaths.api_search:
return 'search/';
case ApiPaths.settings_global_list: