#12 topbar search (#371)

- added search in topbar
 - added skeleton search results page
 - added tests
 - set personal calendars as default search in and allow to select personal and shared as a search in option

---------

Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
Camille Moussu
2025-11-28 14:54:13 +01:00
committed by GitHub
parent 1a85afc57d
commit ae17ac2bd6
20 changed files with 1508 additions and 152 deletions
@@ -3,6 +3,7 @@ import {
moveEvent,
deleteEvent,
importEventFromFile,
searchEvent,
} from "../../../src/features/Events/EventApi";
import { CalendarEvent } from "../../../src/features/Events/EventsTypes";
import { calendarEventToJCal } from "../../../src/features/Events/eventUtils";
@@ -178,4 +179,95 @@ describe("eventApi", () => {
})
);
});
describe("searchEvent", () => {
const mockFilters = {
searchIn: ["user1/calendar1", "user2/calendar2"],
keywords: "meeting",
organizers: ["org@example.com"],
attendees: ["part@example.com"],
};
it("should call API with correct parameters", async () => {
const mockResponse = {
_total_hits: 5,
_embedded: { events: [] },
};
(api.post as jest.Mock).mockReturnValue({
json: jest.fn().mockResolvedValue(mockResponse),
});
await searchEvent("test", mockFilters);
expect(api.post).toHaveBeenCalledWith(
"calendar/api/events/search?limit=30&offset=0",
{
body: JSON.stringify({
query: "meeting",
calendars: [
{ calendarId: "calendar1", userId: "user1" },
{ calendarId: "calendar2", userId: "user2" },
],
organizers: ["org@example.com"],
attendees: ["part@example.com"],
}),
}
);
});
it("should use query param when keywords is empty", async () => {
const mockResponse = { _total_hits: 0, _embedded: { events: [] } };
(api.post as jest.Mock).mockReturnValue({
json: jest.fn().mockResolvedValue(mockResponse),
});
await searchEvent("fallback query", {
...mockFilters,
keywords: "",
});
expect(api.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
body: expect.stringContaining('"query":"fallback query"'),
})
);
});
it("should omit organizers when empty", async () => {
const mockResponse = { _total_hits: 0, _embedded: { events: [] } };
(api.post as jest.Mock).mockReturnValue({
json: jest.fn().mockResolvedValue(mockResponse),
});
await searchEvent("test", {
...mockFilters,
organizers: [],
});
const callArgs = (api.post as jest.Mock).mock.calls[0][1];
const body = JSON.parse(callArgs.body);
expect(body.organizers).toBeUndefined();
});
it("should omit participants when empty", async () => {
const mockResponse = { _total_hits: 0, _embedded: { events: [] } };
(api.post as jest.Mock).mockReturnValue({
json: jest.fn().mockResolvedValue(mockResponse),
});
await searchEvent("test", {
...mockFilters,
attendees: [],
});
const callArgs = (api.post as jest.Mock).mock.calls[0][1];
const body = JSON.parse(callArgs.body);
expect(body.participants).toBeUndefined();
});
});
});