mirror of
https://github.com/inventree/InvenTree.git
synced 2026-07-06 07:00:39 +00:00
Merge branch 'master' into ci-add-zimor
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2138,7 +2138,7 @@ class StockItem(
|
||||
|
||||
self.add_tracking_entry(tracking_code, user, notes=notes, deltas=tracking_info)
|
||||
|
||||
self.save()
|
||||
self.save(add_note=False)
|
||||
|
||||
# Trigger event for the plugin system
|
||||
trigger_event(
|
||||
|
||||
@@ -297,9 +297,9 @@ distlib==0.3.9 \
|
||||
--hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \
|
||||
--hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403
|
||||
# via virtualenv
|
||||
django==4.2.16 \
|
||||
--hash=sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898 \
|
||||
--hash=sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad
|
||||
django==4.2.17 \
|
||||
--hash=sha256:3a93350214ba25f178d4045c0786c61573e7dbfa3c509b3551374f1e11ba8de0 \
|
||||
--hash=sha256:6b56d834cc94c8b21a8f4e775064896be3b4a4ca387f2612d4406a5927cd2fdc
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-admin-shell
|
||||
|
||||
@@ -401,9 +401,9 @@ diff-match-patch==20241021 \
|
||||
dj-rest-auth==7.0.0 \
|
||||
--hash=sha256:08dbc03a35223872da9f59bc2d7a71bec2e721aa69f7cdc84c7a329aeae1f86e
|
||||
# via -r src/backend/requirements.in
|
||||
django==4.2.16 \
|
||||
--hash=sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898 \
|
||||
--hash=sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad
|
||||
django==4.2.17 \
|
||||
--hash=sha256:3a93350214ba25f178d4045c0786c61573e7dbfa3c509b3551374f1e11ba8de0 \
|
||||
--hash=sha256:6b56d834cc94c8b21a8f4e775064896be3b4a4ca387f2612d4406a5927cd2fdc
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# dj-rest-auth
|
||||
|
||||
@@ -3,8 +3,8 @@ import { IconUserStar } from '@tabler/icons-react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import type { ModelType } from '../../enums/ModelType';
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
import { useServerApiState } from '../../states/ApiState';
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { ModelInformationDict } from '../render/ModelType';
|
||||
import { ActionButton } from './ActionButton';
|
||||
@@ -56,16 +56,14 @@ export default function AdminButton(props: Readonly<AdminButtonProps>) {
|
||||
const openAdmin = useCallback(
|
||||
(event: any) => {
|
||||
const modelDef = ModelInformationDict[props.model];
|
||||
const host = useLocalState.getState().host;
|
||||
|
||||
if (!modelDef.admin_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the URL for the admin interface
|
||||
const url = new URL(
|
||||
`${server.server.django_admin}${modelDef.admin_url}${props.id}/`,
|
||||
host
|
||||
const url = generateUrl(
|
||||
`${server.server.django_admin}${modelDef.admin_url}${props.id}/`
|
||||
);
|
||||
|
||||
if (event?.ctrlKey || event?.shiftKey) {
|
||||
|
||||
@@ -8,9 +8,9 @@ import { api } from '../../App';
|
||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import type { ModelType } from '../../enums/ModelType';
|
||||
import { extractAvailableFields } from '../../functions/forms';
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
import { useUserSettingsState } from '../../states/SettingsState';
|
||||
import type { ApiFormFieldSet } from '../forms/fields/ApiFormField';
|
||||
import { ActionDropdown } from '../items/ActionDropdown';
|
||||
@@ -28,8 +28,6 @@ export function PrintingActions({
|
||||
enableReports?: boolean;
|
||||
modelType?: ModelType;
|
||||
}) {
|
||||
const { host } = useLocalState.getState();
|
||||
|
||||
const userSettings = useUserSettingsState();
|
||||
|
||||
const enabled = useMemo(() => items.length > 0, [items]);
|
||||
@@ -116,7 +114,7 @@ export function PrintingActions({
|
||||
|
||||
if (response.output) {
|
||||
// An output file was generated
|
||||
const url = new URL(response.output, host);
|
||||
const url = generateUrl(response.output);
|
||||
window.open(url.toString(), '_blank');
|
||||
}
|
||||
}
|
||||
@@ -154,7 +152,7 @@ export function PrintingActions({
|
||||
|
||||
if (response.output) {
|
||||
// An output file was generated
|
||||
const url = new URL(response.output, host);
|
||||
const url = generateUrl(response.output);
|
||||
window.open(url.toString(), '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Image, type ImageProps, Skeleton, Stack } from '@mantine/core';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
|
||||
interface ApiImageProps extends ImageProps {
|
||||
@@ -19,7 +20,7 @@ export function ApiImage(props: Readonly<ApiImageProps>) {
|
||||
const { host } = useLocalState.getState();
|
||||
|
||||
const imageUrl = useMemo(() => {
|
||||
return new URL(props.src, host).toString();
|
||||
return generateUrl(props.src, host);
|
||||
}, [host, props.src]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
IconPhoto
|
||||
} from '@tabler/icons-react';
|
||||
import { type ReactNode, useMemo } from 'react';
|
||||
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
|
||||
/**
|
||||
* Return an icon based on the provided filename
|
||||
@@ -61,16 +60,13 @@ export function AttachmentLink({
|
||||
}>): ReactNode {
|
||||
const text = external ? attachment : attachment.split('/').pop();
|
||||
|
||||
const host = useLocalState((s) => s.host);
|
||||
|
||||
const url = useMemo(() => {
|
||||
if (external) {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
const u = new URL(attachment, host);
|
||||
return u.toString();
|
||||
}, [host, attachment, external]);
|
||||
return generateUrl(attachment);
|
||||
}, [attachment, external]);
|
||||
|
||||
return (
|
||||
<Group justify='left' gap='sm' wrap='nowrap'>
|
||||
|
||||
@@ -15,8 +15,8 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { api } from '../../App';
|
||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
import { apiUrl, useServerApiState } from '../../states/ApiState';
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { CopyButton } from '../buttons/CopyButton';
|
||||
import { StylishText } from '../items/StylishText';
|
||||
@@ -35,7 +35,6 @@ export function AboutInvenTreeModal({
|
||||
modalBody: string;
|
||||
}>) {
|
||||
const [user] = useUserState((state) => [state.user]);
|
||||
const { host } = useLocalState.getState();
|
||||
const [server] = useServerApiState((state) => [state.server]);
|
||||
|
||||
if (user?.is_staff != true)
|
||||
@@ -137,7 +136,7 @@ export function AboutInvenTreeModal({
|
||||
{
|
||||
ref: 'api',
|
||||
title: <Trans>API Version</Trans>,
|
||||
link: new URL('/api-doc/', host).toString(),
|
||||
link: generateUrl('/api-doc/'),
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useLocalState } from '../../states/LocalState';
|
||||
import { generateUrl } from '../../functions/urls';
|
||||
|
||||
/*
|
||||
* Load an external plugin source from a URL.
|
||||
*/
|
||||
export async function loadExternalPluginSource(source: string) {
|
||||
const host = useLocalState.getState().host;
|
||||
|
||||
source = source.trim();
|
||||
|
||||
// If no source is provided, clear the plugin content
|
||||
@@ -13,7 +11,7 @@ export async function loadExternalPluginSource(source: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = new URL(source, host).toString();
|
||||
const url = generateUrl(source);
|
||||
|
||||
const module = await import(/* @vite-ignore */ url)
|
||||
.catch((error) => {
|
||||
|
||||
@@ -126,6 +126,7 @@ const icons = {
|
||||
units: IconRulerMeasure,
|
||||
keywords: IconTag,
|
||||
status: IconInfoCircle,
|
||||
status_custom_key: IconInfoCircle,
|
||||
edit: IconEdit,
|
||||
info: IconInfoCircle,
|
||||
exclamation: IconExclamationCircle,
|
||||
@@ -291,6 +292,3 @@ export function InvenTreeIcon(props: Readonly<InvenTreeIconProps>) {
|
||||
|
||||
return <Icon {...props.iconProps} />;
|
||||
}
|
||||
function IconShapes(props: TablerIconProps): Element {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ModelInformationDict } from '../components/render/ModelType';
|
||||
import type { ModelType } from '../enums/ModelType';
|
||||
import { base_url } from '../main';
|
||||
import { useLocalState } from '../states/LocalState';
|
||||
|
||||
/**
|
||||
* Returns the detail view URL for a given model type
|
||||
@@ -30,3 +31,26 @@ export function getDetailUrl(
|
||||
console.error(`No detail URL found for model ${model} <${pk}>`);
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edit view URL for a given model type
|
||||
*/
|
||||
export function generateUrl(url: string | URL, base?: string): string {
|
||||
const { host } = useLocalState.getState();
|
||||
|
||||
let newUrl: string | URL = url;
|
||||
|
||||
try {
|
||||
if (base) {
|
||||
newUrl = new URL(url, base).toString();
|
||||
} else if (host) {
|
||||
newUrl = new URL(url, host).toString();
|
||||
} else {
|
||||
newUrl = url.toString();
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error(`ERR: generateURL failed. url='${url}', base='${base}'`);
|
||||
}
|
||||
|
||||
return newUrl.toString();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ import { PanelGroup } from '../components/panels/PanelGroup';
|
||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||
import { useTable } from '../hooks/UseTable';
|
||||
import { apiUrl } from '../states/ApiState';
|
||||
import { NotificationTable } from '../tables/notifications/NotificationsTable';
|
||||
import { NotificationTable } from '../tables/notifications/NotificationTable';
|
||||
|
||||
export default function NotificationsPage() {
|
||||
const unreadTable = useTable('unreadnotifications');
|
||||
|
||||
@@ -2,8 +2,8 @@ import { create } from 'zustand';
|
||||
|
||||
import { api } from '../App';
|
||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||
import { generateUrl } from '../functions/urls';
|
||||
import { apiUrl } from './ApiState';
|
||||
import { useLocalState } from './LocalState';
|
||||
|
||||
type IconPackage = {
|
||||
name: string;
|
||||
@@ -34,8 +34,6 @@ export const useIconState = create<IconState>()((set, get) => ({
|
||||
fetchIcons: async () => {
|
||||
if (get().hasLoaded) return;
|
||||
|
||||
const host = useLocalState.getState().host;
|
||||
|
||||
const packs = await api.get(apiUrl(ApiEndpoints.icons));
|
||||
|
||||
await Promise.all(
|
||||
@@ -43,8 +41,7 @@ export const useIconState = create<IconState>()((set, get) => ({
|
||||
const fontName = `inventree-icon-font-${pack.prefix}`;
|
||||
const src = Object.entries(pack.fonts as Record<string, string>)
|
||||
.map(
|
||||
([format, url]) =>
|
||||
`url(${new URL(url, host).toString()}) format("${format}")`
|
||||
([format, url]) => `url(${generateUrl(url)}) format("${format}")`
|
||||
)
|
||||
.join(',\n');
|
||||
const font = new FontFace(fontName, `${src};`);
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ export function NotificationTable({
|
||||
{
|
||||
accessor: 'age_human',
|
||||
title: t`Age`,
|
||||
sortable: true
|
||||
sortable: true,
|
||||
ordering: 'creation'
|
||||
},
|
||||
{
|
||||
accessor: 'category',
|
||||
Reference in New Issue
Block a user