2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-07-04 06:00:38 +00:00

Remember last used label template and printer plugin per model type (#12146)

* Remember last used label template and printer plugin per model type

* Added playwright test for printing preference persistence and format code

* Used waitFor for react-select assertions for test case fixing and persist plugin key correctly

* Updated the problem resolution code and the tests

* Fixed printing test assertion to avoid word boundary failure with concatenated text
This commit is contained in:
Sanidhya
2026-06-13 09:00:42 +05:30
committed by GitHub
parent d8ae8723ff
commit 3bce9c0a15
3 changed files with 85 additions and 5 deletions
@@ -11,6 +11,7 @@ import { api } from '../../App';
import { extractAvailableFields } from '../../functions/forms';
import useDataOutput from '../../hooks/UseDataOutput';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useLocalState } from '../../states/LocalState';
import {
useGlobalSettingsState,
useUserSettingsState
@@ -32,6 +33,11 @@ export function PrintingActions({
}) {
const userSettings = useUserSettingsState();
const globalSettings = useGlobalSettingsState();
const localState = useLocalState();
const lastUsedPrinting = useMemo(() => {
return modelType ? localState.lastUsedPrinting[modelType] : undefined;
}, [localState.lastUsedPrinting, modelType]);
const enabled = useMemo(() => items.length > 0, [items]);
@@ -118,6 +124,7 @@ export function PrintingActions({
fields.template = {
...fields.template,
autoFill: true,
value: lastUsedPrinting?.template,
filters: {
enabled: true,
model_type: modelType,
@@ -147,7 +154,14 @@ export function PrintingActions({
};
return fields;
}, [defaultLabelPlugin, pluginKey, printingFields.data, itemIdList]);
}, [
defaultLabelPlugin,
pluginKey,
printingFields.data,
itemIdList,
lastUsedPrinting,
modelType
]);
const labelModal = useCreateApiFormModal({
url: apiUrl(ApiEndpoints.label_print),
@@ -158,15 +172,21 @@ export function PrintingActions({
onOpen: () => {
setLabelDialogOpen(true);
setItemIdList(items);
setPluginKey(lastUsedPrinting?.plugin ?? null);
},
onClose: () => {
setLabelDialogOpen(false);
setPluginKey('');
},
submitText: t`Print`,
successMessage: null,
onFormSuccess: (response: any) => {
setPluginKey('');
onFormSuccess: (response: any, form: any) => {
if (modelType) {
const values = form?.getValues?.();
localState.setLastUsedPrinting(modelType, {
plugin: pluginKey || undefined,
template: values?.template ? Number(values.template) : undefined
});
}
setLabelId(response.pk);
}
});
+25
View File
@@ -33,6 +33,12 @@ interface LocalStateProps {
setLayouts: (layouts: any, noPatch?: boolean) => void;
showSampleDashboard: boolean;
setShowSampleDashboard: (value: boolean) => void;
// printing
lastUsedPrinting: Record<string, { plugin?: string; template?: number }>;
setLastUsedPrinting: (
modelType: string,
values: { plugin?: string; template?: number }
) => void;
// panels
lastUsedPanels: Record<string, string>;
setLastUsedPanel: (panelKey: string) => (value: string) => void;
@@ -122,6 +128,25 @@ export const useLocalState = create<LocalStateProps>()(
setShowSampleDashboard: (value) => {
set({ showSampleDashboard: value });
},
// printing
lastUsedPrinting: {},
setLastUsedPrinting: (modelType, values) => {
const current = get().lastUsedPrinting[modelType] || {};
if (
current.plugin !== values.plugin ||
current.template !== values.template
) {
set({
lastUsedPrinting: {
...get().lastUsedPrinting,
[modelType]: {
...current,
...values
}
}
});
}
},
// panels
lastUsedPanels: {},
setLastUsedPanel: (panelKey) => (value) => {
+36 -1
View File
@@ -65,7 +65,42 @@ test('Printing - Label Printing', async ({ browser }) => {
await page.getByRole('button', { name: 'Print', exact: true }).isEnabled();
await page.getByRole('button', { name: 'Print', exact: true }).click();
await page.getByText('Process completed successfully').first().waitFor();
const successMessage = page
.getByText('Process completed successfully')
.first();
await successMessage.waitFor();
await successMessage.waitFor({ state: 'hidden' });
// Re-open print dialog to verify persistence (issue #12129)
await page
.getByLabel('Stock Items')
.getByLabel('action-menu-printing-actions')
.click();
await page.getByLabel('action-menu-printing-actions-print-labels').click();
const labelDialog = page.getByRole('dialog', { name: 'Print Label' });
// Wait for the dialog to fully load
await labelDialog.getByLabel('related-field-template').waitFor();
await labelDialog.getByLabel('related-field-plugin').waitFor();
// Verify the last-used template is preselected
await expect(labelDialog).toContainText('InvenTree Stock Item Label');
// Verify the last-used plugin is preselected
await expect(labelDialog).toContainText('InvenTreeLabel');
// Submit again without re-selecting template or plugin
const printResponse = page.waitForResponse(
(response) =>
response.url().includes('/api/label/print/') &&
response.request().method() === 'POST' &&
response.ok()
);
await labelDialog.getByRole('button', { name: 'Print', exact: true }).click();
await printResponse;
await page.context().close();
});