rename globalSearch

This commit is contained in:
pa
2026-03-14 20:05:10 +09:00
parent b750d3fb9a
commit 84f46a5645
14 changed files with 51 additions and 51 deletions

View File

@@ -5,13 +5,13 @@
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useGlobalSearchStore } from '../stores/globalSearch'; import { useQuickSearchStore } from '../stores/quickSearch';
import { useUserDisplay } from '../composables/useUserDisplay'; import { useUserDisplay } from '../composables/useUserDisplay';
import GlobalSearchSync from './GlobalSearchSync.vue'; import QuickSearchSync from './QuickSearchSync.vue';
const { userImage } = useUserDisplay(); const { userImage } = useUserDisplay();
const globalSearchStore = useGlobalSearchStore(); const quickSearchStore = useQuickSearchStore();
const { const {
isOpen, isOpen,
query, query,
@@ -23,8 +23,8 @@
ownGroupResults, ownGroupResults,
joinedGroupResults, joinedGroupResults,
hasResults hasResults
} = storeToRefs(globalSearchStore); } = storeToRefs(quickSearchStore);
const { selectResult } = globalSearchStore; const { selectResult } = quickSearchStore;
const { t } = useI18n(); const { t } = useI18n();
/** /**
@@ -44,7 +44,7 @@
</DialogHeader> </DialogHeader>
<Command> <Command>
<!-- Sync filterState.search store.query --> <!-- Sync filterState.search store.query -->
<GlobalSearchSync /> <QuickSearchSync />
<CommandInput :placeholder="t('side_panel.search_placeholder')" /> <CommandInput :placeholder="t('side_panel.search_placeholder')" />
<CommandList class="max-h-[min(400px,50vh)] overflow-y-auto overflow-x-hidden"> <CommandList class="max-h-[min(400px,50vh)] overflow-y-auto overflow-x-hidden">
<template v-if="!query || query.length < 2"> <template v-if="!query || query.length < 2">

View File

@@ -15,15 +15,15 @@
import { nextTick, watch } from 'vue'; import { nextTick, watch } from 'vue';
import { useCommand } from '@/components/ui/command'; import { useCommand } from '@/components/ui/command';
import { useGlobalSearchStore } from '../stores/globalSearch'; import { useQuickSearchStore } from '../stores/quickSearch';
const { filterState, allItems, allGroups } = useCommand(); const { filterState, allItems, allGroups } = useCommand();
const globalSearchStore = useGlobalSearchStore(); const quickSearchStore = useQuickSearchStore();
watch( watch(
() => filterState.search, () => filterState.search,
async (value) => { async (value) => {
globalSearchStore.setQuery(value); quickSearchStore.setQuery(value);
// When query < 2 chars, override the built-in filter // When query < 2 chars, override the built-in filter
// so all items (hint categories) stay visible // so all items (hint categories) stay visible

View File

@@ -18,8 +18,8 @@ const mocks = vi.hoisted(() => ({
vi.mock('pinia', async (i) => ({ ...(await i()), storeToRefs: (s) => s })); vi.mock('pinia', async (i) => ({ ...(await i()), storeToRefs: (s) => s }));
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (k) => k }) })); vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (k) => k }) }));
vi.mock('../../stores/globalSearch', () => ({ vi.mock('../../stores/quickSearch', () => ({
useGlobalSearchStore: () => ({ useQuickSearchStore: () => ({
isOpen: mocks.isOpen, isOpen: mocks.isOpen,
query: mocks.query, query: mocks.query,
friendResults: mocks.friendResults, friendResults: mocks.friendResults,
@@ -36,7 +36,7 @@ vi.mock('../../stores/globalSearch', () => ({
vi.mock('../../composables/useUserDisplay', () => ({ vi.mock('../../composables/useUserDisplay', () => ({
useUserDisplay: () => ({ userImage: (...a) => mocks.userImage(...a) }) useUserDisplay: () => ({ userImage: (...a) => mocks.userImage(...a) })
})); }));
vi.mock('../GlobalSearchSync.vue', () => ({ vi.mock('../QuickSearchSync.vue', () => ({
default: { template: '<div data-testid="sync" />' } default: { template: '<div data-testid="sync" />' }
})); }));
vi.mock('@/components/ui/dialog', () => ({ vi.mock('@/components/ui/dialog', () => ({
@@ -63,9 +63,9 @@ vi.mock('lucide-vue-next', () => ({
Users: { template: '<i />' } Users: { template: '<i />' }
})); }));
import GlobalSearchDialog from '../GlobalSearchDialog.vue'; import QuickSearchDialog from '../QuickSearchDialog.vue';
describe('GlobalSearchDialog.vue', () => { describe('QuickSearchDialog.vue', () => {
beforeEach(() => { beforeEach(() => {
mocks.selectResult.mockClear(); mocks.selectResult.mockClear();
mocks.query.value = ''; mocks.query.value = '';
@@ -74,7 +74,7 @@ describe('GlobalSearchDialog.vue', () => {
}); });
it('renders search dialog structure', () => { it('renders search dialog structure', () => {
const wrapper = mount(GlobalSearchDialog); const wrapper = mount(QuickSearchDialog);
expect(wrapper.text()).toContain('side_panel.search_placeholder'); expect(wrapper.text()).toContain('side_panel.search_placeholder');
expect(wrapper.find('[data-testid="sync"]').exists()).toBe(true); expect(wrapper.find('[data-testid="sync"]').exists()).toBe(true);
}); });

View File

@@ -34,17 +34,17 @@ vi.mock('@/components/ui/command', async () => {
}; };
}); });
vi.mock('../../stores/globalSearch', () => ({ vi.mock('../../stores/quickSearch', () => ({
useGlobalSearchStore: () => ({ useQuickSearchStore: () => ({
setQuery: (...args) => mocks.setQuery(...args) setQuery: (...args) => mocks.setQuery(...args)
}) })
})); }));
import GlobalSearchSync from '../GlobalSearchSync.vue'; import QuickSearchSync from '../QuickSearchSync.vue';
describe('GlobalSearchSync.vue', () => { describe('QuickSearchSync.vue', () => {
it('syncs query and keeps hint groups/items visible when query length < 2', async () => { it('syncs query and keeps hint groups/items visible when query length < 2', async () => {
mount(GlobalSearchSync); mount(QuickSearchSync);
mocks.filterState.search = 'a'; mocks.filterState.search = 'a';
await Promise.resolve(); await Promise.resolve();

View File

@@ -7,7 +7,7 @@ import {
searchFriends, searchFriends,
searchGroups, searchGroups,
searchWorlds searchWorlds
} from '../globalSearchUtils'; } from '../quickSearchUtils';
const comparer = new Intl.Collator(undefined, { const comparer = new Intl.Collator(undefined, {
usage: 'search', usage: 'search',

View File

@@ -9,7 +9,7 @@ const mocks = vi.hoisted(() => ({
userStore: null userStore: null
})); }));
vi.mock('../searchWorker.js?worker', () => ({ vi.mock('../quickSearchWorker.js?worker', () => ({
default: class MockSearchWorker { default: class MockSearchWorker {
constructor() { constructor() {
this.onmessage = null; this.onmessage = null;
@@ -51,7 +51,7 @@ vi.mock('../../coordinators/groupCoordinator', () => ({
showGroupDialog: (...args) => showGroupDialog(...args) showGroupDialog: (...args) => showGroupDialog(...args)
})); }));
import { useGlobalSearchStore } from '../globalSearch'; import { useQuickSearchStore } from '../quickSearch';
function setupStores() { function setupStores() {
mocks.friendStore = reactive({ friends: new Map() }); mocks.friendStore = reactive({ friends: new Map() });
@@ -82,7 +82,7 @@ function setupStores() {
mocks.userStore = reactive({ currentUser: { id: 'usr_me' } }); mocks.userStore = reactive({ currentUser: { id: 'usr_me' } });
} }
describe('useGlobalSearchStore', () => { describe('useQuickSearchStore', () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
mocks.workerInstances.length = 0; mocks.workerInstances.length = 0;
@@ -91,7 +91,7 @@ describe('useGlobalSearchStore', () => {
}); });
test('discards stale worker results and applies the latest seq only', async () => { test('discards stale worker results and applies the latest seq only', async () => {
const store = useGlobalSearchStore(); const store = useQuickSearchStore();
store.setQuery('ab'); store.setQuery('ab');
await nextTick(); await nextTick();
@@ -143,7 +143,7 @@ describe('useGlobalSearchStore', () => {
}); });
test('short query clears results and blocks stale refill', async () => { test('short query clears results and blocks stale refill', async () => {
const store = useGlobalSearchStore(); const store = useQuickSearchStore();
store.setQuery('ab'); store.setQuery('ab');
await nextTick(); await nextTick();
@@ -172,7 +172,7 @@ describe('useGlobalSearchStore', () => {
}); });
test('re-dispatches search when currentUserId changes and query is active', async () => { test('re-dispatches search when currentUserId changes and query is active', async () => {
const store = useGlobalSearchStore(); const store = useQuickSearchStore();
store.setQuery('ab'); store.setQuery('ab');
await nextTick(); await nextTick();
@@ -192,7 +192,7 @@ describe('useGlobalSearchStore', () => {
test('re-dispatches search after index update when query is active', async () => { test('re-dispatches search after index update when query is active', async () => {
vi.useFakeTimers(); vi.useFakeTimers();
const store = useGlobalSearchStore(); const store = useQuickSearchStore();
store.isOpen = true; store.isOpen = true;
await nextTick(); await nextTick();

View File

@@ -19,14 +19,14 @@ function setupWorkerHarness() {
}; };
} }
describe('searchWorker message protocol', () => { describe('quickSearchWorker message protocol', () => {
beforeEach(() => { beforeEach(() => {
vi.resetModules(); vi.resetModules();
}); });
test('returns empty search result for short query', async () => { test('returns empty search result for short query', async () => {
const harness = setupWorkerHarness(); const harness = setupWorkerHarness();
await import('../searchWorker.js'); await import('../quickSearchWorker.js');
harness.dispatch({ harness.dispatch({
type: 'search', type: 'search',
@@ -56,7 +56,7 @@ describe('searchWorker message protocol', () => {
test('deduplicates favorites and joined groups against own results', async () => { test('deduplicates favorites and joined groups against own results', async () => {
const harness = setupWorkerHarness(); const harness = setupWorkerHarness();
await import('../searchWorker.js'); await import('../quickSearchWorker.js');
harness.dispatch({ harness.dispatch({
type: 'updateIndex', type: 'updateIndex',

View File

@@ -17,7 +17,7 @@ import { useGalleryStore } from './gallery';
import { useGameLogStore } from './gameLog'; import { useGameLogStore } from './gameLog';
import { useGameStore } from './game'; import { useGameStore } from './game';
import { useGeneralSettingsStore } from './settings/general'; import { useGeneralSettingsStore } from './settings/general';
import { useGlobalSearchStore } from './globalSearch'; import { useQuickSearchStore } from './quickSearch';
import { useGroupStore } from './group'; import { useGroupStore } from './group';
import { useInstanceStore } from './instance'; import { useInstanceStore } from './instance';
import { useInviteStore } from './invite'; import { useInviteStore } from './invite';
@@ -167,7 +167,7 @@ export function createGlobalStores() {
charts: useChartsStore(), charts: useChartsStore(),
dashboard: useDashboardStore(), dashboard: useDashboardStore(),
modal: useModalStore(), modal: useModalStore(),
globalSearch: useGlobalSearchStore() quickSearch: useQuickSearchStore()
}; };
} }
@@ -208,5 +208,5 @@ export {
useUpdateLoopStore, useUpdateLoopStore,
useVrcStatusStore, useVrcStatusStore,
useModalStore, useModalStore,
useGlobalSearchStore useQuickSearchStore
}; };

View File

@@ -8,9 +8,9 @@ import { showWorldDialog } from '../coordinators/worldCoordinator';
import { showAvatarDialog } from '../coordinators/avatarCoordinator'; import { showAvatarDialog } from '../coordinators/avatarCoordinator';
import { showUserDialog } from '../coordinators/userCoordinator'; import { showUserDialog } from '../coordinators/userCoordinator';
import SearchWorker from './searchWorker.js?worker'; import QuickSearchWorker from './quickSearchWorker.js?worker';
export const useGlobalSearchStore = defineStore('GlobalSearch', () => { export const useQuickSearchStore = defineStore('QuickSearch', () => {
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const userStore = useUserStore(); const userStore = useUserStore();
const searchIndexStore = useSearchIndexStore(); const searchIndexStore = useSearchIndexStore();
@@ -25,7 +25,7 @@ export const useGlobalSearchStore = defineStore('GlobalSearch', () => {
function getWorker() { function getWorker() {
if (!worker) { if (!worker) {
worker = new SearchWorker(); worker = new QuickSearchWorker();
worker.onmessage = handleWorkerMessage; worker.onmessage = handleWorkerMessage;
} }
return worker; return worker;

View File

@@ -252,7 +252,7 @@ export const useSearchIndexStore = defineStore('SearchIndex', () => {
/** /**
* Build a snapshot from the internal index maps. * Build a snapshot from the internal index maps.
* Used by globalSearch to send data to the Worker. * Used by quickSearch to send data to the Worker.
* @returns {object} Plain object arrays ready for postMessage. * @returns {object} Plain object arrays ready for postMessage.
*/ */
function getSnapshot() { function getSnapshot() {

View File

@@ -5,7 +5,7 @@
<button <button
type="button" type="button"
class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-2 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer overflow-hidden" class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-2 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer overflow-hidden"
@click="openGlobalSearch"> @click="openQuickSearch">
<Search class="size-4 shrink-0 opacity-50" /> <Search class="size-4 shrink-0 opacity-50" />
<span class="search-text flex-1 min-w-0 text-left text-sm text-muted-foreground truncate">{{ <span class="search-text flex-1 min-w-0 text-left text-sm text-muted-foreground truncate">{{
t('side_panel.search_placeholder') t('side_panel.search_placeholder')
@@ -240,7 +240,7 @@
</TabsUnderline> </TabsUnderline>
<NotificationCenterSheet /> <NotificationCenterSheet />
<GroupOrderSheet v-model:open="isGroupOrderSheetOpen" /> <GroupOrderSheet v-model:open="isGroupOrderSheetOpen" />
<GlobalSearchDialog /> <QuickSearchDialog />
</div> </div>
</template> </template>
@@ -279,10 +279,10 @@
} from '../../stores'; } from '../../stores';
import { runRefreshFriendsListFlow } from '../../coordinators/friendSyncCoordinator'; import { runRefreshFriendsListFlow } from '../../coordinators/friendSyncCoordinator';
import { normalizeFavoriteGroupsChange, resolveFavoriteGroups } from './sidebarSettingsUtils'; import { normalizeFavoriteGroupsChange, resolveFavoriteGroups } from './sidebarSettingsUtils';
import { useGlobalSearchStore } from '../../stores/globalSearch'; import { useQuickSearchStore } from '../../stores/quickSearch';
import FriendsSidebar from './components/FriendsSidebar.vue'; import FriendsSidebar from './components/FriendsSidebar.vue';
import GlobalSearchDialog from '../../components/GlobalSearchDialog.vue'; import QuickSearchDialog from '../../components/QuickSearchDialog.vue';
import GroupOrderSheet from './components/GroupOrderSheet.vue'; import GroupOrderSheet from './components/GroupOrderSheet.vue';
import GroupsSidebar from './components/GroupsSidebar.vue'; import GroupsSidebar from './components/GroupsSidebar.vue';
import NotificationCenterSheet from './components/NotificationCenterSheet.vue'; import NotificationCenterSheet from './components/NotificationCenterSheet.vue';
@@ -291,21 +291,21 @@
const { groupInstances } = storeToRefs(useGroupStore()); const { groupInstances } = storeToRefs(useGroupStore());
const notificationStore = useNotificationStore(); const notificationStore = useNotificationStore();
const { isNotificationCenterOpen, hasUnseenNotifications } = storeToRefs(notificationStore); const { isNotificationCenterOpen, hasUnseenNotifications } = storeToRefs(notificationStore);
const globalSearchStore = useGlobalSearchStore(); const quickSearchStore = useQuickSearchStore();
const { t } = useI18n(); const { t } = useI18n();
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
// Keyboard shortcut: Ctrl+K (Windows) / ⌘K (Mac) // Keyboard shortcut: Ctrl+K (Windows) / ⌘K (Mac)
const keys = useMagicKeys(); const keys = useMagicKeys();
whenever(keys['Meta+k'], () => openGlobalSearch()); whenever(keys['Meta+k'], () => openQuickSearch());
whenever(keys['Ctrl+k'], () => openGlobalSearch()); whenever(keys['Ctrl+k'], () => openQuickSearch());
/** /**
* *
*/ */
function openGlobalSearch() { function openQuickSearch() {
globalSearchStore.open(); quickSearchStore.open();
} }
/** /**

View File

@@ -53,8 +53,8 @@ vi.mock('../../../stores', () => ({
localFriendFavoriteGroups: ref([]) localFriendFavoriteGroups: ref([])
}) })
})); }));
vi.mock('../../../stores/globalSearch', () => ({ vi.mock('../../../stores/quickSearch', () => ({
useGlobalSearchStore: () => ({ open: (...a) => mocks.openSearch(...a) }) useQuickSearchStore: () => ({ open: (...a) => mocks.openSearch(...a) })
})); }));
vi.mock('../../../coordinators/friendSyncCoordinator', () => ({ vi.mock('../../../coordinators/friendSyncCoordinator', () => ({
runRefreshFriendsListFlow: (...a) => mocks.refreshFriends(...a) runRefreshFriendsListFlow: (...a) => mocks.refreshFriends(...a)
@@ -135,7 +135,7 @@ vi.mock('../components/GroupOrderSheet.vue', () => ({
vi.mock('../components/NotificationCenterSheet.vue', () => ({ vi.mock('../components/NotificationCenterSheet.vue', () => ({
default: { template: '<div />' } default: { template: '<div />' }
})); }));
vi.mock('../../../components/GlobalSearchDialog.vue', () => ({ vi.mock('../../../components/QuickSearchDialog.vue', () => ({
default: { template: '<div />' } default: { template: '<div />' }
})); }));
@@ -147,7 +147,7 @@ describe('Sidebar.vue', () => {
mocks.markAllAsSeen.mockClear(); mocks.markAllAsSeen.mockClear();
}); });
it('opens global search and marks notifications read', async () => { it('opens quick search and marks notifications read', async () => {
const wrapper = mount(Sidebar); const wrapper = mount(Sidebar);
const buttons = wrapper.findAll('button'); const buttons = wrapper.findAll('button');
for (const button of buttons) { for (const button of buttons) {