mirror of
https://github.com/inventree/InvenTree.git
synced 2025-11-08 00:55:41 +00:00
Merge branch 'master' of https://github.com/inventree/InvenTree into matmair/issue6281
This commit is contained in:
@@ -40,7 +40,10 @@ export default defineConfig({
|
||||
env: {
|
||||
INVENTREE_DEBUG: 'True',
|
||||
INVENTREE_PLUGINS_ENABLED: 'True',
|
||||
INVENTREE_ADMIN_URL: 'test-admin'
|
||||
INVENTREE_ADMIN_URL: 'test-admin',
|
||||
INVENTREE_SITE_URL: 'http://localhost:8000',
|
||||
INVENTREE_CORS_ORIGIN_ALLOW_ALL: 'True',
|
||||
INVENTREE_COOKIE_SAMESITE: 'Lax'
|
||||
},
|
||||
url: 'http://127.0.0.1:8000/api/',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
||||
@@ -27,8 +27,7 @@ export function Boundary({
|
||||
}>): ReactNode {
|
||||
const onError = useCallback(
|
||||
(error: unknown, componentStack: string | undefined, eventId: string) => {
|
||||
console.error(`Error rendering component: ${label}`);
|
||||
console.error(error, componentStack);
|
||||
console.error(`ERR: Error rendering component: ${label}`);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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[]>([]);
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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]
|
||||
|
||||
31
src/frontend/src/contexts/ApiContext.tsx
Normal file
31
src/frontend/src/contexts/ApiContext.tsx
Normal 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;
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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[]>([]);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: es_MX\n"
|
||||
"Project-Id-Version: inventree\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-12-31 04:52\n"
|
||||
"PO-Revision-Date: 2025-01-05 01:53\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish, Mexico\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function Scan() {
|
||||
// Prevent duplicates
|
||||
if (history.find((i) => i.model == item.model && i.pk == item.pk)) {
|
||||
showNotification({
|
||||
label: t`Duplicate`,
|
||||
title: t`Duplicate`,
|
||||
message: t`Item already scanned`,
|
||||
color: 'orange'
|
||||
});
|
||||
|
||||
@@ -42,6 +42,7 @@ export function CurrencyTable({
|
||||
.then(() => {
|
||||
table.refreshTable();
|
||||
showNotification({
|
||||
title: t`Success`,
|
||||
message: t`Exchange rates updated`,
|
||||
color: 'green'
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
IconUsersGroup
|
||||
} from '@tabler/icons-react';
|
||||
import { type ReactNode, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import {
|
||||
@@ -66,6 +66,7 @@ export type CompanyDetailProps = {
|
||||
export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
||||
const { id } = useParams();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const user = useUserState();
|
||||
|
||||
const {
|
||||
@@ -283,7 +284,9 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
||||
url: ApiEndpoints.company_list,
|
||||
pk: company?.pk,
|
||||
title: t`Delete Company`,
|
||||
onFormSuccess: refreshInstance
|
||||
onFormSuccess: () => {
|
||||
navigate('/');
|
||||
}
|
||||
});
|
||||
|
||||
const companyActions = useMemo(() => {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -217,6 +217,13 @@ export default function PurchaseOrderDetail() {
|
||||
icon: 'reference',
|
||||
copy: true,
|
||||
hidden: !order.project_code
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
@@ -225,6 +232,7 @@ export default function PurchaseOrderDetail() {
|
||||
type: 'date',
|
||||
name: 'creation_date',
|
||||
label: t`Creation Date`,
|
||||
copy: true,
|
||||
icon: 'calendar'
|
||||
},
|
||||
{
|
||||
@@ -240,6 +248,7 @@ export default function PurchaseOrderDetail() {
|
||||
name: 'target_date',
|
||||
label: t`Target Date`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !order.target_date
|
||||
},
|
||||
{
|
||||
@@ -249,13 +258,6 @@ export default function PurchaseOrderDetail() {
|
||||
label: t`Completion Date`,
|
||||
copy: true,
|
||||
hidden: !order.complete_date
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -187,6 +187,13 @@ export default function ReturnOrderDetail() {
|
||||
icon: 'reference',
|
||||
copy: true,
|
||||
hidden: !order.project_code
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
@@ -221,13 +228,6 @@ export default function ReturnOrderDetail() {
|
||||
label: t`Completion Date`,
|
||||
copy: true,
|
||||
hidden: !order.complete_date
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -199,6 +199,13 @@ export default function SalesOrderDetail() {
|
||||
icon: 'reference',
|
||||
copy: true,
|
||||
hidden: !order.project_code
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
@@ -231,13 +238,6 @@ export default function SalesOrderDetail() {
|
||||
label: t`Completion Date`,
|
||||
hidden: !order.shipment_date,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !order.responsible
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -36,7 +36,18 @@ export const useIconState = create<IconState>()((set, get) => ({
|
||||
fetchIcons: async () => {
|
||||
if (get().hasLoaded) return;
|
||||
|
||||
const packs = await api.get(apiUrl(ApiEndpoints.icons));
|
||||
const packs = await api.get(apiUrl(ApiEndpoints.icons)).catch((_error) => {
|
||||
console.error('ERR: Could not fetch icon packages');
|
||||
showNotification({
|
||||
title: t`Error`,
|
||||
message: t`Error loading icon package from server`,
|
||||
color: 'red'
|
||||
});
|
||||
});
|
||||
|
||||
if (!packs) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
packs.data.map(async (pack: any) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { YesNoButton } from '../components/buttons/YesNoButton';
|
||||
import { Thumbnail } from '../components/images/Thumbnail';
|
||||
import { ProgressBar } from '../components/items/ProgressBar';
|
||||
import { TableStatusRenderer } from '../components/render/StatusRenderer';
|
||||
import { RenderOwner } from '../components/render/User';
|
||||
import { RenderOwner, RenderUser } from '../components/render/User';
|
||||
import { formatCurrency, formatDate } from '../defaults/formatters';
|
||||
import type { ModelType } from '../enums/ModelType';
|
||||
import { resolveItem } from '../functions/conversion';
|
||||
@@ -202,6 +202,18 @@ export function StatusColumn({
|
||||
};
|
||||
}
|
||||
|
||||
export function CreatedByColumn(props: TableColumnProps): TableColumn {
|
||||
return {
|
||||
accessor: 'created_by',
|
||||
title: t`Created By`,
|
||||
sortable: true,
|
||||
switchable: true,
|
||||
render: (record: any) =>
|
||||
record.created_by && RenderUser({ instance: record.created_by }),
|
||||
...props
|
||||
};
|
||||
}
|
||||
|
||||
export function ResponsibleColumn(props: TableColumnProps): TableColumn {
|
||||
return {
|
||||
accessor: 'responsible',
|
||||
|
||||
@@ -205,3 +205,47 @@ export function HasProjectCodeFilter(): TableFilter {
|
||||
description: t`Show orders with an assigned project code`
|
||||
};
|
||||
}
|
||||
|
||||
export function OrderStatusFilter({
|
||||
model
|
||||
}: { model: ModelType }): TableFilter {
|
||||
return {
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
description: t`Filter by order status`,
|
||||
choiceFunction: StatusFilterOptions(model)
|
||||
};
|
||||
}
|
||||
|
||||
export function ProjectCodeFilter({
|
||||
choices
|
||||
}: { choices: TableFilterChoice[] }): TableFilter {
|
||||
return {
|
||||
name: 'project_code',
|
||||
label: t`Project Code`,
|
||||
description: t`Filter by project code`,
|
||||
choices: choices
|
||||
};
|
||||
}
|
||||
|
||||
export function ResponsibleFilter({
|
||||
choices
|
||||
}: { choices: TableFilterChoice[] }): TableFilter {
|
||||
return {
|
||||
name: 'assigned_to',
|
||||
label: t`Responsible`,
|
||||
description: t`Filter by responsible owner`,
|
||||
choices: choices
|
||||
};
|
||||
}
|
||||
|
||||
export function CreatedByFilter({
|
||||
choices
|
||||
}: { choices: TableFilterChoice[] }): TableFilter {
|
||||
return {
|
||||
name: 'created_by',
|
||||
label: t`Created By`,
|
||||
description: t`Filter by user who created the order`,
|
||||
choices: choices
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -8,7 +8,11 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { useBuildOrderFields } from '../../forms/BuildForms';
|
||||
import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
|
||||
import {
|
||||
useOwnerFilters,
|
||||
useProjectCodeFilters,
|
||||
useUserFilters
|
||||
} from '../../hooks/UseFilter';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { useTable } from '../../hooks/UseTable';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
@@ -32,8 +36,11 @@ import {
|
||||
HasProjectCodeFilter,
|
||||
MaxDateFilter,
|
||||
MinDateFilter,
|
||||
OrderStatusFilter,
|
||||
OutstandingFilter,
|
||||
OverdueFilter,
|
||||
StatusFilterOptions,
|
||||
ProjectCodeFilter,
|
||||
ResponsibleFilter,
|
||||
type TableFilter,
|
||||
TargetDateAfterFilter,
|
||||
TargetDateBeforeFilter
|
||||
@@ -117,21 +124,12 @@ export function BuildOrderTable({
|
||||
|
||||
const projectCodeFilters = useProjectCodeFilters();
|
||||
const ownerFilters = useOwnerFilters();
|
||||
const userFilters = useUserFilters();
|
||||
|
||||
const tableFilters: TableFilter[] = useMemo(() => {
|
||||
const filters: TableFilter[] = [
|
||||
{
|
||||
name: 'outstanding',
|
||||
type: 'boolean',
|
||||
label: t`Outstanding`,
|
||||
description: t`Show outstanding orders`
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
description: t`Filter by order status`,
|
||||
choiceFunction: StatusFilterOptions(ModelType.build)
|
||||
},
|
||||
OutstandingFilter(),
|
||||
OrderStatusFilter({ model: ModelType.build }),
|
||||
OverdueFilter(),
|
||||
AssignedToMeFilter(),
|
||||
MinDateFilter(),
|
||||
@@ -142,25 +140,15 @@ export function BuildOrderTable({
|
||||
TargetDateAfterFilter(),
|
||||
CompletedBeforeFilter(),
|
||||
CompletedAfterFilter(),
|
||||
{
|
||||
name: 'project_code',
|
||||
label: t`Project Code`,
|
||||
description: t`Filter by project code`,
|
||||
choices: projectCodeFilters.choices
|
||||
},
|
||||
ProjectCodeFilter({ choices: projectCodeFilters.choices }),
|
||||
HasProjectCodeFilter(),
|
||||
{
|
||||
name: 'issued_by',
|
||||
label: t`Issued By`,
|
||||
description: t`Filter by user who issued this order`,
|
||||
choices: ownerFilters.choices
|
||||
choices: userFilters.choices
|
||||
},
|
||||
{
|
||||
name: 'assigned_to',
|
||||
label: t`Responsible`,
|
||||
description: t`Filter by responsible owner`,
|
||||
choices: ownerFilters.choices
|
||||
}
|
||||
ResponsibleFilter({ choices: ownerFilters.choices })
|
||||
];
|
||||
|
||||
// If we are filtering on a specific part, we can include the "include variants" filter
|
||||
@@ -174,7 +162,12 @@ export function BuildOrderTable({
|
||||
}
|
||||
|
||||
return filters;
|
||||
}, [partId, projectCodeFilters.choices, ownerFilters.choices]);
|
||||
}, [
|
||||
partId,
|
||||
projectCodeFilters.choices,
|
||||
ownerFilters.choices,
|
||||
userFilters.choices
|
||||
]);
|
||||
|
||||
const user = useUserState();
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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`);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -8,13 +8,18 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { usePurchaseOrderFields } from '../../forms/PurchaseOrderForms';
|
||||
import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
|
||||
import {
|
||||
useOwnerFilters,
|
||||
useProjectCodeFilters,
|
||||
useUserFilters
|
||||
} from '../../hooks/UseFilter';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { useTable } from '../../hooks/UseTable';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import {
|
||||
CompletionDateColumn,
|
||||
CreatedByColumn,
|
||||
CreationDateColumn,
|
||||
DescriptionColumn,
|
||||
LineItemsProgressColumn,
|
||||
@@ -30,12 +35,15 @@ import {
|
||||
CompletedBeforeFilter,
|
||||
CreatedAfterFilter,
|
||||
CreatedBeforeFilter,
|
||||
CreatedByFilter,
|
||||
HasProjectCodeFilter,
|
||||
MaxDateFilter,
|
||||
MinDateFilter,
|
||||
OrderStatusFilter,
|
||||
OutstandingFilter,
|
||||
OverdueFilter,
|
||||
StatusFilterOptions,
|
||||
ProjectCodeFilter,
|
||||
ResponsibleFilter,
|
||||
type TableFilter,
|
||||
TargetDateAfterFilter,
|
||||
TargetDateBeforeFilter
|
||||
@@ -57,15 +65,11 @@ export function PurchaseOrderTable({
|
||||
|
||||
const projectCodeFilters = useProjectCodeFilters();
|
||||
const responsibleFilters = useOwnerFilters();
|
||||
const createdByFilters = useUserFilters();
|
||||
|
||||
const tableFilters: TableFilter[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
description: t`Filter by order status`,
|
||||
choiceFunction: StatusFilterOptions(ModelType.purchaseorder)
|
||||
},
|
||||
OrderStatusFilter({ model: ModelType.purchaseorder }),
|
||||
OutstandingFilter(),
|
||||
OverdueFilter(),
|
||||
AssignedToMeFilter(),
|
||||
@@ -77,21 +81,16 @@ export function PurchaseOrderTable({
|
||||
TargetDateAfterFilter(),
|
||||
CompletedBeforeFilter(),
|
||||
CompletedAfterFilter(),
|
||||
{
|
||||
name: 'project_code',
|
||||
label: t`Project Code`,
|
||||
description: t`Filter by project code`,
|
||||
choices: projectCodeFilters.choices
|
||||
},
|
||||
ProjectCodeFilter({ choices: projectCodeFilters.choices }),
|
||||
HasProjectCodeFilter(),
|
||||
{
|
||||
name: 'assigned_to',
|
||||
label: t`Responsible`,
|
||||
description: t`Filter by responsible owner`,
|
||||
choices: responsibleFilters.choices
|
||||
}
|
||||
ResponsibleFilter({ choices: responsibleFilters.choices }),
|
||||
CreatedByFilter({ choices: createdByFilters.choices })
|
||||
];
|
||||
}, [projectCodeFilters.choices, responsibleFilters.choices]);
|
||||
}, [
|
||||
projectCodeFilters.choices,
|
||||
responsibleFilters.choices,
|
||||
createdByFilters.choices
|
||||
]);
|
||||
|
||||
const tableColumns = useMemo(() => {
|
||||
return [
|
||||
@@ -120,6 +119,7 @@ export function PurchaseOrderTable({
|
||||
StatusColumn({ model: ModelType.purchaseorder }),
|
||||
ProjectCodeColumn({}),
|
||||
CreationDateColumn({}),
|
||||
CreatedByColumn({}),
|
||||
TargetDateColumn({}),
|
||||
CompletionDateColumn({
|
||||
accessor: 'complete_date'
|
||||
|
||||
@@ -8,13 +8,18 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { useReturnOrderFields } from '../../forms/ReturnOrderForms';
|
||||
import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
|
||||
import {
|
||||
useOwnerFilters,
|
||||
useProjectCodeFilters,
|
||||
useUserFilters
|
||||
} from '../../hooks/UseFilter';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { useTable } from '../../hooks/UseTable';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import {
|
||||
CompletionDateColumn,
|
||||
CreatedByColumn,
|
||||
CreationDateColumn,
|
||||
DescriptionColumn,
|
||||
LineItemsProgressColumn,
|
||||
@@ -30,12 +35,15 @@ import {
|
||||
CompletedBeforeFilter,
|
||||
CreatedAfterFilter,
|
||||
CreatedBeforeFilter,
|
||||
CreatedByFilter,
|
||||
HasProjectCodeFilter,
|
||||
MaxDateFilter,
|
||||
MinDateFilter,
|
||||
OrderStatusFilter,
|
||||
OutstandingFilter,
|
||||
OverdueFilter,
|
||||
StatusFilterOptions,
|
||||
ProjectCodeFilter,
|
||||
ResponsibleFilter,
|
||||
type TableFilter,
|
||||
TargetDateAfterFilter,
|
||||
TargetDateBeforeFilter
|
||||
@@ -54,15 +62,11 @@ export function ReturnOrderTable({
|
||||
|
||||
const projectCodeFilters = useProjectCodeFilters();
|
||||
const responsibleFilters = useOwnerFilters();
|
||||
const createdByFilters = useUserFilters();
|
||||
|
||||
const tableFilters: TableFilter[] = useMemo(() => {
|
||||
const filters: TableFilter[] = [
|
||||
{
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
description: t`Filter by order status`,
|
||||
choiceFunction: StatusFilterOptions(ModelType.returnorder)
|
||||
},
|
||||
OrderStatusFilter({ model: ModelType.returnorder }),
|
||||
OutstandingFilter(),
|
||||
OverdueFilter(),
|
||||
AssignedToMeFilter(),
|
||||
@@ -74,19 +78,10 @@ export function ReturnOrderTable({
|
||||
TargetDateAfterFilter(),
|
||||
CompletedBeforeFilter(),
|
||||
CompletedAfterFilter(),
|
||||
{
|
||||
name: 'project_code',
|
||||
label: t`Project Code`,
|
||||
description: t`Filter by project code`,
|
||||
choices: projectCodeFilters.choices
|
||||
},
|
||||
HasProjectCodeFilter(),
|
||||
{
|
||||
name: 'assigned_to',
|
||||
label: t`Responsible`,
|
||||
description: t`Filter by responsible owner`,
|
||||
choices: responsibleFilters.choices
|
||||
}
|
||||
ProjectCodeFilter({ choices: projectCodeFilters.choices }),
|
||||
ResponsibleFilter({ choices: responsibleFilters.choices }),
|
||||
CreatedByFilter({ choices: createdByFilters.choices })
|
||||
];
|
||||
|
||||
if (!!partId) {
|
||||
@@ -99,7 +94,12 @@ export function ReturnOrderTable({
|
||||
}
|
||||
|
||||
return filters;
|
||||
}, [partId, projectCodeFilters.choices, responsibleFilters.choices]);
|
||||
}, [
|
||||
partId,
|
||||
projectCodeFilters.choices,
|
||||
responsibleFilters.choices,
|
||||
createdByFilters.choices
|
||||
]);
|
||||
|
||||
const tableColumns = useMemo(() => {
|
||||
return [
|
||||
@@ -128,6 +128,7 @@ export function ReturnOrderTable({
|
||||
StatusColumn({ model: ModelType.returnorder }),
|
||||
ProjectCodeColumn({}),
|
||||
CreationDateColumn({}),
|
||||
CreatedByColumn({}),
|
||||
TargetDateColumn({}),
|
||||
CompletionDateColumn({
|
||||
accessor: 'complete_date'
|
||||
|
||||
@@ -9,12 +9,17 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
import { UserRoles } from '../../enums/Roles';
|
||||
import { useSalesOrderFields } from '../../forms/SalesOrderForms';
|
||||
import { useOwnerFilters, useProjectCodeFilters } from '../../hooks/UseFilter';
|
||||
import {
|
||||
useOwnerFilters,
|
||||
useProjectCodeFilters,
|
||||
useUserFilters
|
||||
} from '../../hooks/UseFilter';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { useTable } from '../../hooks/UseTable';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import {
|
||||
CreatedByColumn,
|
||||
CreationDateColumn,
|
||||
DescriptionColumn,
|
||||
LineItemsProgressColumn,
|
||||
@@ -31,12 +36,15 @@ import {
|
||||
CompletedBeforeFilter,
|
||||
CreatedAfterFilter,
|
||||
CreatedBeforeFilter,
|
||||
CreatedByFilter,
|
||||
HasProjectCodeFilter,
|
||||
MaxDateFilter,
|
||||
MinDateFilter,
|
||||
OrderStatusFilter,
|
||||
OutstandingFilter,
|
||||
OverdueFilter,
|
||||
StatusFilterOptions,
|
||||
ProjectCodeFilter,
|
||||
ResponsibleFilter,
|
||||
type TableFilter,
|
||||
TargetDateAfterFilter,
|
||||
TargetDateBeforeFilter
|
||||
@@ -55,15 +63,11 @@ export function SalesOrderTable({
|
||||
|
||||
const projectCodeFilters = useProjectCodeFilters();
|
||||
const responsibleFilters = useOwnerFilters();
|
||||
const createdByFilters = useUserFilters();
|
||||
|
||||
const tableFilters: TableFilter[] = useMemo(() => {
|
||||
const filters: TableFilter[] = [
|
||||
{
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
description: t`Filter by order status`,
|
||||
choiceFunction: StatusFilterOptions(ModelType.salesorder)
|
||||
},
|
||||
OrderStatusFilter({ model: ModelType.salesorder }),
|
||||
OutstandingFilter(),
|
||||
OverdueFilter(),
|
||||
AssignedToMeFilter(),
|
||||
@@ -75,19 +79,10 @@ export function SalesOrderTable({
|
||||
TargetDateAfterFilter(),
|
||||
CompletedBeforeFilter(),
|
||||
CompletedAfterFilter(),
|
||||
{
|
||||
name: 'project_code',
|
||||
label: t`Project Code`,
|
||||
description: t`Filter by project code`,
|
||||
choices: projectCodeFilters.choices
|
||||
},
|
||||
HasProjectCodeFilter(),
|
||||
{
|
||||
name: 'assigned_to',
|
||||
label: t`Responsible`,
|
||||
description: t`Filter by responsible owner`,
|
||||
choices: responsibleFilters.choices
|
||||
}
|
||||
ProjectCodeFilter({ choices: projectCodeFilters.choices }),
|
||||
ResponsibleFilter({ choices: responsibleFilters.choices }),
|
||||
CreatedByFilter({ choices: createdByFilters.choices })
|
||||
];
|
||||
|
||||
if (!!partId) {
|
||||
@@ -100,7 +95,12 @@ export function SalesOrderTable({
|
||||
}
|
||||
|
||||
return filters;
|
||||
}, [partId, projectCodeFilters.choices, responsibleFilters.choices]);
|
||||
}, [
|
||||
partId,
|
||||
projectCodeFilters.choices,
|
||||
responsibleFilters.choices,
|
||||
createdByFilters.choices
|
||||
]);
|
||||
|
||||
const salesOrderFields = useSalesOrderFields({});
|
||||
|
||||
@@ -165,6 +165,7 @@ export function SalesOrderTable({
|
||||
StatusColumn({ model: ModelType.salesorder }),
|
||||
ProjectCodeColumn({}),
|
||||
CreationDateColumn({}),
|
||||
CreatedByColumn({}),
|
||||
TargetDateColumn({}),
|
||||
ShipmentDateColumn({}),
|
||||
ResponsibleColumn({}),
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export const doQuickLogin = async (
|
||||
await page.goto(`${url}/login/?login=${username}&password=${password}`);
|
||||
await page.waitForURL('**/platform/home');
|
||||
|
||||
await page.getByLabel('navigation-menu').waitFor();
|
||||
await page.getByText(/InvenTree Demo Server -/).waitFor();
|
||||
};
|
||||
|
||||
|
||||
@@ -35,8 +35,24 @@ test('Purchase Orders - Barcodes', async ({ page }) => {
|
||||
await page.getByRole('img', { name: 'QR Code' }).waitFor();
|
||||
await page.getByRole('banner').getByRole('button').click();
|
||||
|
||||
// Link to barcode
|
||||
// Un-link barcode if a link exists
|
||||
await page.getByLabel('action-menu-barcode-actions').click();
|
||||
await page.waitForTimeout(100);
|
||||
|
||||
if (
|
||||
await page
|
||||
.getByLabel('action-menu-barcode-actions-unlink-barcode')
|
||||
.isVisible()
|
||||
) {
|
||||
await page.getByLabel('action-menu-barcode-actions-unlink-barcode').click();
|
||||
await page.getByRole('button', { name: 'Unlink Barcode' }).click();
|
||||
await page.waitForTimeout(100);
|
||||
} else {
|
||||
await page.keyboard.press('Escape');
|
||||
}
|
||||
|
||||
// Link to barcode
|
||||
await page.getByLabel('action-menu-barcode-actions', { exact: true }).click();
|
||||
await page.getByLabel('action-menu-barcode-actions-link-barcode').click();
|
||||
|
||||
await page.getByLabel('barcode-input-scanner').click();
|
||||
@@ -49,7 +65,7 @@ test('Purchase Orders - Barcodes', async ({ page }) => {
|
||||
await page.getByRole('button', { name: 'Issue Order' }).waitFor();
|
||||
|
||||
// Ensure we can scan back to this page, with the associated barcode
|
||||
await page.goto(`${baseUrl}/home`);
|
||||
await page.goto(`${baseUrl}/`);
|
||||
await page.waitForTimeout(250);
|
||||
await page.getByRole('button', { name: 'Open Barcode Scanner' }).click();
|
||||
await page.getByPlaceholder('Enter barcode data').fill('1234567890');
|
||||
|
||||
Reference in New Issue
Block a user