mirror of
https://github.com/vector-im/element-web.git
synced 2025-11-28 22:11:41 +01:00
print better errors in the search view instead of a blocking modal (#29724)
* print better errors in the search view instead of a blocking modal * update tests and i18n * fix unused variable * fix unused variable again
This commit is contained in:
parent
7ce0a76414
commit
475e449e81
@ -718,4 +718,8 @@ export interface SearchInfo {
|
||||
* The total count of matching results as returned by the backend.
|
||||
*/
|
||||
count?: number;
|
||||
/**
|
||||
* Describe the error if any occured.
|
||||
*/
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
@ -21,8 +21,6 @@ import { _t } from "../../languageHandler";
|
||||
import { haveRendererForEvent } from "../../events/EventTileFactory";
|
||||
import SearchResultTile from "../views/rooms/SearchResultTile";
|
||||
import { searchPagination, SearchScope } from "../../Searching";
|
||||
import Modal from "../../Modal";
|
||||
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
||||
import type ResizeNotifier from "../../utils/ResizeNotifier";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
|
||||
@ -45,7 +43,7 @@ interface Props {
|
||||
abortController?: AbortController;
|
||||
resizeNotifier: ResizeNotifier;
|
||||
className: string;
|
||||
onUpdate(inProgress: boolean, results: ISearchResults | null): void;
|
||||
onUpdate(inProgress: boolean, results: ISearchResults | null, error: Error | null): void;
|
||||
}
|
||||
|
||||
// XXX: todo: merge overlapping results somehow?
|
||||
@ -70,7 +68,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
|
||||
const handleSearchResult = useCallback(
|
||||
(searchPromise: Promise<ISearchResults>): Promise<boolean> => {
|
||||
onUpdate(true, null);
|
||||
onUpdate(true, null, null);
|
||||
|
||||
return searchPromise.then(
|
||||
async (results): Promise<boolean> => {
|
||||
@ -116,7 +114,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
|
||||
setHighlights(highlights);
|
||||
setResults({ ...results }); // copy to force a refresh
|
||||
onUpdate(false, results);
|
||||
onUpdate(false, results, null);
|
||||
return false;
|
||||
},
|
||||
(error) => {
|
||||
@ -125,11 +123,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
|
||||
return false;
|
||||
}
|
||||
logger.error("Search failed", error);
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("error_dialog|search_failed|title"),
|
||||
description: error?.message ?? _t("error_dialog|search_failed|server_unavailable"),
|
||||
});
|
||||
onUpdate(false, null);
|
||||
onUpdate(false, null, error);
|
||||
return false;
|
||||
},
|
||||
);
|
||||
|
||||
@ -1716,11 +1716,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.onSearch(this.state.search?.term ?? "", scope);
|
||||
};
|
||||
|
||||
private onSearchUpdate = (inProgress: boolean, searchResults: ISearchResults | null): void => {
|
||||
private onSearchUpdate = (inProgress: boolean, searchResults: ISearchResults | null, error: Error | null): void => {
|
||||
this.setState({
|
||||
search: {
|
||||
...this.state.search!,
|
||||
count: searchResults?.count,
|
||||
error: error ?? undefined,
|
||||
inProgress,
|
||||
},
|
||||
});
|
||||
|
||||
@ -40,6 +40,8 @@ const RoomSearchAuxPanel: React.FC<Props> = ({ searchInfo, isRoomEncrypted, onSe
|
||||
{ count: searchInfo.count },
|
||||
{ query: () => <strong>{searchInfo.term}</strong> },
|
||||
)
|
||||
) : searchInfo?.error !== undefined ? (
|
||||
searchInfo?.error.message
|
||||
) : (
|
||||
<InlineSpinner />
|
||||
)}
|
||||
|
||||
@ -1133,11 +1133,7 @@
|
||||
"title": "Unable to copy room link"
|
||||
},
|
||||
"error_loading_user_profile": "Could not load user profile",
|
||||
"forget_room_failed": "Failed to forget room %(errCode)s",
|
||||
"search_failed": {
|
||||
"server_unavailable": "Server may be unavailable, overloaded, or search timed out :(",
|
||||
"title": "Search failed"
|
||||
}
|
||||
"forget_room_failed": "Failed to forget room %(errCode)s"
|
||||
},
|
||||
"error_user_not_logged_in": "User is not logged in",
|
||||
"event_preview": {
|
||||
|
||||
@ -247,7 +247,7 @@ describe("<RoomSearchView/>", () => {
|
||||
|
||||
await screen.findByRole("progressbar");
|
||||
await screen.findByText("Potato");
|
||||
expect(onUpdate).toHaveBeenCalledWith(false, expect.objectContaining({}));
|
||||
expect(onUpdate).toHaveBeenCalledWith(false, expect.objectContaining({}), null);
|
||||
|
||||
rerender(
|
||||
<MatrixClientContext.Provider value={client}>
|
||||
@ -314,7 +314,8 @@ describe("<RoomSearchView/>", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should show modal if error is encountered", async () => {
|
||||
it("report error if one is encountered", async () => {
|
||||
const onUpdate = jest.fn();
|
||||
const deferred = defer<ISearchResults>();
|
||||
|
||||
render(
|
||||
@ -326,14 +327,18 @@ describe("<RoomSearchView/>", () => {
|
||||
promise={deferred.promise}
|
||||
resizeNotifier={resizeNotifier}
|
||||
className="someClass"
|
||||
onUpdate={jest.fn()}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</MatrixClientContext.Provider>,
|
||||
);
|
||||
deferred.reject(new Error("Some error"));
|
||||
deferred.reject("Some error");
|
||||
try {
|
||||
// Wait for RoomSearchView to process the promise
|
||||
await deferred.promise;
|
||||
} catch {}
|
||||
|
||||
await screen.findByText("Search failed");
|
||||
await screen.findByText("Some error");
|
||||
expect(onUpdate).toHaveBeenCalledWith(false, null, "Some error");
|
||||
expect(onUpdate).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("should combine search results when the query is present in multiple sucessive messages", async () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user