Merge branch 'master' into ci-add-zimor

This commit is contained in:
Matthias Mair 2024-12-09 19:12:00 +01:00 committed by GitHub
commit 440a111375
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
92 changed files with 29459 additions and 27967 deletions

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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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');
}
}

View File

@ -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 (

View File

@ -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'>

View File

@ -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
},
{

View File

@ -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) => {

View File

@ -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.');
}

View File

@ -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

View File

@ -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');

View File

@ -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};`);

View File

@ -24,7 +24,8 @@ export function NotificationTable({
{
accessor: 'age_human',
title: t`Age`,
sortable: true
sortable: true,
ordering: 'creation'
},
{
accessor: 'category',