mirror of
https://github.com/inventree/InvenTree.git
synced 2026-11-14 12:32:44 +00:00
Merge commit '3309032b261e891944db5270a305a3ecf9f926ce' into block-notes
This commit is contained in:
commit
d98a57fbe9
97 files changed
+124493
-118422
No files matched your search
@@ -70,6 +70,11 @@ export type TableState = {
|
||||
idAccessor?: string;
|
||||
};
|
||||
|
||||
export type TableColumnFilterType =
|
||||
| string
|
||||
| string[]
|
||||
| (({ close }: { close: () => void }) => ReactNode);
|
||||
|
||||
/**
|
||||
* Table column properties
|
||||
*
|
||||
@@ -109,10 +114,7 @@ export type TableColumnProps<T = any> = {
|
||||
editable?: boolean;
|
||||
definition?: ApiFormFieldType;
|
||||
render?: (record: T, index?: number) => any;
|
||||
filter?:
|
||||
| string
|
||||
| string[]
|
||||
| (({ close }: { close: () => void }) => ReactNode);
|
||||
filter?: TableColumnFilterType;
|
||||
filtering?: boolean;
|
||||
width?: number;
|
||||
minWidth?: string | number;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { t } from '@lingui/core/macro';
|
||||
import type { SpotlightActionData } from '@mantine/spotlight';
|
||||
import {
|
||||
IconBarcode,
|
||||
IconDevicesPc,
|
||||
IconLink,
|
||||
IconPlug,
|
||||
IconPointer,
|
||||
@@ -9,7 +10,8 @@ import {
|
||||
IconSettings,
|
||||
IconTags,
|
||||
IconUserBolt,
|
||||
IconUserCog
|
||||
IconUserCog,
|
||||
IconUsers
|
||||
} from '@tabler/icons-react';
|
||||
import type { NavigateFunction } from 'react-router-dom';
|
||||
|
||||
@@ -213,6 +215,16 @@ export function getActions(navigate: NavigateFunction) {
|
||||
leftSection: <IconReport size='1.2rem' />
|
||||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.user) &&
|
||||
_actions.push({
|
||||
id: 'users',
|
||||
label: t`Users`,
|
||||
description: t`Manage user accounts`,
|
||||
onClick: () => navigate('/settings/admin/user'),
|
||||
leftSection: <IconUsers size='1.2rem' />
|
||||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.pluginconfig) &&
|
||||
_actions.push({
|
||||
@@ -223,6 +235,16 @@ export function getActions(navigate: NavigateFunction) {
|
||||
leftSection: <IconPlug size='1.2rem' />
|
||||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.pluginconfig) &&
|
||||
_actions.push({
|
||||
id: 'machine-management',
|
||||
label: t`Machines`,
|
||||
description: t`Manage machines and machine types`,
|
||||
onClick: () => navigate('/settings/admin/machine'),
|
||||
leftSection: <IconDevicesPc size='1.2rem' />
|
||||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.reporttemplate) &&
|
||||
_actions.push({
|
||||
|
||||
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1860
-1737
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1857
-1734
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1857
-1734
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1855
-1732
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1858
-1735
File diff suppressed because it is too large.
Load diff
+1858
-1735
File diff suppressed because it is too large.
Load diff
+1853
-1730
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1852
-1729
File diff suppressed because it is too large.
Load diff
+1851
-1728
File diff suppressed because it is too large.
Load diff
+1856
-1733
File diff suppressed because it is too large.
Load diff
+1854
-1731
File diff suppressed because it is too large.
Load diff
+1856
-1733
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
@@ -10,8 +10,12 @@ function LabelTemplateTable() {
|
||||
templateEndpoint: ApiEndpoints.label_list,
|
||||
printingEndpoint: ApiEndpoints.label_print,
|
||||
additionalFormFields: {
|
||||
width: {},
|
||||
height: {}
|
||||
width: {
|
||||
sortable: true
|
||||
},
|
||||
height: {
|
||||
sortable: true
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -17,24 +17,44 @@ function ReportTemplateTable() {
|
||||
modelType: ModelType.reporttemplate,
|
||||
templateEndpoint: ApiEndpoints.report_list,
|
||||
printingEndpoint: ApiEndpoints.report_print,
|
||||
additionalFilters: [
|
||||
{
|
||||
name: 'landscape',
|
||||
label: t`Landscape`,
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'merge',
|
||||
label: t`Merge`,
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'attach_to_model',
|
||||
label: t`Attach to Model`,
|
||||
type: 'boolean'
|
||||
}
|
||||
],
|
||||
additionalFormFields: {
|
||||
page_size: {
|
||||
label: t`Page Size`
|
||||
},
|
||||
landscape: {
|
||||
label: t`Landscape`,
|
||||
filter: 'landscape',
|
||||
modelRenderer: (instance: any) => (
|
||||
<YesNoButton value={instance.landscape} />
|
||||
)
|
||||
},
|
||||
merge: {
|
||||
label: t`Merge`,
|
||||
filter: 'merge',
|
||||
modelRenderer: (instance: any) => (
|
||||
<YesNoButton value={instance.merge} />
|
||||
)
|
||||
},
|
||||
attach_to_model: {
|
||||
label: t`Attach to Model`,
|
||||
filter: 'attach_to_model',
|
||||
modelRenderer: (instance: any) => (
|
||||
<YesNoButton value={instance.attach_to_model} />
|
||||
)
|
||||
|
||||
@@ -374,11 +374,13 @@ export function ProjectCodeFilter(): TableFilter {
|
||||
export function OwnerFilter({
|
||||
name,
|
||||
label,
|
||||
description
|
||||
description,
|
||||
apiFilter
|
||||
}: {
|
||||
name: string;
|
||||
label: string;
|
||||
description: string;
|
||||
apiFilter?: Record<string, any>;
|
||||
}): TableFilter {
|
||||
return {
|
||||
name: name,
|
||||
@@ -386,6 +388,7 @@ export function OwnerFilter({
|
||||
description: description,
|
||||
type: 'api',
|
||||
apiUrl: apiUrl(ApiEndpoints.owner_list),
|
||||
apiFilter: { is_active: true, ...apiFilter },
|
||||
model: ModelType.owner,
|
||||
modelRenderer: (instance: any) => instance.name
|
||||
};
|
||||
@@ -425,11 +428,13 @@ export function TagsFilter({
|
||||
export function UserFilter({
|
||||
name,
|
||||
label,
|
||||
description
|
||||
description,
|
||||
apiFilter
|
||||
}: {
|
||||
name?: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
apiFilter?: Record<string, any>;
|
||||
}): TableFilter {
|
||||
return {
|
||||
name: name ?? 'user',
|
||||
@@ -437,6 +442,7 @@ export function UserFilter({
|
||||
description: description ?? t`Filter by user`,
|
||||
type: 'api',
|
||||
apiUrl: apiUrl(ApiEndpoints.user_list),
|
||||
apiFilter: { is_active: true, ...apiFilter },
|
||||
model: ModelType.user,
|
||||
modelRenderer: (instance: any) => instance.username
|
||||
};
|
||||
|
||||
@@ -585,7 +585,7 @@ export function ColumnFilterPopover({
|
||||
const closeOnApply = filters.length === 1;
|
||||
|
||||
return (
|
||||
<Stack gap={5} p={3}>
|
||||
<Stack gap={5} p={3} miw={250}>
|
||||
{filters.map((filter, index) => (
|
||||
<Stack gap='xs' key={filter.name}>
|
||||
{index > 0 && <Divider />}
|
||||
|
||||
@@ -24,7 +24,8 @@ export function TableHoverCard({
|
||||
icon, // The icon to display
|
||||
iconColor, // The icon color
|
||||
position, // The position of the hovercard
|
||||
zIndex // Optional z-index for the hovercard
|
||||
zIndex, // Optional z-index for the hovercard
|
||||
minWidth // Optional minimum width for the dropdown
|
||||
}: Readonly<{
|
||||
value: any;
|
||||
extra?: ReactNode;
|
||||
@@ -33,6 +34,7 @@ export function TableHoverCard({
|
||||
iconColor?: string;
|
||||
position?: FloatingPosition;
|
||||
zIndex?: string | number;
|
||||
minWidth?: number;
|
||||
}>) {
|
||||
const extraItems: ReactNode = useMemo(() => {
|
||||
if (Array.isArray(extra)) {
|
||||
@@ -74,7 +76,7 @@ export function TableHoverCard({
|
||||
/>
|
||||
</Group>
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown>
|
||||
<HoverCard.Dropdown style={minWidth ? { minWidth } : undefined}>
|
||||
<Stack gap='xs'>
|
||||
<Group gap='xs' justify='left'>
|
||||
<InvenTreeIcon
|
||||
|
||||
@@ -120,6 +120,7 @@ export function BuildOrderTable({
|
||||
UserColumn({
|
||||
accessor: 'issued_by_detail',
|
||||
ordering: 'issued_by',
|
||||
filter: 'issued_by',
|
||||
title: t`Issued By`
|
||||
}),
|
||||
ResponsibleColumn({}),
|
||||
|
||||
@@ -14,13 +14,14 @@ import {
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { TableColumn } from '@lib/types/Tables';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Group } from '@mantine/core';
|
||||
import { Divider, Group, Text } from '@mantine/core';
|
||||
import { useHover } from '@mantine/hooks';
|
||||
import { IconCirclePlus } from '@tabler/icons-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useApi } from '../../contexts/ApiContext';
|
||||
import { formatDate } from '../../defaults/formatters';
|
||||
import { useParameterFields } from '../../forms/CommonForms';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
@@ -72,11 +73,41 @@ function ParameterCell({
|
||||
parameter.data_numeric != parameter.data
|
||||
) {
|
||||
const numeric = formatDecimal(parameter.data_numeric, { digits: 15 });
|
||||
extra.push(`${numeric} [${template.units}]`);
|
||||
|
||||
extra.push(
|
||||
<Group gap='xs' justify='space-between'>
|
||||
<Text size='sm' fw='bold'>
|
||||
{numeric}
|
||||
</Text>
|
||||
<Text size='xs'>[{template.units}]</Text>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
if (parameter?.updated) {
|
||||
extra.push(
|
||||
<Group gap='xs' justify='space-between'>
|
||||
<Text size='sm' fw='bold'>{t`Last Updated`}</Text>
|
||||
<Text size='xs'>{formatDate(parameter.updated)}</Text>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
if (parameter?.updated_by_detail?.username) {
|
||||
extra.push(
|
||||
<Group gap='xs' justify='space-between'>
|
||||
<Text size='sm' fw='bold'>{t`Updated By`}</Text>
|
||||
<Text size='xs'>{parameter.updated_by_detail.username}</Text>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
if (hovered && canEdit) {
|
||||
extra.push(t`Click to edit`);
|
||||
if (extra.length > 0) {
|
||||
extra.push(<Divider />);
|
||||
}
|
||||
|
||||
extra.push(<Text size='xs'>{t`Click to edit`}</Text>);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -88,6 +119,7 @@ function ParameterCell({
|
||||
extra={extra}
|
||||
icon={hovered && canEdit ? 'edit' : 'info'}
|
||||
title={template.name}
|
||||
minWidth={250}
|
||||
/>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
@@ -18,8 +18,8 @@ import { apiUrl } from '@lib/functions/Api';
|
||||
import { identifierString } from '@lib/functions/Conversion';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||
import type { TableColumn } from '@lib/types/Tables';
|
||||
import type { ApiFormFieldSet, ApiFormFieldType } from '@lib/types/Forms';
|
||||
import type { TableColumn, TableColumnFilterType } from '@lib/types/Tables';
|
||||
import {
|
||||
CodeEditor,
|
||||
PdfPreview,
|
||||
@@ -68,11 +68,21 @@ export type TemplateI = {
|
||||
template: string;
|
||||
};
|
||||
|
||||
// Additional field props to control the column behaviour in the template table
|
||||
interface TemplateFormFieldType extends ApiFormFieldType {
|
||||
sortable?: boolean;
|
||||
switchable?: boolean;
|
||||
filter?: TableColumnFilterType;
|
||||
}
|
||||
|
||||
type TemplateFormFieldSet = Record<string, TemplateFormFieldType>;
|
||||
|
||||
export interface TemplateProps {
|
||||
modelType: ModelType.labeltemplate | ModelType.reporttemplate;
|
||||
templateEndpoint: ApiEndpoints;
|
||||
printingEndpoint: ApiEndpoints;
|
||||
additionalFormFields?: ApiFormFieldSet;
|
||||
additionalFilters?: TableFilter[];
|
||||
additionalFormFields?: TemplateFormFieldSet;
|
||||
}
|
||||
|
||||
export function TemplateDrawer({
|
||||
@@ -233,6 +243,7 @@ export function TemplateTable({
|
||||
},
|
||||
{
|
||||
accessor: 'model_type',
|
||||
filter: 'model_type',
|
||||
sortable: true,
|
||||
switchable: false
|
||||
},
|
||||
@@ -276,10 +287,10 @@ export function TemplateTable({
|
||||
},
|
||||
...Object.entries(additionalFormFields || {}).map(([key, field]) => ({
|
||||
accessor: key,
|
||||
...field,
|
||||
title: field.label,
|
||||
sortable: false,
|
||||
switchable: true,
|
||||
title: field.label,
|
||||
...field,
|
||||
render: field.modelRenderer
|
||||
})),
|
||||
BooleanColumn({ accessor: 'enabled', title: t`Enabled` })
|
||||
@@ -391,6 +402,7 @@ export function TemplateTable({
|
||||
|
||||
const tableFilters: TableFilter[] = useMemo(() => {
|
||||
return [
|
||||
...(templateProps.additionalFilters || []),
|
||||
{
|
||||
name: 'enabled',
|
||||
label: t`Enabled`,
|
||||
@@ -404,7 +416,7 @@ export function TemplateTable({
|
||||
choices: modelTypeFilters.choices
|
||||
}
|
||||
];
|
||||
}, [modelTypeFilters.choices]);
|
||||
}, [templateProps.additionalFilters, modelTypeFilters.choices]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in new issue
Block a user