2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-01 04:56:45 +00:00

[UI] API Context (#8851)

* Create ApiContext provider

* Utilize new context

* Remove api from global context

* Refactor <InvenTreeTable>

- No longer need hard-coded API constant

* Refactor useInstance hook

* Refactoring

- QueryCountDatshboardWidget
- NotesEditor
- RenderInstance

* Refactor multiple tables

* Fix typos

* Refactor useFilters hook

- Allow plugins to use this hook!

* Further refactoring

* Refactor API forms

* Cleanup context routing

* Fix provision order
This commit is contained in:
Oliver 2025-01-08 07:34:06 +11:00 committed by GitHub
parent 3a62bdd276
commit 296c54a1d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 127 additions and 66 deletions

View File

@ -682,7 +682,7 @@ class PartSerializer(
Used when displaying all details of a single component.
"""
import_exclude_fields = ['duplicate']
import_exclude_fields = ['duplicate', 'tags']
class Meta:
"""Metaclass defining serializer fields."""

View File

@ -4,7 +4,7 @@ import { useQuery } from '@tanstack/react-query';
import { type ReactNode, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../../App';
import { useApi } from '../../../contexts/ApiContext';
import type { ModelType } from '../../../enums/ModelType';
import {
InvenTreeIcon,
@ -31,6 +31,7 @@ function QueryCountWidget({
icon?: InvenTreeIconType;
params: any;
}>): ReactNode {
const api = useApi();
const user = useUserState();
const navigate = useNavigate();

View File

@ -14,7 +14,7 @@ import { getValueAtPath } from 'mantine-datatable';
import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import { formatDate } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ModelType } from '../../enums/ModelType';
@ -101,6 +101,8 @@ function NameBadge({
pk,
type
}: Readonly<{ pk: string | number; type: BadgeType }>) {
const api = useApi();
const { data } = useQuery({
queryKey: ['badge', type, pk],
queryFn: async () => {
@ -217,6 +219,7 @@ function BooleanValue(props: Readonly<FieldProps>) {
}
function TableAnchorValue(props: Readonly<FieldProps>) {
const api = useApi();
const navigate = useNavigate();
const { data } = useQuery({

View File

@ -7,7 +7,7 @@ import 'easymde/dist/easymde.min.css';
import { useCallback, useEffect, useMemo, useState } from 'react';
import SimpleMDE from 'react-simplemde-editor';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ModelType } from '../../enums/ModelType';
import { apiUrl } from '../../states/ApiState';
@ -31,6 +31,7 @@ export default function NotesEditor({
modelId: number;
editable?: boolean;
}>) {
const api = useApi();
// In addition to the editable prop, we also need to check if the user has "enabled" editing
const [editing, setEditing] = useState<boolean>(false);

View File

@ -12,7 +12,7 @@ import {
} from '@mantine/core';
import { useId } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { useQuery } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useCallback, useEffect, useMemo, useState } from 'react';
import {
type FieldValues,
@ -23,7 +23,7 @@ import {
} from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { api, queryClient } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import type { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ModelType } from '../../enums/ModelType';
import {
@ -110,6 +110,8 @@ export function OptionsApiForm({
props: ApiFormProps;
id?: string;
}>) {
const api = useApi();
const props = useMemo(
() => ({
..._props,
@ -205,6 +207,8 @@ export function ApiForm({
props: ApiFormProps;
optionsLoading: boolean;
}>) {
const api = useApi();
const queryClient = useQueryClient();
const navigate = useNavigate();
const [fields, setFields] = useState<ApiFormFieldSet>(

View File

@ -5,7 +5,7 @@ import {
useFormContext
} from 'react-hook-form';
import { api } from '../../../App';
import { useApi } from '../../../contexts/ApiContext';
import {
constructField,
extractAvailableFields
@ -29,6 +29,7 @@ export function DependentField({
url?: string;
setFields?: React.Dispatch<React.SetStateAction<ApiFormFieldSet>>;
}>) {
const api = useApi();
const { watch, resetField } = useFormContext();
const mappedFieldNames = useMemo(

View File

@ -15,7 +15,7 @@ import {
} from 'react-hook-form';
import Select from 'react-select';
import { api } from '../../../App';
import { useApi } from '../../../contexts/ApiContext';
import { vars } from '../../../theme';
import { RenderInstance } from '../../render/Instance';
import type { ApiFormFieldType } from './ApiFormField';
@ -34,6 +34,7 @@ export function RelatedModelField({
fieldName: string;
limit?: number;
}>) {
const api = useApi();
const fieldId = useId();
const {
field,

View File

@ -9,7 +9,7 @@ import {
} from '@tabler/icons-react';
import { type ReactNode, useCallback, useMemo, useState } from 'react';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { cancelEvent } from '../../functions/events';
import {
@ -131,6 +131,7 @@ export default function ImporterDataSelector({
}: Readonly<{
session: ImportSessionState;
}>) {
const api = useApi();
const table = useTable('dataimporter');
const [selectedFieldNames, setSelectedFieldNames] = useState<string[]>([]);

View File

@ -13,7 +13,7 @@ import {
import { IconCheck } from '@tabler/icons-react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ImportSessionState } from '../../hooks/UseImportSession';
import { apiUrl } from '../../states/ApiState';
@ -24,6 +24,8 @@ function ImporterColumn({
column,
options
}: Readonly<{ column: any; options: any[] }>) {
const api = useApi();
const [errorMessage, setErrorMessage] = useState<string>('');
const [selectedColumn, setSelectedColumn] = useState<string>(
@ -78,6 +80,8 @@ function ImporterDefaultField({
fieldName: string;
session: ImportSessionState;
}) {
const api = useApi();
const onChange = useCallback(
(value: any) => {
// Update the default value for the field
@ -162,6 +166,8 @@ export default function ImporterColumnSelector({
}: Readonly<{
session: ImportSessionState;
}>) {
const api = useApi();
const [errorMessage, setErrorMessage] = useState<string>('');
const acceptMapping = useCallback(() => {

View File

@ -21,7 +21,7 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import type { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ModelType } from '../../enums/ModelType';
import { navigateToLink } from '../../functions/navigation';
@ -48,6 +48,7 @@ export default function NavigationTree({
modelType: ModelType;
endpoint: ApiEndpoints;
}>) {
const api = useApi();
const navigate = useNavigate();
const treeState = useTree();

View File

@ -3,7 +3,7 @@ import { Alert, Anchor, Group, Skeleton, Space, Text } from '@mantine/core';
import { useQuery } from '@tanstack/react-query';
import { type ReactNode, useCallback } from 'react';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import { ModelType } from '../../enums/ModelType';
import { navigateToLink } from '../../functions/navigation';
import { shortenString } from '../../functions/tables';
@ -130,6 +130,8 @@ export function RenderRemoteInstance({
model: ModelType;
pk: number;
}>): ReactNode {
const api = useApi();
const { data, isLoading, isFetching } = useQuery({
queryKey: ['model', model, pk],
queryFn: async () => {

View File

@ -10,7 +10,7 @@ import React, {
} from 'react';
import { useStore } from 'zustand';
import { api } from '../../App';
import { useApi } from '../../contexts/ApiContext';
import type { ModelType } from '../../enums/ModelType';
import { useEditApiFormModal } from '../../hooks/UseForm';
import { apiUrl } from '../../states/ApiState';
@ -40,6 +40,8 @@ export function SettingList({
settingsState.fetchSettings();
}, []);
const api = useApi();
const allKeys = useMemo(
() => settingsState?.settings?.map((s) => s.key) ?? [],
[settingsState?.settings]

View File

@ -0,0 +1,31 @@
import { type QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { AxiosInstance } from 'axios';
import { createContext, useContext } from 'react';
const ApiContext = createContext<AxiosInstance | null>(null);
export const ApiProvider = ({
api,
client,
children
}: {
api: AxiosInstance;
client: QueryClient;
children: React.ReactNode;
}) => {
return (
<QueryClientProvider client={client}>
<ApiContext.Provider value={api}>{children}</ApiContext.Provider>
</QueryClientProvider>
);
};
export const useApi = () => {
const context = useContext(ApiContext);
if (!context) {
throw new Error('useApi must be used within an ApiProvider');
}
return context;
};

View File

@ -1,12 +0,0 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '../App';
import { ThemeContext } from './ThemeContext';
export const BaseContext = ({ children }: { children: any }) => {
return (
<QueryClientProvider client={queryClient}>
<ThemeContext>{children}</ThemeContext>
</QueryClientProvider>
);
};

View File

@ -2,8 +2,8 @@ import { t } from '@lingui/macro';
import { IconPackages } from '@tabler/icons-react';
import { useMemo, useState } from 'react';
import { api } from '../App';
import type { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { useApi } from '../contexts/ApiContext';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import { apiUrl } from '../states/ApiState';
import { useGlobalSettingsState } from '../states/SettingsState';
@ -179,6 +179,8 @@ export function usePartParameterFields({
}: {
editTemplate?: boolean;
}): ApiFormFieldSet {
const api = useApi();
// Valid field choices
const [choices, setChoices] = useState<any[]>([]);

View File

@ -5,7 +5,7 @@
import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
import { api } from '../App';
import { useApi } from '../contexts/ApiContext';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import { resolveItem } from '../functions/conversion';
import { apiUrl } from '../states/ApiState';
@ -20,6 +20,8 @@ type UseFilterProps = {
};
export function useFilters(props: UseFilterProps) {
const api = useApi();
const query = useQuery({
enabled: true,
gcTime: 500,

View File

@ -1,7 +1,7 @@
import { type QueryObserverResult, useQuery } from '@tanstack/react-query';
import { useCallback, useMemo, useState } from 'react';
import { api } from '../App';
import { useApi } from '../contexts/ApiContext';
import type { ApiEndpoints } from '../enums/ApiEndpoints';
import { type PathParams, apiUrl } from '../states/ApiState';
@ -48,6 +48,8 @@ export function useInstance<T = any>({
throwError?: boolean;
updateInterval?: number;
}): UseInstanceResult {
const api = useApi();
const [instance, setInstance] = useState<T | undefined>(defaultValue);
const [requestStatus, setRequestStatus] = useState<number>(0);

View File

@ -12,7 +12,6 @@ import ReactDOM from 'react-dom/client';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { api } from './App';
import type { HostList } from './states/states';
import MainView from './views/MainView';
@ -27,7 +26,6 @@ declare global {
sentry_dsn?: string;
environment?: string;
};
InvenTreeAPI: typeof api;
React: typeof React;
}
}
@ -105,4 +103,3 @@ if (window.location.pathname === '/') {
}
window.React = React;
window.InvenTreeAPI = api;

View File

@ -11,16 +11,17 @@ import {
} from '@tabler/icons-react';
import { useCallback, useMemo } from 'react';
import { api } from '../App';
import { ActionButton } from '../components/buttons/ActionButton';
import { PageDetail } from '../components/nav/PageDetail';
import { PanelGroup } from '../components/panels/PanelGroup';
import { useApi } from '../contexts/ApiContext';
import { ApiEndpoints } from '../enums/ApiEndpoints';
import { useTable } from '../hooks/UseTable';
import { apiUrl } from '../states/ApiState';
import { NotificationTable } from '../tables/notifications/NotificationTable';
export default function NotificationsPage() {
const api = useApi();
const unreadTable = useTable('unreadnotifications');
const readTable = useTable('readnotifications');

View File

@ -34,7 +34,6 @@ import { type ReactNode, useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import Select from 'react-select';
import { api } from '../../App';
import AdminButton from '../../components/buttons/AdminButton';
import { PrintingActions } from '../../components/buttons/PrintingActions';
import {
@ -63,6 +62,7 @@ import type { PanelType } from '../../components/panels/Panel';
import { PanelGroup } from '../../components/panels/PanelGroup';
import { RenderPart } from '../../components/render/Part';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { useApi } from '../../contexts/ApiContext';
import { formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
@ -110,6 +110,7 @@ import PartSupplierDetail from './PartSupplierDetail';
export default function PartDetail() {
const { id } = useParams();
const api = useApi();
const navigate = useNavigate();
const user = useUserState();

View File

@ -14,7 +14,6 @@ import { useQuery } from '@tanstack/react-query';
import { type ReactNode, useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { api } from '../../App';
import AdminButton from '../../components/buttons/AdminButton';
import { PrintingActions } from '../../components/buttons/PrintingActions';
import {
@ -43,6 +42,7 @@ import { PanelGroup } from '../../components/panels/PanelGroup';
import LocateItemButton from '../../components/plugins/LocateItemButton';
import { StatusRenderer } from '../../components/render/StatusRenderer';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { useApi } from '../../contexts/ApiContext';
import { formatCurrency } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
@ -78,6 +78,7 @@ import { StockTrackingTable } from '../../tables/stock/StockTrackingTable';
export default function StockDetail() {
const { id } = useParams();
const api = useApi();
const user = useUserState();
const globalSettings = useGlobalSettingsState();
@ -377,7 +378,7 @@ export default function StockDetail() {
); // Must not be installed into another item
}, [stockitem]);
const showSalesAlloctions: boolean = useMemo(() => {
const showSalesAllocations: boolean = useMemo(() => {
return stockitem?.part_detail?.salable;
}, [stockitem]);
@ -452,14 +453,14 @@ export default function StockDetail() {
icon: <IconBookmark />,
hidden:
!stockitem.in_stock ||
(!showSalesAlloctions && !showBuildAllocations),
(!showSalesAllocations && !showBuildAllocations),
content: (
<Accordion
multiple={true}
defaultValue={['buildallocations', 'salesallocations']}
defaultValue={['buildAllocations', 'salesAllocations']}
>
{showBuildAllocations && (
<Accordion.Item value='buildallocations' key='buildallocations'>
<Accordion.Item value='buildAllocations' key='buildAllocations'>
<Accordion.Control>
<StylishText size='lg'>{t`Build Order Allocations`}</StylishText>
</Accordion.Control>
@ -473,8 +474,8 @@ export default function StockDetail() {
</Accordion.Panel>
</Accordion.Item>
)}
{showSalesAlloctions && (
<Accordion.Item value='salesallocations' key='salesallocations'>
{showSalesAllocations && (
<Accordion.Item value='salesAllocations' key='salesAllocations'>
<Accordion.Control>
<StylishText size='lg'>{t`Sales Order Allocations`}</StylishText>
</Accordion.Control>
@ -536,7 +537,7 @@ export default function StockDetail() {
})
];
}, [
showSalesAlloctions,
showSalesAllocations,
showBuildAllocations,
showInstalledItems,
stockitem,

View File

@ -13,9 +13,9 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { showNotification } from '@mantine/notifications';
import { api } from '../App';
import { Boundary } from '../components/Boundary';
import type { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { useApi } from '../contexts/ApiContext';
import type { ModelType } from '../enums/ModelType';
import { resolveItem } from '../functions/conversion';
import { cancelEvent } from '../functions/events';
@ -139,6 +139,7 @@ export function InvenTreeTable<T extends Record<string, any>>({
const [fieldNames, setFieldNames] = useState<Record<string, string>>({});
const api = useApi();
const navigate = useNavigate();
const { showContextMenu } = useContextMenu();

View File

@ -16,11 +16,11 @@ import {
import { useState } from 'react';
import { Fragment } from 'react/jsx-runtime';
import { api } from '../App';
import { Boundary } from '../components/Boundary';
import { ActionButton } from '../components/buttons/ActionButton';
import { ButtonMenu } from '../components/buttons/ButtonMenu';
import { PrintingActions } from '../components/buttons/PrintingActions';
import { useApi } from '../contexts/ApiContext';
import { useDeleteApiFormModal } from '../hooks/UseForm';
import type { TableState } from '../hooks/UseTable';
import { TableColumnSelect } from './ColumnSelect';
@ -50,6 +50,8 @@ export default function InvenTreeTableHeader({
filters: TableFilter[];
toggleColumn: (column: string) => void;
}>) {
const api = useApi();
// Filter list visibility
const [filtersVisible, setFiltersVisible] = useState<boolean>(false);

View File

@ -11,12 +11,12 @@ import {
import { type ReactNode, useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { ActionButton } from '../../components/buttons/ActionButton';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { YesNoButton } from '../../components/buttons/YesNoButton';
import { Thumbnail } from '../../components/images/Thumbnail';
import ImporterDrawer from '../../components/importer/ImporterDrawer';
import { useApi } from '../../contexts/ApiContext';
import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
@ -71,6 +71,7 @@ export function BomTable({
partLocked?: boolean;
params?: any;
}>) {
const api = useApi();
const user = useUserState();
const table = useTable('bom');
const navigate = useNavigate();

View File

@ -10,10 +10,10 @@ import {
useState
} from 'react';
import { api } from '../../App';
import { PassFailButton } from '../../components/buttons/YesNoButton';
import type { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { RenderUser } from '../../components/render/User';
import { useApi } from '../../contexts/ApiContext';
import { formatDate } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { useTestResultFields } from '../../forms/StockForms';
@ -40,6 +40,7 @@ export default function BuildOrderTestTable({
}>) {
const table = useTable('build-tests');
const user = useUserState();
const api = useApi();
// Fetch the test templates required for this build order
const { data: testTemplates } = useQuery({

View File

@ -18,11 +18,11 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { ActionButton } from '../../components/buttons/ActionButton';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { ProgressBar } from '../../components/items/ProgressBar';
import { StylishText } from '../../components/items/StylishText';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles';
@ -121,6 +121,7 @@ export default function BuildOutputTable({
build,
refreshBuild
}: Readonly<{ build: any; refreshBuild: () => void }>) {
const api = useApi();
const user = useUserState();
const navigate = useNavigate();
const table = useTable('build-outputs');

View File

@ -10,10 +10,10 @@ import {
} from '@tabler/icons-react';
import { type ReactNode, useCallback, useMemo, useState } from 'react';
import { api } from '../../App';
import { ActionButton } from '../../components/buttons/ActionButton';
import type { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { AttachmentLink } from '../../components/items/AttachmentLink';
import { useApi } from '../../contexts/ApiContext';
import { formatFileSize } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import type { ModelType } from '../../enums/ModelType';
@ -99,6 +99,7 @@ export function AttachmentTable({
model_type: ModelType;
model_id: number;
}>): ReactNode {
const api = useApi();
const user = useUserState();
const table = useTable(`${model_type}-attachments`);

View File

@ -20,7 +20,6 @@ import { useQuery } from '@tanstack/react-query';
import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { YesNoButton } from '../../components/buttons/YesNoButton';
import {
@ -40,6 +39,7 @@ import {
TableStatusRenderer
} from '../../components/render/StatusRenderer';
import { MachineSettingList } from '../../components/settings/SettingList';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import {
useCreateApiFormModal,
@ -103,6 +103,8 @@ export function useMachineTypeDriver({
includeTypes = true,
includeDrivers = true
}: { includeTypes?: boolean; includeDrivers?: boolean } = {}) {
const api = useApi();
const {
data: machineTypes,
isFetching: isMachineTypesFetching,
@ -146,6 +148,7 @@ function MachineDrawer({
machinePk: string;
refreshTable: () => void;
}>) {
const api = useApi();
const navigate = useNavigate();
const {
data: machine,

View File

@ -5,9 +5,9 @@ import { useQuery } from '@tanstack/react-query';
import { type ReactNode, useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { YesNoButton } from '../../components/buttons/YesNoButton';
import type { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { useApi } from '../../contexts/ApiContext';
import { formatDecimal } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
@ -95,11 +95,12 @@ export default function ParametricPartTable({
}: Readonly<{
categoryId?: any;
}>) {
const api = useApi();
const table = useTable('parametric-parts');
const user = useUserState();
const navigate = useNavigate();
const categoryParmeters = useQuery({
const categoryParameters = useQuery({
queryKey: ['category-parameters', categoryId],
queryFn: async () => {
return api
@ -170,13 +171,13 @@ export default function ParametricPartTable({
records[partIndex].parameters[parameterIndex] = parameter;
}
table.setRecords(records);
table.updateRecord(records[partIndex]);
},
[table.records]
[table.updateRecord]
);
const parameterColumns: TableColumn[] = useMemo(() => {
const data = categoryParmeters.data ?? [];
const data = categoryParameters.data ?? [];
return data.map((template: any) => {
let title = template.name;
@ -201,7 +202,7 @@ export default function ParametricPartTable({
)
};
});
}, [user, categoryParmeters.data]);
}, [user, categoryParameters.data]);
const onParameterClick = useCallback((template: number, part: any) => {
setSelectedTemplate(template);

View File

@ -13,12 +13,12 @@ import {
import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { ActionButton } from '../../components/buttons/ActionButton';
import { YesNoButton } from '../../components/buttons/YesNoButton';
import { DetailDrawer } from '../../components/nav/DetailDrawer';
import PluginDrawer from '../../components/plugins/PluginDrawer';
import type { PluginInterface } from '../../components/plugins/PluginInterface';
import { useApi } from '../../contexts/ApiContext';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import {
useCreateApiFormModal,
@ -63,6 +63,7 @@ function PluginIcon({ plugin }: Readonly<{ plugin: PluginInterface }>) {
* Table displaying list of available plugins
*/
export default function PluginListTable() {
const api = useApi();
const table = useTable('plugin');
const navigate = useNavigate();
const user = useUserState();

View File

@ -10,12 +10,12 @@ import { useQuery } from '@tanstack/react-query';
import { DataTable } from 'mantine-datatable';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { api } from '../../App';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { PassFailButton } from '../../components/buttons/YesNoButton';
import type { ApiFormFieldSet } from '../../components/forms/fields/ApiFormField';
import { AttachmentLink } from '../../components/items/AttachmentLink';
import { RenderUser } from '../../components/render/User';
import { useApi } from '../../contexts/ApiContext';
import { formatDate } from '../../defaults/formatters';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { UserRoles } from '../../enums/Roles';
@ -47,6 +47,7 @@ export default function StockItemTestResultTable({
partId: number;
itemId: number;
}>) {
const api = useApi();
const user = useUserState();
const table = useTable('stocktests');

View File

@ -1,9 +1,9 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { useEffect } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { queryClient } from '../App';
import { BaseContext } from '../contexts/BaseContext';
import { api, queryClient } from '../App';
import { ApiProvider } from '../contexts/ApiContext';
import { ThemeContext } from '../contexts/ThemeContext';
import { defaultHostList } from '../defaults/defaultHostList';
import { base_url } from '../main';
import { routes } from '../router';
@ -19,10 +19,10 @@ export default function DesktopAppView() {
}, [hostList]);
return (
<BaseContext>
<QueryClientProvider client={queryClient}>
<ApiProvider client={queryClient} api={api}>
<ThemeContext>
<BrowserRouter basename={base_url}>{routes}</BrowserRouter>
</QueryClientProvider>
</BaseContext>
</ThemeContext>
</ApiProvider>
);
}

View File

@ -1,7 +1,7 @@
import { Trans } from '@lingui/macro';
import { Anchor, Center, Container, Stack, Text, Title } from '@mantine/core';
import { BaseContext } from '../contexts/BaseContext';
import { ThemeContext } from '../contexts/ThemeContext';
import { docLinks } from '../defaults/links';
import { IS_DEV } from '../main';
import { useLocalState } from '../states/LocalState';
@ -14,7 +14,7 @@ export default function MobileAppView() {
window.location.reload();
}
return (
<BaseContext>
<ThemeContext>
<Center h='100vh'>
<Container>
<Stack>
@ -38,6 +38,6 @@ export default function MobileAppView() {
</Stack>
</Container>
</Center>
</BaseContext>
</ThemeContext>
);
}