Merge branch 'master' into optimize_test_statistic_queries

This commit is contained in:
Miklós Márton 2024-08-02 13:41:27 +02:00 committed by GitHub
commit 1a09ef08a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
92 changed files with 37272 additions and 32948 deletions

View File

@ -18,6 +18,9 @@ from pathlib import Path
import requests import requests
REPO = os.getenv('GITHUB_REPOSITORY', 'inventree/inventree')
GITHUB_API_URL = os.getenv('GITHUB_API_URL', 'https://api.github.com')
def get_existing_release_tags(): def get_existing_release_tags():
"""Request information on existing releases via the GitHub API.""" """Request information on existing releases via the GitHub API."""
@ -28,9 +31,7 @@ def get_existing_release_tags():
if token: if token:
headers = {'Authorization': f'Bearer {token}'} headers = {'Authorization': f'Bearer {token}'}
response = requests.get( response = requests.get(f'{GITHUB_API_URL}/repos/{REPO}/releases', headers=headers)
'https://api.github.com/repos/inventree/inventree/releases', headers=headers
)
if response.status_code != 200: if response.status_code != 200:
raise ValueError( raise ValueError(
@ -90,6 +91,11 @@ def check_version_number(version_string, allow_duplicate=False):
if __name__ == '__main__': if __name__ == '__main__':
# Ensure that we are running in GH Actions
if os.environ.get('GITHUB_ACTIONS', '') != 'true':
print('This script is intended to be run within a GitHub Action!')
sys.exit(1)
if 'only_version' in sys.argv: if 'only_version' in sys.argv:
here = Path(__file__).parent.absolute() here = Path(__file__).parent.absolute()
version_file = here.joinpath( version_file = here.joinpath(
@ -102,14 +108,13 @@ if __name__ == '__main__':
results[0] = str(int(results[0]) - 1) results[0] = str(int(results[0]) - 1)
print(results[0]) print(results[0])
exit(0) exit(0)
# GITHUB_REF_TYPE may be either 'branch' or 'tag' # GITHUB_REF_TYPE may be either 'branch' or 'tag'
GITHUB_REF_TYPE = os.environ['GITHUB_REF_TYPE'] GITHUB_REF_TYPE = os.environ['GITHUB_REF_TYPE']
# GITHUB_REF may be either 'refs/heads/<branch>' or 'refs/heads/<tag>' # GITHUB_REF may be either 'refs/heads/<branch>' or 'refs/heads/<tag>'
GITHUB_REF = os.environ['GITHUB_REF'] GITHUB_REF = os.environ['GITHUB_REF']
GITHUB_REF_NAME = os.environ['GITHUB_REF_NAME'] GITHUB_REF_NAME = os.environ['GITHUB_REF_NAME']
GITHUB_BASE_REF = os.environ['GITHUB_BASE_REF'] GITHUB_BASE_REF = os.environ['GITHUB_BASE_REF']
# Print out version information, makes debugging actions *much* easier! # Print out version information, makes debugging actions *much* easier!
@ -193,7 +198,7 @@ if __name__ == '__main__':
# Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/ # Ref: https://getridbug.com/python/how-to-set-environment-variables-in-github-actions-using-python/
with open(os.getenv('GITHUB_ENV'), 'a') as env_file: with open(os.getenv('GITHUB_ENV'), 'a') as env_file:
# Construct tag string # Construct tag string
tags = ','.join([f'inventree/inventree:{tag}' for tag in docker_tags]) tags = ','.join([f'{REPO}:{tag}' for tag in docker_tags])
env_file.write(f'docker_tags={tags}\n') env_file.write(f'docker_tags={tags}\n')

View File

@ -118,7 +118,7 @@ def check_daily_holdoff(task_name: str, n_days: int = 1) -> bool:
if last_success: if last_success:
threshold = datetime.now() - timedelta(days=n_days) threshold = datetime.now() - timedelta(days=n_days)
if last_success > threshold: if last_success.date() > threshold.date():
logger.info( logger.info(
"Last successful run for '%s' was too recent - skipping task", task_name "Last successful run for '%s' was too recent - skipping task", task_name
) )

View File

@ -5,6 +5,8 @@ from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import mptt.fields import mptt.fields
from build.status_codes import BuildStatus
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -40,7 +42,7 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='build', model_name='build',
name='status', name='status',
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'Production'), (30, 'Cancelled'), (40, 'Complete')], default=10, help_text='Build status code', validators=[django.core.validators.MinValueValidator(0)], verbose_name='Build Status'), field=models.PositiveIntegerField(choices=BuildStatus.items(), default=BuildStatus.PENDING.value, help_text='Build status code', validators=[django.core.validators.MinValueValidator(0)], verbose_name='Build Status'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='build', model_name='build',

View File

@ -9,7 +9,7 @@ class BuildStatus(StatusCode):
"""Build status codes.""" """Build status codes."""
PENDING = 10, _('Pending'), 'secondary' # Build is pending / active PENDING = 10, _('Pending'), 'secondary' # Build is pending / active
PRODUCTION = 20, _('Production'), 'primary' # BuildOrder is in production PRODUCTION = 20, _('Production'), 'primary' # Build is in production
CANCELLED = 30, _('Cancelled'), 'danger' # Build was cancelled CANCELLED = 30, _('Cancelled'), 'danger' # Build was cancelled
COMPLETE = 40, _('Complete'), 'success' # Build is complete COMPLETE = 40, _('Complete'), 'success' # Build is complete
@ -17,4 +17,7 @@ class BuildStatus(StatusCode):
class BuildStatusGroups: class BuildStatusGroups:
"""Groups for BuildStatus codes.""" """Groups for BuildStatus codes."""
ACTIVE_CODES = [BuildStatus.PENDING.value, BuildStatus.PRODUCTION.value] ACTIVE_CODES = [
BuildStatus.PENDING.value,
BuildStatus.PRODUCTION.value,
]

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

@ -5,6 +5,8 @@ import django.core.validators
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from order.status_codes import PurchaseOrderStatus
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -17,7 +19,12 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='purchaseorder', model_name='purchaseorder',
name='status', name='status',
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'Placed'), (30, 'Complete'), (40, 'Cancelled'), (50, 'Lost'), (60, 'Returned')], default=10, help_text='Purchase order status'), field=models.PositiveIntegerField(
choices=PurchaseOrderStatus.items(),
default=PurchaseOrderStatus.PENDING.value,
help_text='Purchase order status',
verbose_name='Status',
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='salesorder', model_name='salesorder',

View File

@ -2,6 +2,8 @@
from django.db import migrations, models from django.db import migrations, models
from order.status_codes import ReturnOrderStatus
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -23,7 +25,11 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='returnorder', model_name='returnorder',
name='status', name='status',
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'In Progress'), (30, 'Complete'), (40, 'Cancelled')], default=10, help_text='Return order status', verbose_name='Status'), field=models.PositiveIntegerField(
choices=ReturnOrderStatus.items(),
default=ReturnOrderStatus.PENDING.value,
help_text='Return order status', verbose_name='Status'
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='salesorder', model_name='salesorder',

View File

@ -2,6 +2,8 @@
from django.db import migrations, models from django.db import migrations, models
from order.status_codes import SalesOrderStatus
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -13,6 +15,10 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='salesorder', model_name='salesorder',
name='status', name='status',
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (15, 'In Progress'), (20, 'Shipped'), (40, 'Cancelled'), (50, 'Lost'), (60, 'Returned')], default=10, help_text='Purchase order status', verbose_name='Status'), field=models.PositiveIntegerField(
choices=SalesOrderStatus.items(),
default=SalesOrderStatus.PENDING.value,
help_text='Sales order status', verbose_name='Status'
),
), ),
] ]

