mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Api tweaks (#5690)
* Improvements to API handling on react UI - Do not force "/api/" prefix to the base URL of the server - We will need to fetch media files from the server (at /media/) - Extend API URL helper functions * Update some more hard-coded URLs * Fix search API endpoint * Fix div for panel tab * Fix debug msg
This commit is contained in:
parent
0c519c6b98
commit
814322e512
@ -26,7 +26,7 @@ export function InstanceOptions({
|
|||||||
]);
|
]);
|
||||||
const hostListData = Object.keys(hostList).map((key) => ({
|
const hostListData = Object.keys(hostList).map((key) => ({
|
||||||
value: key,
|
value: key,
|
||||||
label: hostList[key].name
|
label: hostList[key]?.name
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function SaveOptions(newHostList: HostList): void {
|
function SaveOptions(newHostList: HostList): void {
|
||||||
@ -93,7 +93,7 @@ function ServerInfo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Text>
|
<Text>
|
||||||
{hostList[hostKey].host}
|
{hostList[hostKey]?.host}
|
||||||
<br />
|
<br />
|
||||||
<Trans>Version: {server.version}</Trans>
|
<Trans>Version: {server.version}</Trans>
|
||||||
<br />
|
<br />
|
||||||
|
@ -23,6 +23,7 @@ import { Html5QrcodeResult } from 'html5-qrcode/core';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
export function QrCodeModal({
|
export function QrCodeModal({
|
||||||
context,
|
context,
|
||||||
@ -63,16 +64,18 @@ export function QrCodeModal({
|
|||||||
qrCodeScanner?.pause();
|
qrCodeScanner?.pause();
|
||||||
|
|
||||||
handlers.append(decodedText);
|
handlers.append(decodedText);
|
||||||
api.post('/barcode/', { barcode: decodedText }).then((response) => {
|
api
|
||||||
showNotification({
|
.post(apiUrl(ApiPaths.barcode), { barcode: decodedText })
|
||||||
title: response.data?.success || t`Unknown response`,
|
.then((response) => {
|
||||||
message: JSON.stringify(response.data),
|
showNotification({
|
||||||
color: response.data?.success ? 'teal' : 'red'
|
title: response.data?.success || t`Unknown response`,
|
||||||
|
message: JSON.stringify(response.data),
|
||||||
|
color: response.data?.success ? 'teal' : 'red'
|
||||||
|
});
|
||||||
|
if (response.data?.url) {
|
||||||
|
window.location.href = response.data.url;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (response.data?.url) {
|
|
||||||
window.location.href = response.data.url;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
qrCodeScanner?.resume();
|
qrCodeScanner?.resume();
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,10 @@ export function BreadcrumbList({ breadcrumbs }: { breadcrumbs: Breadcrumb[] }) {
|
|||||||
<Breadcrumbs>
|
<Breadcrumbs>
|
||||||
{breadcrumbs.map((breadcrumb, index) => {
|
{breadcrumbs.map((breadcrumb, index) => {
|
||||||
return (
|
return (
|
||||||
<Anchor onClick={() => breadcrumb.url && navigate(breadcrumb.url)}>
|
<Anchor
|
||||||
|
key={`breadcrumb-${index}`}
|
||||||
|
onClick={() => breadcrumb.url && navigate(breadcrumb.url)}
|
||||||
|
>
|
||||||
<Text size="sm">{breadcrumb.name}</Text>
|
<Text size="sm">{breadcrumb.name}</Text>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,7 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { navTabs as mainNavTabs } from '../../defaults/links';
|
import { navTabs as mainNavTabs } from '../../defaults/links';
|
||||||
import { InvenTreeStyle } from '../../globalStyle';
|
import { InvenTreeStyle } from '../../globalStyle';
|
||||||
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
import { ScanButton } from '../items/ScanButton';
|
import { ScanButton } from '../items/ScanButton';
|
||||||
import { MainMenu } from './MainMenu';
|
import { MainMenu } from './MainMenu';
|
||||||
import { NavHoverMenu } from './NavHoverMenu';
|
import { NavHoverMenu } from './NavHoverMenu';
|
||||||
@ -36,7 +37,7 @@ export function Header() {
|
|||||||
queryKey: ['notification-count'],
|
queryKey: ['notification-count'],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return api
|
return api
|
||||||
.get('/notifications/', {
|
.get(apiUrl(ApiPaths.notifications_list), {
|
||||||
params: {
|
params: {
|
||||||
read: false,
|
read: false,
|
||||||
limit: 1
|
limit: 1
|
||||||
|
@ -34,7 +34,7 @@ export function NavHoverMenu({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hostKey && hostList[hostKey]) {
|
if (hostKey && hostList[hostKey]) {
|
||||||
setInstanceName(hostList[hostKey].name);
|
setInstanceName(hostList[hostKey]?.name);
|
||||||
}
|
}
|
||||||
}, [hostKey]);
|
}, [hostKey]);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import { useState } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a notification drawer.
|
* Construct a notification drawer.
|
||||||
@ -33,7 +34,7 @@ export function NotificationDrawer({
|
|||||||
queryKey: ['notifications', opened],
|
queryKey: ['notifications', opened],
|
||||||
queryFn: async () =>
|
queryFn: async () =>
|
||||||
api
|
api
|
||||||
.get('/notifications/', {
|
.get(apiUrl(ApiPaths.notifications_list), {
|
||||||
params: {
|
params: {
|
||||||
read: false,
|
read: false,
|
||||||
limit: 10
|
limit: 10
|
||||||
|
@ -68,6 +68,7 @@ export function PanelGroup({
|
|||||||
(panel, idx) =>
|
(panel, idx) =>
|
||||||
!panel.hidden && (
|
!panel.hidden && (
|
||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
|
key={`panel-tab-${panel.name}`}
|
||||||
p="xs"
|
p="xs"
|
||||||
value={panel.name}
|
value={panel.name}
|
||||||
icon={panel.icon}
|
icon={panel.icon}
|
||||||
|
@ -30,6 +30,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
import { RenderInstance } from '../render/Instance';
|
import { RenderInstance } from '../render/Instance';
|
||||||
import { ModelInformationDict, ModelType } from '../render/ModelType';
|
import { ModelInformationDict, ModelType } from '../render/ModelType';
|
||||||
|
|
||||||
@ -264,7 +265,7 @@ export function SearchDrawer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.post(`/search/`, params)
|
.post(apiUrl(ApiPaths.api_search), params)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
return response.data;
|
return response.data;
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,7 @@ import { Anchor, Loader } from '@mantine/core';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
import { ThumbnailHoverCard } from '../items/Thumbnail';
|
import { ThumbnailHoverCard } from '../items/Thumbnail';
|
||||||
|
|
||||||
export function GeneralRenderer({
|
export function GeneralRenderer({
|
||||||
@ -33,7 +33,7 @@ export function GeneralRenderer({
|
|||||||
queryKey: [ref, pk],
|
queryKey: [ref, pk],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
return api
|
return api
|
||||||
.get(url(api_key, pk))
|
.get(apiUrl(api_key, pk))
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@ import { useMemo } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { TableFilter } from '../Filter';
|
import { TableFilter } from '../Filter';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
@ -142,7 +142,7 @@ export function BuildOrderTable({ params = {} }: { params?: any }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.build_order_list)}
|
url={apiUrl(ApiPaths.build_order_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { RowAction } from '../RowActions';
|
import { RowAction } from '../RowActions';
|
||||||
@ -40,7 +40,7 @@ export function NotificationTable({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.notifications_list)}
|
url={apiUrl(ApiPaths.notifications_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -3,7 +3,7 @@ import { useMemo } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ export function PartCategoryTable({ params = {} }: { params?: any }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.category_list)}
|
url={apiUrl(ApiPaths.category_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -7,7 +7,7 @@ import { editPart } from '../../../functions/forms/PartForms';
|
|||||||
import { notYetImplemented } from '../../../functions/notifications';
|
import { notYetImplemented } from '../../../functions/notifications';
|
||||||
import { shortenString } from '../../../functions/tables';
|
import { shortenString } from '../../../functions/tables';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { TableFilter } from '../Filter';
|
import { TableFilter } from '../Filter';
|
||||||
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';
|
import { InvenTreeTable, InvenTreeTableProps } from '../InvenTreeTable';
|
||||||
@ -221,7 +221,7 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.part_list)}
|
url={apiUrl(ApiPaths.part_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -6,7 +6,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
|
|
||||||
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms';
|
import { openCreateApiForm, openDeleteApiForm } from '../../../functions/forms';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { Thumbnail } from '../../items/Thumbnail';
|
import { Thumbnail } from '../../items/Thumbnail';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
@ -116,7 +116,7 @@ export function RelatedPartTable({ partId }: { partId: number }): ReactNode {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.related_part_list)}
|
url={apiUrl(ApiPaths.related_part_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -5,8 +5,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
|
|
||||||
import { notYetImplemented } from '../../../functions/notifications';
|
import { notYetImplemented } from '../../../functions/notifications';
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { ThumbnailHoverCard } from '../../items/Thumbnail';
|
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { TableFilter } from '../Filter';
|
import { TableFilter } from '../Filter';
|
||||||
import { RowAction } from '../RowActions';
|
import { RowAction } from '../RowActions';
|
||||||
@ -126,7 +125,7 @@ export function StockItemTable({ params = {} }: { params?: any }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.stock_item_list)}
|
url={apiUrl(ApiPaths.stock_item_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -3,7 +3,7 @@ import { useMemo } from 'react';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
import { useTableRefresh } from '../../../hooks/TableRefresh';
|
||||||
import { ApiPaths, url } from '../../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { TableColumn } from '../Column';
|
import { TableColumn } from '../Column';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ export function StockLocationTable({ params = {} }: { params?: any }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InvenTreeTable
|
<InvenTreeTable
|
||||||
url={url(ApiPaths.stock_location_list)}
|
url={apiUrl(ApiPaths.stock_location_list)}
|
||||||
tableKey={tableKey}
|
tableKey={tableKey}
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications, showNotification } from '@mantine/notifications';
|
||||||
import { IconCheck } from '@tabler/icons-react';
|
import { IconCheck } from '@tabler/icons-react';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ApiPaths, url, useServerApiState } from '../states/ApiState';
|
import { ApiPaths, apiUrl, useServerApiState } from '../states/ApiState';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useSessionState } from '../states/SessionState';
|
import { useSessionState } from '../states/SessionState';
|
||||||
import {
|
import {
|
||||||
@ -18,9 +18,17 @@ export const doClassicLogin = async (username: string, password: string) => {
|
|||||||
|
|
||||||
// Get token from server
|
// Get token from server
|
||||||
const token = await axios
|
const token = await axios
|
||||||
.get(`${host}${url(ApiPaths.user_token)}`, { auth: { username, password } })
|
.get(apiUrl(ApiPaths.user_token), {
|
||||||
|
auth: { username, password },
|
||||||
|
baseURL: host.toString()
|
||||||
|
})
|
||||||
.then((response) => response.data.token)
|
.then((response) => response.data.token)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
showNotification({
|
||||||
|
title: t`Login failed`,
|
||||||
|
message: t`Error fetching token from server.`,
|
||||||
|
color: 'red'
|
||||||
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,7 +58,7 @@ export const doClassicLogout = async () => {
|
|||||||
export const doSimpleLogin = async (email: string) => {
|
export const doSimpleLogin = async (email: string) => {
|
||||||
const { host } = useLocalState.getState();
|
const { host } = useLocalState.getState();
|
||||||
const mail = await axios
|
const mail = await axios
|
||||||
.post(`${host}${url(ApiPaths.user_simple_login)}`, {
|
.post(apiUrl(ApiPaths.user_simple_login), {
|
||||||
email: email
|
email: email
|
||||||
})
|
})
|
||||||
.then((response) => response.data)
|
.then((response) => response.data)
|
||||||
@ -77,7 +85,7 @@ export const doTokenLogin = (token: string) => {
|
|||||||
|
|
||||||
export function handleReset(navigate: any, values: { email: string }) {
|
export function handleReset(navigate: any, values: { email: string }) {
|
||||||
api
|
api
|
||||||
.post(url(ApiPaths.user_reset), values, {
|
.post(apiUrl(ApiPaths.user_reset), values, {
|
||||||
headers: { Authorization: '' }
|
headers: { Authorization: '' }
|
||||||
})
|
})
|
||||||
.then((val) => {
|
.then((val) => {
|
||||||
@ -101,7 +109,7 @@ export function handleReset(navigate: any, values: { email: string }) {
|
|||||||
|
|
||||||
export function checkLoginState(navigate: any) {
|
export function checkLoginState(navigate: any) {
|
||||||
api
|
api
|
||||||
.get(url(ApiPaths.user_token))
|
.get(apiUrl(ApiPaths.user_token))
|
||||||
.then((val) => {
|
.then((val) => {
|
||||||
if (val.status === 200 && val.data.token) {
|
if (val.status === 200 && val.data.token) {
|
||||||
doTokenLogin(val.data.token);
|
doTokenLogin(val.data.token);
|
||||||
|
@ -6,7 +6,7 @@ import { AxiosResponse } from 'axios';
|
|||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ApiForm, ApiFormProps } from '../components/forms/ApiForm';
|
import { ApiForm, ApiFormProps } from '../components/forms/ApiForm';
|
||||||
import { ApiFormFieldType } from '../components/forms/fields/ApiFormField';
|
import { ApiFormFieldType } from '../components/forms/fields/ApiFormField';
|
||||||
import { url } from '../states/ApiState';
|
import { apiUrl } from '../states/ApiState';
|
||||||
import { invalidResponse, permissionDenied } from './notifications';
|
import { invalidResponse, permissionDenied } from './notifications';
|
||||||
import { generateUniqueId } from './uid';
|
import { generateUniqueId } from './uid';
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ import { generateUniqueId } from './uid';
|
|||||||
* Construct an API url from the provided ApiFormProps object
|
* Construct an API url from the provided ApiFormProps object
|
||||||
*/
|
*/
|
||||||
export function constructFormUrl(props: ApiFormProps): string {
|
export function constructFormUrl(props: ApiFormProps): string {
|
||||||
return url(props.url, props.pk);
|
return apiUrl(props.url, props.pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ApiPaths, url } from '../states/ApiState';
|
import { ApiPaths, apiUrl } from '../states/ApiState';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook for loading a single instance of an instance from the API
|
* Custom hook for loading a single instance of an instance from the API
|
||||||
@ -32,8 +32,10 @@ export function useInstance({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let url = apiUrl(endpoint, pk);
|
||||||
|
|
||||||
return api
|
return api
|
||||||
.get(url(endpoint, pk), {
|
.get(url, {
|
||||||
params: params
|
params: params
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -48,7 +50,7 @@ export function useInstance({
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInstance({});
|
setInstance({});
|
||||||
console.error(`Error fetching instance ${url}${pk}:`, error);
|
console.error(`Error fetching instance ${url}:`, error);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -28,13 +28,13 @@ export const IS_DEV_OR_DEMO = IS_DEV || IS_DEMO;
|
|||||||
window.INVENTREE_SETTINGS = {
|
window.INVENTREE_SETTINGS = {
|
||||||
server_list: {
|
server_list: {
|
||||||
'mantine-cqj63coxn': {
|
'mantine-cqj63coxn': {
|
||||||
host: `${window.location.origin}/api/`,
|
host: `${window.location.origin}/`,
|
||||||
name: 'Current Server'
|
name: 'Current Server'
|
||||||
},
|
},
|
||||||
...(IS_DEV_OR_DEMO
|
...(IS_DEV_OR_DEMO
|
||||||
? {
|
? {
|
||||||
'mantine-u56l5jt85': {
|
'mantine-u56l5jt85': {
|
||||||
host: 'https://demo.inventree.org/api/',
|
host: 'https://demo.inventree.org/',
|
||||||
name: 'InvenTree Demo'
|
name: 'InvenTree Demo'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ export default function Login() {
|
|||||||
state.fetchServerApiState
|
state.fetchServerApiState
|
||||||
]);
|
]);
|
||||||
const hostname =
|
const hostname =
|
||||||
hostList[hostKey] === undefined ? t`No selection` : hostList[hostKey].name;
|
hostList[hostKey] === undefined ? t`No selection` : hostList[hostKey]?.name;
|
||||||
const [hostEdit, setHostEdit] = useToggle([false, true] as const);
|
const [hostEdit, setHostEdit] = useToggle([false, true] as const);
|
||||||
|
|
||||||
// Data manipulation functions
|
// Data manipulation functions
|
||||||
function ChangeHost(newHost: string): void {
|
function ChangeHost(newHost: string): void {
|
||||||
setHost(hostList[newHost].host, newHost);
|
setHost(hostList[newHost]?.host, newHost);
|
||||||
setApiDefaults();
|
setApiDefaults();
|
||||||
fetchServerApiState();
|
fetchServerApiState();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom';
|
|||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { LanguageContext } from '../../contexts/LanguageContext';
|
import { LanguageContext } from '../../contexts/LanguageContext';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
export default function Set_Password() {
|
export default function Set_Password() {
|
||||||
const simpleForm = useForm({ initialValues: { password: '' } });
|
const simpleForm = useForm({ initialValues: { password: '' } });
|
||||||
@ -57,7 +57,7 @@ export default function Set_Password() {
|
|||||||
// Set password with call to backend
|
// Set password with call to backend
|
||||||
api
|
api
|
||||||
.post(
|
.post(
|
||||||
url(ApiPaths.user_reset_set),
|
apiUrl(ApiPaths.user_reset_set),
|
||||||
{
|
{
|
||||||
uid: uid,
|
uid: uid,
|
||||||
token: token,
|
token: token,
|
||||||
|
@ -19,6 +19,7 @@ import { api, queryClient } from '../../../App';
|
|||||||
import { ColorToggle } from '../../../components/items/ColorToggle';
|
import { ColorToggle } from '../../../components/items/ColorToggle';
|
||||||
import { EditButton } from '../../../components/items/EditButton';
|
import { EditButton } from '../../../components/items/EditButton';
|
||||||
import { LanguageSelect } from '../../../components/items/LanguageSelect';
|
import { LanguageSelect } from '../../../components/items/LanguageSelect';
|
||||||
|
import { ApiPaths, apiUrl } from '../../../states/ApiState';
|
||||||
import { useLocalState } from '../../../states/LocalState';
|
import { useLocalState } from '../../../states/LocalState';
|
||||||
import { UserTheme } from './UserTheme';
|
import { UserTheme } from './UserTheme';
|
||||||
|
|
||||||
@ -29,7 +30,8 @@ export function UserPanel() {
|
|||||||
|
|
||||||
// data
|
// data
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
return api.get('user/me/').then((res) => res.data);
|
// TODO: Replace this call with the global user state, perhaps?
|
||||||
|
return api.get(apiUrl(ApiPaths.user_me)).then((res) => res.data);
|
||||||
}
|
}
|
||||||
const { isLoading, data } = useQuery({
|
const { isLoading, data } = useQuery({
|
||||||
queryKey: ['user-me'],
|
queryKey: ['user-me'],
|
||||||
@ -68,7 +70,7 @@ export function UserInfo({ data }: { data: any }) {
|
|||||||
const form = useForm({ initialValues: data });
|
const form = useForm({ initialValues: data });
|
||||||
const [editing, setEditing] = useToggle([false, true] as const);
|
const [editing, setEditing] = useToggle([false, true] as const);
|
||||||
function SaveData(values: any) {
|
function SaveData(values: any) {
|
||||||
api.put('user/me/', values).then((res) => {
|
api.put(apiUrl(ApiPaths.user_me)).then((res) => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
setEditing();
|
setEditing();
|
||||||
queryClient.invalidateQueries(['user-me']);
|
queryClient.invalidateQueries(['user-me']);
|
||||||
|
@ -50,7 +50,7 @@ import { TitleWithDoc } from '../../components/items/TitleWithDoc';
|
|||||||
import { Render, RenderTypes } from '../../components/renderers';
|
import { Render, RenderTypes } from '../../components/renderers';
|
||||||
import { notYetImplemented } from '../../functions/notifications';
|
import { notYetImplemented } from '../../functions/notifications';
|
||||||
import { IS_DEV_OR_DEMO } from '../../main';
|
import { IS_DEV_OR_DEMO } from '../../main';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
interface ScanItem {
|
interface ScanItem {
|
||||||
id: string;
|
id: string;
|
||||||
@ -136,7 +136,7 @@ export default function Scan() {
|
|||||||
|
|
||||||
function runBarcode(value: string, id?: string) {
|
function runBarcode(value: string, id?: string) {
|
||||||
api
|
api
|
||||||
.post(url(ApiPaths.barcode), { barcode: value })
|
.post(apiUrl(ApiPaths.barcode), { barcode: value })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
// update item in history
|
// update item in history
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
@ -24,7 +24,7 @@ import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable';
|
|||||||
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
|
import { StockItemTable } from '../../components/tables/stock/StockItemTable';
|
||||||
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
||||||
import { useInstance } from '../../hooks/UseInstance';
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detail page for a single Build Order
|
* Detail page for a single Build Order
|
||||||
@ -121,7 +121,7 @@ export default function BuildDetail() {
|
|||||||
icon: <IconNotes size="18" />,
|
icon: <IconNotes size="18" />,
|
||||||
content: (
|
content: (
|
||||||
<NotesEditor
|
<NotesEditor
|
||||||
url={url(ApiPaths.build_order_list, build.pk)}
|
url={apiUrl(ApiPaths.build_order_list, build.pk)}
|
||||||
data={build.notes ?? ''}
|
data={build.notes ?? ''}
|
||||||
allowEdit={true}
|
allowEdit={true}
|
||||||
/>
|
/>
|
||||||
|
@ -29,7 +29,7 @@ import { StockItemTable } from '../../components/tables/stock/StockItemTable';
|
|||||||
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
||||||
import { editPart } from '../../functions/forms/PartForms';
|
import { editPart } from '../../functions/forms/PartForms';
|
||||||
import { useInstance } from '../../hooks/UseInstance';
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detail view for a single Part instance
|
* Detail view for a single Part instance
|
||||||
@ -157,7 +157,7 @@ export default function PartDetail() {
|
|||||||
// TODO: Set edit permission based on user permissions
|
// TODO: Set edit permission based on user permissions
|
||||||
return (
|
return (
|
||||||
<NotesEditor
|
<NotesEditor
|
||||||
url={url(ApiPaths.part_list, part.pk)}
|
url={apiUrl(ApiPaths.part_list, part.pk)}
|
||||||
data={part.notes ?? ''}
|
data={part.notes ?? ''}
|
||||||
allowEdit={true}
|
allowEdit={true}
|
||||||
/>
|
/>
|
||||||
|
@ -18,7 +18,7 @@ import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
|
|||||||
import { AttachmentTable } from '../../components/tables/AttachmentTable';
|
import { AttachmentTable } from '../../components/tables/AttachmentTable';
|
||||||
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
import { NotesEditor } from '../../components/widgets/MarkdownEditor';
|
||||||
import { useInstance } from '../../hooks/UseInstance';
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
import { ApiPaths, url } from '../../states/ApiState';
|
import { ApiPaths, apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
export default function StockDetail() {
|
export default function StockDetail() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@ -87,7 +87,7 @@ export default function StockDetail() {
|
|||||||
icon: <IconNotes size="18" />,
|
icon: <IconNotes size="18" />,
|
||||||
content: (
|
content: (
|
||||||
<NotesEditor
|
<NotesEditor
|
||||||
url={url(ApiPaths.stock_item_list, stockitem.pk)}
|
url={apiUrl(ApiPaths.stock_item_list, stockitem.pk)}
|
||||||
data={stockitem.notes ?? ''}
|
data={stockitem.notes ?? ''}
|
||||||
allowEdit={true}
|
allowEdit={true}
|
||||||
/>
|
/>
|
||||||
|
@ -15,13 +15,17 @@ export const useServerApiState = create<ServerApiStateProps>((set, get) => ({
|
|||||||
setServer: (newServer: ServerAPIProps) => set({ server: newServer }),
|
setServer: (newServer: ServerAPIProps) => set({ server: newServer }),
|
||||||
fetchServerApiState: async () => {
|
fetchServerApiState: async () => {
|
||||||
// Fetch server data
|
// Fetch server data
|
||||||
await api.get('/').then((response) => {
|
await api.get(apiUrl(ApiPaths.api_server_info)).then((response) => {
|
||||||
set({ server: response.data });
|
set({ server: response.data });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export enum ApiPaths {
|
export enum ApiPaths {
|
||||||
|
api_server_info = 'api-server-info',
|
||||||
|
|
||||||
|
api_search = 'api-search',
|
||||||
|
|
||||||
// User information
|
// User information
|
||||||
user_me = 'api-user-me',
|
user_me = 'api-user-me',
|
||||||
user_roles = 'api-user-roles',
|
user_roles = 'api-user-roles',
|
||||||
@ -62,11 +66,21 @@ export enum ApiPaths {
|
|||||||
sales_order_list = 'api-sales-order-list'
|
sales_order_list = 'api-sales-order-list'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to return the API prefix.
|
||||||
|
* For now it is fixed, but may be configurable in the future.
|
||||||
|
*/
|
||||||
|
export function apiPrefix(): string {
|
||||||
|
return '/api/';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the endpoint associated with a given API path
|
* Return the endpoint associated with a given API path
|
||||||
*/
|
*/
|
||||||
export function endpoint(path: ApiPaths): string {
|
export function apiEndpoint(path: ApiPaths): string {
|
||||||
switch (path) {
|
switch (path) {
|
||||||
|
case ApiPaths.api_server_info:
|
||||||
|
return '';
|
||||||
case ApiPaths.user_me:
|
case ApiPaths.user_me:
|
||||||
return 'user/me/';
|
return 'user/me/';
|
||||||
case ApiPaths.user_roles:
|
case ApiPaths.user_roles:
|
||||||
@ -76,9 +90,13 @@ export function endpoint(path: ApiPaths): string {
|
|||||||
case ApiPaths.user_simple_login:
|
case ApiPaths.user_simple_login:
|
||||||
return 'email/generate/';
|
return 'email/generate/';
|
||||||
case ApiPaths.user_reset:
|
case ApiPaths.user_reset:
|
||||||
|
// Note leading prefix here
|
||||||
return '/auth/password/reset/';
|
return '/auth/password/reset/';
|
||||||
case ApiPaths.user_reset_set:
|
case ApiPaths.user_reset_set:
|
||||||
|
// Note leading prefix here
|
||||||
return '/auth/password/reset/confirm/';
|
return '/auth/password/reset/confirm/';
|
||||||
|
case ApiPaths.api_search:
|
||||||
|
return 'search/';
|
||||||
case ApiPaths.settings_global_list:
|
case ApiPaths.settings_global_list:
|
||||||
return 'settings/global/';
|
return 'settings/global/';
|
||||||
case ApiPaths.settings_user_list:
|
case ApiPaths.settings_user_list:
|
||||||
@ -122,8 +140,13 @@ export function endpoint(path: ApiPaths): string {
|
|||||||
/**
|
/**
|
||||||
* Construct an API URL with an endpoint and (optional) pk value
|
* Construct an API URL with an endpoint and (optional) pk value
|
||||||
*/
|
*/
|
||||||
export function url(path: ApiPaths, pk?: any): string {
|
export function apiUrl(path: ApiPaths, pk?: any): string {
|
||||||
let _url = endpoint(path);
|
let _url = apiEndpoint(path);
|
||||||
|
|
||||||
|
// If the URL does not start with a '/', add the API prefix
|
||||||
|
if (!_url.startsWith('/')) {
|
||||||
|
_url = apiPrefix() + _url;
|
||||||
|
}
|
||||||
|
|
||||||
if (_url && pk) {
|
if (_url && pk) {
|
||||||
_url += `${pk}/`;
|
_url += `${pk}/`;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ApiPaths, url } from './ApiState';
|
import { ApiPaths, apiUrl } from './ApiState';
|
||||||
import { Setting } from './states';
|
import { Setting } from './states';
|
||||||
|
|
||||||
interface SettingsStateProps {
|
interface SettingsStateProps {
|
||||||
@ -20,7 +20,7 @@ export const useGlobalSettingsState = create<SettingsStateProps>(
|
|||||||
settings: [],
|
settings: [],
|
||||||
fetchSettings: async () => {
|
fetchSettings: async () => {
|
||||||
await api
|
await api
|
||||||
.get(url(ApiPaths.settings_global_list))
|
.get(apiUrl(ApiPaths.settings_global_list))
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
set({ settings: response.data });
|
set({ settings: response.data });
|
||||||
})
|
})
|
||||||
@ -38,7 +38,7 @@ export const useUserSettingsState = create<SettingsStateProps>((set, get) => ({
|
|||||||
settings: [],
|
settings: [],
|
||||||
fetchSettings: async () => {
|
fetchSettings: async () => {
|
||||||
await api
|
await api
|
||||||
.get(url(ApiPaths.settings_user_list))
|
.get(apiUrl(ApiPaths.settings_user_list))
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
set({ settings: response.data });
|
set({ settings: response.data });
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { ApiPaths, url } from './ApiState';
|
import { ApiPaths, apiUrl } from './ApiState';
|
||||||
import { UserProps } from './states';
|
import { UserProps } from './states';
|
||||||
|
|
||||||
interface UserStateProps {
|
interface UserStateProps {
|
||||||
@ -19,7 +19,7 @@ export const useUserState = create<UserStateProps>((set, get) => ({
|
|||||||
fetchUserState: async () => {
|
fetchUserState: async () => {
|
||||||
// Fetch user data
|
// Fetch user data
|
||||||
await api
|
await api
|
||||||
.get(url(ApiPaths.user_me))
|
.get(apiUrl(ApiPaths.user_me))
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const user: UserProps = {
|
const user: UserProps = {
|
||||||
name: `${response.data.first_name} ${response.data.last_name}`,
|
name: `${response.data.first_name} ${response.data.last_name}`,
|
||||||
@ -34,7 +34,7 @@ export const useUserState = create<UserStateProps>((set, get) => ({
|
|||||||
|
|
||||||
// Fetch role data
|
// Fetch role data
|
||||||
await api
|
await api
|
||||||
.get(url(ApiPaths.user_roles))
|
.get(apiUrl(ApiPaths.user_roles))
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const user: UserProps = get().user as UserProps;
|
const user: UserProps = get().user as UserProps;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user