mirror of
https://github.com/inventree/InvenTree.git
synced 2025-09-13 06:01:35 +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:
@@ -21,6 +21,7 @@ The *Display Settings* screen shows general display configuration options:
|
||||
{{ usersetting("ICONS_IN_NAVBAR") }}
|
||||
{{ usersetting("STICKY_HEADER") }}
|
||||
{{ usersetting("STICKY_TABLE_HEADER") }}
|
||||
{{ usersetting("SHOW_SPOTLIGHT") }}
|
||||
{{ usersetting("DATE_DISPLAY_FORMAT") }}
|
||||
{{ usersetting("FORMS_CLOSE_USING_ESCAPE") }}
|
||||
{{ usersetting("DISPLAY_STOCKTAKE_TAB") }}
|
||||
|
@@ -191,6 +191,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
|
||||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'SHOW_SPOTLIGHT': {
|
||||
'name': _('Show Spotlight'),
|
||||
'description': _('Enable spotlight navigation functionality'),
|
||||
'default': True,
|
||||
'validator': bool,
|
||||
},
|
||||
'ICONS_IN_NAVBAR': {
|
||||
'name': _('Navigation Icons'),
|
||||
'description': _('Display icons in the navigation bar'),
|
||||
|
@@ -8,7 +8,11 @@ import {
|
||||
Tooltip,
|
||||
UnstyledButton
|
||||
} from '@mantine/core';
|
||||
import { useDisclosure, useDocumentVisibility } from '@mantine/hooks';
|
||||
import {
|
||||
useDisclosure,
|
||||
useDocumentVisibility,
|
||||
useHotkeys
|
||||
} from '@mantine/hooks';
|
||||
import { IconBell, IconSearch } from '@tabler/icons-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { type ReactNode, useEffect, useMemo, useState } from 'react';
|
||||
@@ -49,11 +53,27 @@ export function Header() {
|
||||
const [server] = useServerApiState(useShallow((state) => [state.server]));
|
||||
const [navDrawerOpened, { open: openNavDrawer, close: closeNavDrawer }] =
|
||||
useDisclosure(navigationOpen);
|
||||
|
||||
const [
|
||||
searchDrawerOpened,
|
||||
{ open: openSearchDrawer, close: closeSearchDrawer }
|
||||
] = useDisclosure(false);
|
||||
|
||||
useHotkeys([
|
||||
[
|
||||
'/',
|
||||
() => {
|
||||
openSearchDrawer();
|
||||
}
|
||||
],
|
||||
[
|
||||
'mod+/',
|
||||
() => {
|
||||
openSearchDrawer();
|
||||
}
|
||||
]
|
||||
]);
|
||||
|
||||
const [
|
||||
notificationDrawerOpened,
|
||||
{ open: openNotificationDrawer, close: closeNotificationDrawer }
|
||||
@@ -154,7 +174,7 @@ export function Header() {
|
||||
<IconSearch />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<SpotlightButton />
|
||||
{userSettings.isSet('SHOW_SPOTLIGHT') && <SpotlightButton />}
|
||||
{globalSettings.isSet('BARCODE_ENABLE') && <ScanButton />}
|
||||
<Indicator
|
||||
radius='lg'
|
||||
|
@@ -7,6 +7,7 @@ import { Navigate, Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { getActions } from '../../defaults/actions';
|
||||
import * as classes from '../../main.css';
|
||||
import { useUserSettingsState } from '../../states/SettingsStates';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { Boundary } from '../Boundary';
|
||||
import { Footer } from './Footer';
|
||||
@@ -37,6 +38,7 @@ export const [firstStore, firstSpotlight] = createSpotlight();
|
||||
export default function LayoutComponent() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const userSettings = useUserSettingsState();
|
||||
|
||||
const defaultActions = getActions(navigate);
|
||||
const [actions, setActions] = useState(defaultActions);
|
||||
@@ -68,17 +70,19 @@ export default function LayoutComponent() {
|
||||
</Container>
|
||||
<Space h='xl' />
|
||||
<Footer />
|
||||
<Spotlight
|
||||
actions={actions}
|
||||
store={firstStore}
|
||||
highlightQuery
|
||||
searchProps={{
|
||||
leftSection: <IconSearch size='1.2rem' />,
|
||||
placeholder: t`Search...`
|
||||
}}
|
||||
shortcut={['mod + K', '/']}
|
||||
nothingFound={t`Nothing found...`}
|
||||
/>
|
||||
{userSettings.isSet('SHOW_SPOTLIGHT') && (
|
||||
<Spotlight
|
||||
actions={actions}
|
||||
store={firstStore}
|
||||
highlightQuery
|
||||
searchProps={{
|
||||
leftSection: <IconSearch size='1.2rem' />,
|
||||
placeholder: t`Search...`
|
||||
}}
|
||||
shortcut={['mod + K']}
|
||||
nothingFound={t`Nothing found...`}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</ProtectedRoute>
|
||||
);
|
||||
|
@@ -58,6 +58,7 @@ export default function UserSettings() {
|
||||
'ICONS_IN_NAVBAR',
|
||||
'STICKY_HEADER',
|
||||
'STICKY_TABLE_HEADER',
|
||||
'SHOW_SPOTLIGHT',
|
||||
'DATE_DISPLAY_FORMAT',
|
||||
'FORMS_CLOSE_USING_ESCAPE',
|
||||
'DISPLAY_STOCKTAKE_TAB',
|
||||
|
@@ -5,7 +5,7 @@ import { doCachedLogin } from './login.js';
|
||||
/**
|
||||
* Test for integration of django admin button
|
||||
*/
|
||||
test('Admin Button', async ({ browser }) => {
|
||||
test('General - Admin Button', async ({ browser }) => {
|
||||
const page = await doCachedLogin(browser, {
|
||||
username: 'admin',
|
||||
password: 'inventree',
|
||||
@@ -21,12 +21,17 @@ test('Admin Button', async ({ browser }) => {
|
||||
});
|
||||
|
||||
// Tests for the global search functionality
|
||||
test('Search', async ({ browser }) => {
|
||||
test('General - Search', async ({ browser }) => {
|
||||
const page = await doCachedLogin(browser, {
|
||||
username: 'steven',
|
||||
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');
|
||||
|
||||
// Check for expected results
|
||||
|
Reference in New Issue
Block a user