2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-05-17 14:58:36 +00:00

Feature: Auto-select items tab for final stock locations (#11766) (#11955)

* Enhance: Auto-select items tab for final stock locations/categories

* Fix biome formatting in PanelGroup.tsx

* Change default setting to False per review

* Refactor: Rename setting to DISPLAY_ITEMS_FINAL_LEVEL to apply generically to both locations and categories per review

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
Aditya Kumar Mishra
2026-05-17 14:36:00 +05:30
committed by GitHub
parent c09848422c
commit 582013e51c
5 changed files with 43 additions and 1 deletions
+1
View File
@@ -30,6 +30,7 @@ The *Display Settings* screen shows general display configuration options:
{{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}} {{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}}
{{ usersetting("ENABLE_LAST_BREADCRUMB") }} {{ usersetting("ENABLE_LAST_BREADCRUMB") }}
{{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }} {{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }}
{{ usersetting("DISPLAY_ITEMS_FINAL_LEVEL") }}
### Search Settings ### Search Settings
@@ -268,4 +268,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
'description': _('Save the last used printing machines for a user'), 'description': _('Save the last used printing machines for a user'),
'default': '', 'default': '',
}, },
'DISPLAY_ITEMS_FINAL_LEVEL': {
'name': _('Display Items at Final Level'),
'description': _(
'Automatically default to showing items/parts instead of sub-levels for locations or categories with no children'
),
'default': False,
'validator': bool,
},
} }
@@ -79,6 +79,7 @@ export type PanelProps = {
model?: ModelType; model?: ModelType;
id?: number | null; id?: number | null;
selectedPanel?: string; selectedPanel?: string;
defaultPanel?: string;
onPanelChange?: (panel: string) => void; onPanelChange?: (panel: string) => void;
collapsible?: boolean; collapsible?: boolean;
pluginPanelWithoutId?: boolean; pluginPanelWithoutId?: boolean;
@@ -483,12 +484,16 @@ function getPanelContent(
function IndexPanelComponent({ function IndexPanelComponent({
pageKey, pageKey,
selectedPanel, selectedPanel,
defaultPanel,
panels panels
}: Readonly<PanelProps>) { }: Readonly<PanelProps>) {
const lastUsedPanel = useLocalState( const lastUsedPanel = useLocalState(
useShallow((state) => { useShallow((state) => {
const panelName = const panelName =
selectedPanel || state.lastUsedPanels[pageKey] || panels[0]?.name; selectedPanel ||
defaultPanel ||
state.lastUsedPanels[pageKey] ||
panels[0]?.name;
const panel = panels.findIndex( const panel = panels.findIndex(
(p) => p.name === panelName && !p.disabled && !p.hidden (p) => p.name === panelName && !p.disabled && !p.hidden
@@ -42,6 +42,7 @@ import {
useEditApiFormModal useEditApiFormModal
} from '../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { useUserSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import ParametricPartTable from '../../tables/part/ParametricPartTable'; import ParametricPartTable from '../../tables/part/ParametricPartTable';
import { PartCategoryTable } from '../../tables/part/PartCategoryTable'; import { PartCategoryTable } from '../../tables/part/PartCategoryTable';
@@ -63,6 +64,7 @@ export default function CategoryDetail() {
const navigate = useNavigate(); const navigate = useNavigate();
const user = useUserState(); const user = useUserState();
const settings = useUserSettingsState();
const [treeOpen, setTreeOpen] = useState(false); const [treeOpen, setTreeOpen] = useState(false);
@@ -344,6 +346,17 @@ export default function CategoryDetail() {
[category] [category]
); );
const defaultPanel = useMemo(() => {
if (
settings.isSet('DISPLAY_ITEMS_FINAL_LEVEL', true) &&
category.pk &&
category.subcategories === 0
) {
return 'parts';
}
return undefined;
}, [settings, category]);
return ( return (
<> <>
{editCategory.modal} {editCategory.modal}
@@ -385,6 +398,7 @@ export default function CategoryDetail() {
instance={category} instance={category}
reloadInstance={refreshInstance} reloadInstance={refreshInstance}
id={category.pk ?? null} id={category.pk ?? null}
defaultPanel={defaultPanel}
/> />
</Stack> </Stack>
</InstanceDetail> </InstanceDetail>
@@ -47,6 +47,7 @@ import {
} from '../../hooks/UseForm'; } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance'; import { useInstance } from '../../hooks/UseInstance';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions'; import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';
import { useUserSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { PartListTable } from '../../tables/part/PartTable'; import { PartListTable } from '../../tables/part/PartTable';
import { StockItemTable } from '../../tables/stock/StockItemTable'; import { StockItemTable } from '../../tables/stock/StockItemTable';
@@ -63,6 +64,7 @@ export default function Stock() {
const navigate = useNavigate(); const navigate = useNavigate();
const user = useUserState(); const user = useUserState();
const settings = useUserSettingsState();
const [treeOpen, setTreeOpen] = useState(false); const [treeOpen, setTreeOpen] = useState(false);
@@ -431,6 +433,17 @@ export default function Stock() {
[location] [location]
); );
const defaultPanel = useMemo(() => {
if (
settings.isSet('DISPLAY_ITEMS_FINAL_LEVEL', true) &&
location.pk &&
location.sublocations === 0
) {
return 'stock-items';
}
return undefined;
}, [settings, location]);
return ( return (
<> <>
{editLocation.modal} {editLocation.modal}
@@ -479,6 +492,7 @@ export default function Stock() {
id={location?.pk} id={location?.pk}
instance={location} instance={location}
pluginPanelWithoutId pluginPanelWithoutId
defaultPanel={defaultPanel}
/> />
</Stack> </Stack>
{stockAdjustActions.modals.map((modal) => modal.modal)} {stockAdjustActions.modals.map((modal) => modal.modal)}