View File

@ -15,6 +15,10 @@ class Migration(migrations.Migration):
migrations.AlterField( migrations.AlterField(
model_name='salesorder', model_name='salesorder',
name='status', name='status',
field=models.PositiveIntegerField(choices=order.status_codes.SalesOrderStatus.items(), default=10, help_text='Purchase order status', verbose_name='Status'), field=models.PositiveIntegerField(
choices=order.status_codes.SalesOrderStatus.items(),
default=order.status_codes.SalesOrderStatus.PENDING.value,
help_text='Sales order status', verbose_name='Status'
),
), ),
] ]

View File

@ -474,6 +474,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
status = models.PositiveIntegerField( status = models.PositiveIntegerField(
default=PurchaseOrderStatus.PENDING.value, default=PurchaseOrderStatus.PENDING.value,
choices=PurchaseOrderStatus.items(), choices=PurchaseOrderStatus.items(),
verbose_name=_('Status'),
help_text=_('Purchase order status'), help_text=_('Purchase order status'),
) )
@ -967,7 +968,7 @@ class SalesOrder(TotalPriceMixin, Order):
default=SalesOrderStatus.PENDING.value, default=SalesOrderStatus.PENDING.value,
choices=SalesOrderStatus.items(), choices=SalesOrderStatus.items(),
verbose_name=_('Status'), verbose_name=_('Status'),
help_text=_('Purchase order status'), help_text=_('Sales order status'),
) )
@property @property

View File

