mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'upstream/master' into barcode-generation
This commit is contained in:
commit
6dd2c6409a
3
.github/scripts/version_check.py
vendored
3
.github/scripts/version_check.py
vendored
@ -97,6 +97,9 @@ if __name__ == '__main__':
|
|||||||
)
|
)
|
||||||
text = version_file.read_text()
|
text = version_file.read_text()
|
||||||
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
|
results = re.findall(r"""INVENTREE_API_VERSION = (.*)""", text)
|
||||||
|
# If 2. args is true lower the version number by 1
|
||||||
|
if len(sys.argv) > 2 and sys.argv[2] == 'true':
|
||||||
|
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'
|
||||||
|
18
.github/workflows/qc_checks.yaml
vendored
18
.github/workflows/qc_checks.yaml
vendored
@ -164,15 +164,27 @@ jobs:
|
|||||||
name: schema.yml
|
name: schema.yml
|
||||||
path: src/backend/InvenTree/schema.yml
|
path: src/backend/InvenTree/schema.yml
|
||||||
- name: Download public schema
|
- name: Download public schema
|
||||||
if: needs.paths-filter.outputs.api == 'false'
|
|
||||||
run: |
|
run: |
|
||||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
|
pip install --require-hashes -r contrib/dev_reqs/requirements.txt >/dev/null 2>&1
|
||||||
version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
|
version="$(python3 .github/scripts/version_check.py only_version ${{ needs.paths-filter.outputs.api }} 2>&1)"
|
||||||
echo "Version: $version"
|
echo "Version: $version"
|
||||||
url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml"
|
url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml"
|
||||||
echo "URL: $url"
|
echo "URL: $url"
|
||||||
curl -s -o api.yaml $url
|
code=$(curl -s -o api.yaml $url --write-out '%{http_code}' --silent)
|
||||||
|
if [ "$code" != "200" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
echo "Downloaded api.yaml"
|
echo "Downloaded api.yaml"
|
||||||
|
- name: Running OpenAPI Spec diff action
|
||||||
|
id: breaking_changes
|
||||||
|
uses: oasdiff/oasdiff-action/diff@main
|
||||||
|
with:
|
||||||
|
base: 'api.yaml'
|
||||||
|
revision: 'src/backend/InvenTree/schema.yml'
|
||||||
|
format: 'html'
|
||||||
|
- name: Echoing diff to step
|
||||||
|
run: echo "${{ steps.breaking_changes.outputs.diff }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
- name: Check for differences in API Schema
|
- name: Check for differences in API Schema
|
||||||
if: needs.paths-filter.outputs.api == 'false'
|
if: needs.paths-filter.outputs.api == 'false'
|
||||||
run: |
|
run: |
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""API for the plugin app."""
|
"""API for the plugin app."""
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -266,7 +268,9 @@ class PluginSettingList(ListAPI):
|
|||||||
filterset_fields = ['plugin__active', 'plugin__key']
|
filterset_fields = ['plugin__active', 'plugin__key']
|
||||||
|
|
||||||
|
|
||||||
def check_plugin(plugin_slug: str, plugin_pk: int) -> InvenTreePlugin:
|
def check_plugin(
|
||||||
|
plugin_slug: Optional[str], plugin_pk: Optional[int]
|
||||||
|
) -> InvenTreePlugin:
|
||||||
"""Check that a plugin for the provided slug exists and get the config.
|
"""Check that a plugin for the provided slug exists and get the config.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -286,16 +290,16 @@ def check_plugin(plugin_slug: str, plugin_pk: int) -> InvenTreePlugin:
|
|||||||
raise NotFound(detail='Plugin not specified')
|
raise NotFound(detail='Plugin not specified')
|
||||||
|
|
||||||
# Define filter
|
# Define filter
|
||||||
filter = {}
|
filters = {}
|
||||||
if plugin_slug:
|
if plugin_slug:
|
||||||
filter['key'] = plugin_slug
|
filters['key'] = plugin_slug
|
||||||
elif plugin_pk:
|
elif plugin_pk:
|
||||||
filter['pk'] = plugin_pk
|
filters['pk'] = plugin_pk
|
||||||
ref = plugin_slug or plugin_pk
|
ref = plugin_slug or plugin_pk
|
||||||
|
|
||||||
# Check that the 'plugin' specified is valid
|
# Check that the 'plugin' specified is valid
|
||||||
try:
|
try:
|
||||||
plugin_cgf = PluginConfig.objects.filter(**filter).first()
|
plugin_cgf = PluginConfig.objects.filter(**filters).first()
|
||||||
except PluginConfig.DoesNotExist:
|
except PluginConfig.DoesNotExist:
|
||||||
raise NotFound(detail=f"Plugin '{ref}' not installed")
|
raise NotFound(detail=f"Plugin '{ref}' not installed")
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ def barcode(data, barcode_class='code128', **kwargs):
|
|||||||
"""Render a barcode."""
|
"""Render a barcode."""
|
||||||
constructor = python_barcode.get_barcode_class(barcode_class)
|
constructor = python_barcode.get_barcode_class(barcode_class)
|
||||||
|
|
||||||
format = kwargs.pop('format', 'PNG')
|
img_format = kwargs.pop('format', 'PNG')
|
||||||
|
|
||||||
data = str(data).zfill(constructor.digits)
|
data = str(data).zfill(constructor.digits)
|
||||||
|
|
||||||
@ -86,4 +86,4 @@ def barcode(data, barcode_class='code128', **kwargs):
|
|||||||
image = barcode_image.render(writer_options=kwargs)
|
image = barcode_image.render(writer_options=kwargs)
|
||||||
|
|
||||||
# Render to byte-encoded image
|
# Render to byte-encoded image
|
||||||
return image_data(image, fmt=format)
|
return image_data(image, fmt=img_format)
|
||||||
|
@ -173,7 +173,7 @@ function generateTreeStructure(data, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (options.processNode) {
|
if (options.processNode) {
|
||||||
node = options.processNode(node);
|
data[data.indexOf(node)] = options.processNode(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ function generateTreeStructure(data, options) {
|
|||||||
if (node.state.expanded) {
|
if (node.state.expanded) {
|
||||||
while (node.parent != null) {
|
while (node.parent != null) {
|
||||||
nodes[node.parent].state.expanded = true;
|
nodes[node.parent].state.expanded = true;
|
||||||
node = nodes[node.parent];
|
data[data.indexOf(node)] = nodes[node.parent];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,9 @@ export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
|||||||
<Trans>Preview not available, click "Reload Preview".</Trans>
|
<Trans>Preview not available, click "Reload Preview".</Trans>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{pdfUrl && <iframe src={pdfUrl} width="100%" height="100%" />}
|
{pdfUrl && (
|
||||||
|
<iframe src={pdfUrl} width="100%" height="100%" title="PDF Preview" />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ export function usePartFields({
|
|||||||
/**
|
/**
|
||||||
* Construct a set of fields for creating / editing a PartCategory instance
|
* Construct a set of fields for creating / editing a PartCategory instance
|
||||||
*/
|
*/
|
||||||
export function partCategoryFields({}: {}): ApiFormFieldSet {
|
export function partCategoryFields(): ApiFormFieldSet {
|
||||||
let fields: ApiFormFieldSet = {
|
let fields: ApiFormFieldSet = {
|
||||||
parent: {
|
parent: {
|
||||||
description: t`Parent part category`,
|
description: t`Parent part category`,
|
||||||
|
@ -902,7 +902,7 @@ export function useDeleteStockItem(props: StockOperationProps) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stockLocationFields({}: {}): ApiFormFieldSet {
|
export function stockLocationFields(): ApiFormFieldSet {
|
||||||
let fields: ApiFormFieldSet = {
|
let fields: ApiFormFieldSet = {
|
||||||
parent: {
|
parent: {
|
||||||
description: t`Parent stock location`,
|
description: t`Parent stock location`,
|
||||||
|
@ -5,7 +5,7 @@ import { NavigateFunction } from 'react-router-dom';
|
|||||||
|
|
||||||
import { api, setApiDefaults } from '../App';
|
import { api, setApiDefaults } from '../App';
|
||||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||||
import { apiUrl, useServerApiState } from '../states/ApiState';
|
import { apiUrl } from '../states/ApiState';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useUserState } from '../states/UserState';
|
import { useUserState } from '../states/UserState';
|
||||||
import { fetchGlobalStates } from '../states/states';
|
import { fetchGlobalStates } from '../states/states';
|
||||||
@ -47,8 +47,7 @@ function post(path: string, params: any, method = 'post') {
|
|||||||
*/
|
*/
|
||||||
export const doBasicLogin = async (username: string, password: string) => {
|
export const doBasicLogin = async (username: string, password: string) => {
|
||||||
const { host } = useLocalState.getState();
|
const { host } = useLocalState.getState();
|
||||||
const { clearUserState, setToken, fetchUserState, isLoggedIn } =
|
const { clearUserState, setToken, fetchUserState } = useUserState.getState();
|
||||||
useUserState.getState();
|
|
||||||
|
|
||||||
if (username.length == 0 || password.length == 0) {
|
if (username.length == 0 || password.length == 0) {
|
||||||
return;
|
return;
|
||||||
@ -96,7 +95,7 @@ export const doBasicLogin = async (username: string, password: string) => {
|
|||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
await fetchUserState();
|
await fetchUserState();
|
||||||
await fetchGlobalStates();
|
fetchGlobalStates();
|
||||||
} else {
|
} else {
|
||||||
clearUserState();
|
clearUserState();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
|
|
||||||
// Generate some example forms using the modal API forms interface
|
// Generate some example forms using the modal API forms interface
|
||||||
const fields = partCategoryFields({});
|
const fields = partCategoryFields();
|
||||||
|
|
||||||
function ApiFormsPlayground() {
|
function ApiFormsPlayground() {
|
||||||
const editCategory = useEditApiFormModal({
|
const editCategory = useEditApiFormModal({
|
||||||
|
@ -89,7 +89,7 @@ export function SecurityContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function EmailContent({}: {}) {
|
function EmailContent() {
|
||||||
const [value, setValue] = useState<string>('');
|
const [value, setValue] = useState<string>('');
|
||||||
const [newEmailValue, setNewEmailValue] = useState('');
|
const [newEmailValue, setNewEmailValue] = useState('');
|
||||||
const [user] = useUserState((state) => [state.user]);
|
const [user] = useUserState((state) => [state.user]);
|
||||||
@ -321,7 +321,7 @@ function SsoContent({ dataProvider }: { dataProvider: any | undefined }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MfaContent({}: {}) {
|
function MfaContent() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
MFA Details
|
MFA Details
|
||||||
|
@ -42,7 +42,7 @@ import { PartListTable } from '../../tables/part/PartTable';
|
|||||||
*
|
*
|
||||||
* Note: If no category ID is supplied, this acts as the top-level part category page
|
* Note: If no category ID is supplied, this acts as the top-level part category page
|
||||||
*/
|
*/
|
||||||
export default function CategoryDetail({}: {}) {
|
export default function CategoryDetail() {
|
||||||
const { id: _id } = useParams();
|
const { id: _id } = useParams();
|
||||||
const id = useMemo(
|
const id = useMemo(
|
||||||
() => (!isNaN(parseInt(_id || '')) ? _id : undefined),
|
() => (!isNaN(parseInt(_id || '')) ? _id : undefined),
|
||||||
@ -158,7 +158,7 @@ export default function CategoryDetail({}: {}) {
|
|||||||
url: ApiEndpoints.category_list,
|
url: ApiEndpoints.category_list,
|
||||||
pk: id,
|
pk: id,
|
||||||
title: t`Edit Part Category`,
|
title: t`Edit Part Category`,
|
||||||
fields: partCategoryFields({}),
|
fields: partCategoryFields(),
|
||||||
onFormSuccess: refreshInstance
|
onFormSuccess: refreshInstance
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,10 +21,9 @@ function AccordionControl(props: AccordionControlProps) {
|
|||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
<Box style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
{props.disabled && (
|
{props.disabled && (
|
||||||
<Tooltip
|
<Tooltip label={t`No data available`}>
|
||||||
label={t`No data available`}
|
<IconAlertCircle size="1rem" color="gray" />
|
||||||
children={<IconAlertCircle size="1rem" color="gray" />}
|
</Tooltip>
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<Accordion.Control
|
<Accordion.Control
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -210,7 +210,7 @@ export default function Stock() {
|
|||||||
url: ApiEndpoints.stock_location_list,
|
url: ApiEndpoints.stock_location_list,
|
||||||
pk: id,
|
pk: id,
|
||||||
title: t`Edit Stock Location`,
|
title: t`Edit Stock Location`,
|
||||||
fields: stockLocationFields({}),
|
fields: stockLocationFields(),
|
||||||
onFormSuccess: refreshInstance
|
onFormSuccess: refreshInstance
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@ export function InvenTreeTable<T = any>({
|
|||||||
enableLabels={tableProps.enableLabels}
|
enableLabels={tableProps.enableLabels}
|
||||||
enableReports={tableProps.enableReports}
|
enableReports={tableProps.enableReports}
|
||||||
/>
|
/>
|
||||||
{(tableProps.barcodeActions?.length ?? 0 > 0) && (
|
{(tableProps.barcodeActions?.length ?? 0) > 0 && (
|
||||||
<ButtonMenu
|
<ButtonMenu
|
||||||
key="barcode-actions"
|
key="barcode-actions"
|
||||||
icon={<IconBarcode />}
|
icon={<IconBarcode />}
|
||||||
|
@ -76,7 +76,7 @@ export function PartCategoryTable({ parentId }: { parentId?: any }) {
|
|||||||
const newCategory = useCreateApiFormModal({
|
const newCategory = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.category_list,
|
url: ApiEndpoints.category_list,
|
||||||
title: t`New Part Category`,
|
title: t`New Part Category`,
|
||||||
fields: partCategoryFields({}),
|
fields: partCategoryFields(),
|
||||||
initialData: {
|
initialData: {
|
||||||
parent: parentId
|
parent: parentId
|
||||||
},
|
},
|
||||||
@ -91,7 +91,7 @@ export function PartCategoryTable({ parentId }: { parentId?: any }) {
|
|||||||
url: ApiEndpoints.category_list,
|
url: ApiEndpoints.category_list,
|
||||||
pk: selectedCategory,
|
pk: selectedCategory,
|
||||||
title: t`Edit Part Category`,
|
title: t`Edit Part Category`,
|
||||||
fields: partCategoryFields({}),
|
fields: partCategoryFields(),
|
||||||
onFormSuccess: (record: any) => table.updateRecord(record)
|
onFormSuccess: (record: any) => table.updateRecord(record)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import { TableFilter } from '../Filter';
|
|||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { RowDeleteAction, RowEditAction } from '../RowActions';
|
import { RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
|
|
||||||
export default function PartCategoryTemplateTable({}: {}) {
|
export default function PartCategoryTemplateTable() {
|
||||||
const table = useTable('part-category-parameter-templates');
|
const table = useTable('part-category-parameter-templates');
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ export function StockLocationTable({ parentId }: { parentId?: any }) {
|
|||||||
const newLocation = useCreateApiFormModal({
|
const newLocation = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.stock_location_list,
|
url: ApiEndpoints.stock_location_list,
|
||||||
title: t`Add Stock Location`,
|
title: t`Add Stock Location`,
|
||||||
fields: stockLocationFields({}),
|
fields: stockLocationFields(),
|
||||||
initialData: {
|
initialData: {
|
||||||
parent: parentId
|
parent: parentId
|
||||||
},
|
},
|
||||||
@ -112,7 +112,7 @@ export function StockLocationTable({ parentId }: { parentId?: any }) {
|
|||||||
url: ApiEndpoints.stock_location_list,
|
url: ApiEndpoints.stock_location_list,
|
||||||
pk: selectedLocation,
|
pk: selectedLocation,
|
||||||
title: t`Edit Stock Location`,
|
title: t`Edit Stock Location`,
|
||||||
fields: stockLocationFields({}),
|
fields: stockLocationFields(),
|
||||||
onFormSuccess: (record: any) => table.updateRecord(record)
|
onFormSuccess: (record: any) => table.updateRecord(record)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user