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