@ -43,7 +43,6 @@ from InvenTree.mixins import (
from InvenTree.permissions import RolePermission from InvenTree.permissions import RolePermission
from InvenTree.serializers import EmptySerializer from InvenTree.serializers import EmptySerializer
from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
from part.admin import PartCategoryResource, PartResource
from stock.models import StockLocation from stock.models import StockLocation
from . import serializers as part_serializers from . import serializers as part_serializers
@ -245,7 +244,7 @@ class CategoryList(CategoryMixin, DataExportViewMixin, ListCreateAPI):
# Use hierarchical ordering by default # Use hierarchical ordering by default
ordering = ['tree_id', 'lft', 'name'] ordering = ['tree_id', 'lft', 'name']
search_fields = ['name', 'description'] search_fields = ['name', 'description', 'pathstring']
class CategoryDetail(CategoryMixin, CustomRetrieveUpdateDestroyAPI): class CategoryDetail(CategoryMixin, CustomRetrieveUpdateDestroyAPI):

View File

@ -418,7 +418,7 @@ class StockLocationList(DataExportViewMixin, ListCreateAPI):
filter_backends = SEARCH_ORDER_FILTER filter_backends = SEARCH_ORDER_FILTER
search_fields = ['name', 'description', 'tags__name', 'tags__slug'] search_fields = ['name', 'description', 'pathstring', 'tags__name', 'tags__slug']
ordering_fields = ['name', 'pathstring', 'items', 'level', 'tree_id', 'lft'] ordering_fields = ['name', 'pathstring', 'items', 'level', 'tree_id', 'lft']

View File

@ -236,25 +236,23 @@ export function RelatedModelField({
// Field doesn't follow Mantine theming // Field doesn't follow Mantine theming
// Define color theme to pass to field based on Mantine theme // Define color theme to pass to field based on Mantine theme
const theme = useMantineTheme(); const theme = useMantineTheme();
const colorschema = vars.colors.primaryColors;
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const colors = useMemo(() => { const colors = useMemo(() => {
let colors: any; let colors: any;
if (colorScheme === 'dark') { if (colorScheme === 'dark') {
colors = { colors = {
neutral0: colorschema[6], neutral0: vars.colors.dark[6],
neutral5: colorschema[4], neutral5: vars.colors.dark[4],
neutral10: colorschema[4], neutral10: vars.colors.dark[4],
neutral20: colorschema[4], neutral20: vars.colors.dark[4],
neutral30: colorschema[3], neutral30: vars.colors.dark[3],
neutral40: colorschema[2], neutral40: vars.colors.dark[2],
neutral50: colorschema[1], neutral50: vars.colors.dark[1],
neutral60: colorschema[0], neutral60: vars.colors.dark[0],
neutral70: colorschema[0], neutral70: vars.colors.dark[0],
neutral80: colorschema[0], neutral80: vars.colors.dark[0],
neutral90: colorschema[0], neutral90: vars.colors.dark[0],
primary: vars.colors.primaryColors[7], primary: vars.colors.primaryColors[7],
primary25: vars.colors.primaryColors[6], primary25: vars.colors.primaryColors[6],
primary50: vars.colors.primaryColors[5], primary50: vars.colors.primaryColors[5],

View File

@ -157,7 +157,8 @@ export function RenderInlineModel({
labels, labels,
url, url,
navigate, navigate,
showSecondary = true showSecondary = true,
tooltip
}: { }: {
primary: string; primary: string;
secondary?: string; secondary?: string;
@ -168,6 +169,7 @@ export function RenderInlineModel({
labels?: string[]; labels?: string[];
url?: string; url?: string;
navigate?: any; navigate?: any;
tooltip?: string;
}): ReactNode { }): ReactNode {
// TODO: Handle labels // TODO: Handle labels
@ -181,7 +183,7 @@ export function RenderInlineModel({
); );
return ( return (
<Group gap="xs" justify="space-between" wrap="nowrap"> <Group gap="xs" justify="space-between" wrap="nowrap" title={tooltip}>
<Group gap="xs" justify="left" wrap="nowrap"> <Group gap="xs" justify="left" wrap="nowrap">
{prefix} {prefix}
{image && <Thumbnail src={image} size={18} />} {image && <Thumbnail src={image} size={18} />}

View File

@ -56,13 +56,18 @@ export function RenderPartCategory(
props: Readonly<InstanceRenderInterface> props: Readonly<InstanceRenderInterface>
): ReactNode { ): ReactNode {
const { instance } = props; const { instance } = props;
const lvl = '-'.repeat(instance.level || 0);
return ( return (
<RenderInlineModel <RenderInlineModel
{...props} {...props}
prefix={instance.icon && <ApiIcon name={instance.icon} />} tooltip={instance.pathstring}
primary={`${lvl} ${instance.name}`} prefix={
<>
<div style={{ width: 10 * (instance.level || 0) }}></div>
{instance.icon && <ApiIcon name={instance.icon} />}
</>
}
primary={instance.name}
secondary={instance.description} secondary={instance.description}
url={ url={
props.link props.link

View File

@ -17,7 +17,13 @@ export function RenderStockLocation(
return ( return (
<RenderInlineModel <RenderInlineModel
{...props} {...props}
prefix={instance.icon && <ApiIcon name={instance.icon} />} tooltip={instance.pathstring}
prefix={
<>
<div style={{ width: 10 * (instance.level || 0) }}></div>
{instance.icon && <ApiIcon name={instance.icon} />}
</>
}
primary={instance.name} primary={instance.name}
secondary={instance.description} secondary={instance.description}
url={ url={

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

File diff suppressed because it is too large Load Diff