2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-09-13 14:11:37 +00:00

[UI] Search shortcut (#10181)

* Add search shortcut

- Use '/' to open search drawer

* Add user setting for spotlight

* Hide spotlight if disabled

* Updated playwright tests
This commit is contained in:
Oliver
2025-08-15 20:41:03 +10:00
committed by GitHub
parent 4cadc433bb
commit 0f04c31ffb
6 changed files with 52 additions and 15 deletions

View File

@@ -21,6 +21,7 @@ The *Display Settings* screen shows general display configuration options:
{{ usersetting("ICONS_IN_NAVBAR") }} {{ usersetting("ICONS_IN_NAVBAR") }}
{{ usersetting("STICKY_HEADER") }} {{ usersetting("STICKY_HEADER") }}
{{ usersetting("STICKY_TABLE_HEADER") }} {{ usersetting("STICKY_TABLE_HEADER") }}
{{ usersetting("SHOW_SPOTLIGHT") }}
{{ usersetting("DATE_DISPLAY_FORMAT") }} {{ usersetting("DATE_DISPLAY_FORMAT") }}
{{ usersetting("FORMS_CLOSE_USING_ESCAPE") }} {{ usersetting("FORMS_CLOSE_USING_ESCAPE") }}
{{ usersetting("DISPLAY_STOCKTAKE_TAB") }} {{ usersetting("DISPLAY_STOCKTAKE_TAB") }}

View File

@@ -191,6 +191,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
'default': False, 'default': False,
'validator': bool, 'validator': bool,
}, },
'SHOW_SPOTLIGHT': {
'name': _('Show Spotlight'),
'description': _('Enable spotlight navigation functionality'),
'default': True,
'validator': bool,
},
'ICONS_IN_NAVBAR': { 'ICONS_IN_NAVBAR': {
'name': _('Navigation Icons'), 'name': _('Navigation Icons'),
'description': _('Display icons in the navigation bar'), 'description': _('Display icons in the navigation bar'),

View File

@@ -8,7 +8,11 @@ import {
Tooltip, Tooltip,
UnstyledButton UnstyledButton
} from '@mantine/core'; } from '@mantine/core';
import { useDisclosure, useDocumentVisibility } from '@mantine/hooks'; import {
useDisclosure,
useDocumentVisibility,
useHotkeys
} from '@mantine/hooks';
import { IconBell, IconSearch } from '@tabler/icons-react'; import { IconBell, IconSearch } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { type ReactNode, useEffect, useMemo, useState } from 'react'; import { type ReactNode, useEffect, useMemo, useState } from 'react';
@@ -49,11 +53,27 @@ export function Header() {
const [server] = useServerApiState(useShallow((state) => [state.server])); const [server] = useServerApiState(useShallow((state) => [state.server]));
const [navDrawerOpened, { open: openNavDrawer, close: closeNavDrawer }] = const [navDrawerOpened, { open: openNavDrawer, close: closeNavDrawer }] =
useDisclosure(navigationOpen); useDisclosure(navigationOpen);
const [ const [
searchDrawerOpened, searchDrawerOpened,
{ open: openSearchDrawer, close: closeSearchDrawer } { open: openSearchDrawer, close: closeSearchDrawer }
] = useDisclosure(false); ] = useDisclosure(false);
useHotkeys([
[
'/',
() => {
openSearchDrawer();
}
],
[
'mod+/',
() => {
openSearchDrawer();
}
]
]);
const [ const [
notificationDrawerOpened, notificationDrawerOpened,
{ open: openNotificationDrawer, close: closeNotificationDrawer } { open: openNotificationDrawer, close: closeNotificationDrawer }
@@ -154,7 +174,7 @@ export function Header() {
<IconSearch /> <IconSearch />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>
<SpotlightButton /> {userSettings.isSet('SHOW_SPOTLIGHT') && <SpotlightButton />}
{globalSettings.isSet('BARCODE_ENABLE') && <ScanButton />} {globalSettings.isSet('BARCODE_ENABLE') && <ScanButton />}
<Indicator <Indicator
radius='lg' radius='lg'

View File

@@ -7,6 +7,7 @@ import { Navigate, Outlet, useLocation, useNavigate } from 'react-router-dom';
import { getActions } from '../../defaults/actions'; import { getActions } from '../../defaults/actions';
import * as classes from '../../main.css'; import * as classes from '../../main.css';
import { useUserSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { Boundary } from '../Boundary'; import { Boundary } from '../Boundary';
import { Footer } from './Footer'; import { Footer } from './Footer';
@@ -37,6 +38,7 @@ export const [firstStore, firstSpotlight] = createSpotlight();
export default function LayoutComponent() { export default function LayoutComponent() {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const userSettings = useUserSettingsState();
const defaultActions = getActions(navigate); const defaultActions = getActions(navigate);
const [actions, setActions] = useState(defaultActions); const [actions, setActions] = useState(defaultActions);
@@ -68,17 +70,19 @@ export default function LayoutComponent() {
</Container> </Container>
<Space h='xl' /> <Space h='xl' />
<Footer /> <Footer />
<Spotlight {userSettings.isSet('SHOW_SPOTLIGHT') && (
actions={actions} <Spotlight
store={firstStore} actions={actions}
highlightQuery store={firstStore}
searchProps={{ highlightQuery
leftSection: <IconSearch size='1.2rem' />, searchProps={{
placeholder: t`Search...` leftSection: <IconSearch size='1.2rem' />,
}} placeholder: t`Search...`
shortcut={['mod + K', '/']} }}
nothingFound={t`Nothing found...`} shortcut={['mod + K']}
/> nothingFound={t`Nothing found...`}
/>
)}
</Flex> </Flex>
</ProtectedRoute> </ProtectedRoute>
); );

View File

@@ -58,6 +58,7 @@ export default function UserSettings() {
'ICONS_IN_NAVBAR', 'ICONS_IN_NAVBAR',
'STICKY_HEADER', 'STICKY_HEADER',
'STICKY_TABLE_HEADER', 'STICKY_TABLE_HEADER',
'SHOW_SPOTLIGHT',
'DATE_DISPLAY_FORMAT', 'DATE_DISPLAY_FORMAT',
'FORMS_CLOSE_USING_ESCAPE', 'FORMS_CLOSE_USING_ESCAPE',
'DISPLAY_STOCKTAKE_TAB', 'DISPLAY_STOCKTAKE_TAB',

View File

@@ -5,7 +5,7 @@ import { doCachedLogin } from './login.js';
/** /**
* Test for integration of django admin button * Test for integration of django admin button
*/ */
test('Admin Button', async ({ browser }) => { test('General - Admin Button', async ({ browser }) => {
const page = await doCachedLogin(browser, { const page = await doCachedLogin(browser, {
username: 'admin', username: 'admin',
password: 'inventree', password: 'inventree',
@@ -21,12 +21,17 @@ test('Admin Button', async ({ browser }) => {
}); });
// Tests for the global search functionality // Tests for the global search functionality
test('Search', async ({ browser }) => { test('General - Search', async ({ browser }) => {
const page = await doCachedLogin(browser, { const page = await doCachedLogin(browser, {
username: 'steven', username: 'steven',
password: 'wizardstaff' password: 'wizardstaff'
}); });
// Open the search drawer with a shortcut
await page.keyboard.press('Control+/');
await page.getByRole('textbox', { name: 'global-search-input' }).waitFor();
await page.keyboard.press('Escape');
await globalSearch(page, 'another customer'); await globalSearch(page, 'another customer');
// Check for expected results // Check for expected results