Merge commit '3309032b261e891944db5270a305a3ecf9f926ce' into block-notes

This commit is contained in:
Oliver Walters committed 2026-06-11 06:33:52 +00:00
commit d98a57fbe9
97 files changed
+124493 -118422

No files matched your search

+6 -4
View File
@@ -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;
+23 -1
View File
@@ -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({
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
@@ -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} />
)
+8 -2
View File
@@ -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 />}
+4 -2
View File
@@ -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 (
<>