Merge branch 'searchFixTakeTwo'

This commit is contained in:
Reto Brunner 2023-01-22 15:22:32 +01:00
commit 7f3ac62e0d
8 changed files with 59 additions and 46 deletions

View file

@ -33,18 +33,19 @@
<button <button
ref="loadMoreButton" ref="loadMoreButton"
:disabled=" :disabled="
store.state.messageSearchInProgress || !store.state.isConnected !!store.state.messageSearchPendingQuery ||
!store.state.isConnected
" "
class="btn" class="btn"
@click="onShowMoreClick" @click="onShowMoreClick"
> >
<span v-if="store.state.messageSearchInProgress">Loading</span> <span v-if="store.state.messageSearchPendingQuery">Loading</span>
<span v-else>Show older messages</span> <span v-else>Show older messages</span>
</button> </button>
</div> </div>
<div <div
v-if="store.state.messageSearchInProgress && !offset" v-if="store.state.messageSearchPendingQuery && !offset"
class="search-status" class="search-status"
> >
Searching Searching
@ -105,6 +106,7 @@ import type {ClientMessage} from "../../js/types";
import {useStore} from "../../js/store"; import {useStore} from "../../js/store";
import {useRoute, useRouter} from "vue-router"; import {useRoute, useRouter} from "vue-router";
import {switchToChannel} from "../../js/router"; import {switchToChannel} from "../../js/router";
import {SearchQuery} from "../../../server/plugins/messageStorage/types";
export default defineComponent({ export default defineComponent({
name: "SearchResults", name: "SearchResults",
@ -187,37 +189,44 @@ export default defineComponent({
const clearSearchState = () => { const clearSearchState = () => {
offset.value = 0; offset.value = 0;
store.commit("messageSearchInProgress", false);
store.commit("messageSearchResults", null); store.commit("messageSearchResults", null);
store.commit("messageSearchPendingQuery", null);
}; };
const doSearch = () => { const doSearch = () => {
if (!network.value || !channel.value) {
return;
}
clearSearchState(); // this is a new search, so we need to clear anything before that clearSearchState(); // this is a new search, so we need to clear anything before that
socket.emit("search", { const query: SearchQuery = {
networkUuid: network.value?.uuid, networkUuid: network.value.uuid,
channelName: channel.value?.name, channelName: channel.value.name,
searchTerm: String(route.query.q || ""), searchTerm: String(route.query.q || ""),
offset: offset.value, offset: offset.value,
}); };
store.commit("messageSearchPendingQuery", query);
socket.emit("search", query);
}; };
const onShowMoreClick = () => { const onShowMoreClick = () => {
if (!chat.value) { if (!chat.value || !network.value || !channel.value) {
return; return;
} }
offset.value += 100; offset.value += 100;
store.commit("messageSearchInProgress", true);
oldScrollTop.value = chat.value.scrollTop; oldScrollTop.value = chat.value.scrollTop;
oldChatHeight.value = chat.value.scrollHeight; oldChatHeight.value = chat.value.scrollHeight;
socket.emit("search", { const query: SearchQuery = {
networkUuid: network.value?.uuid, networkUuid: network.value.uuid,
channelName: channel.value?.name, channelName: channel.value.name,
searchTerm: String(route.query.q || ""), searchTerm: String(route.query.q || ""),
offset: offset.value, offset: offset.value,
}); };
store.commit("messageSearchPendingQuery", query);
socket.emit("search", query);
}; };
const jumpToBottom = async () => { const jumpToBottom = async () => {

View file

@ -2,12 +2,27 @@ import socket from "../socket";
import {store} from "../store"; import {store} from "../store";
socket.on("search:results", (response) => { socket.on("search:results", (response) => {
store.commit("messageSearchInProgress", false); const pendingQuery = store.state.messageSearchPendingQuery;
if (
!pendingQuery ||
pendingQuery.channelName !== response.channelName ||
pendingQuery.networkUuid !== response.networkUuid ||
pendingQuery.offset !== response.offset ||
pendingQuery.searchTerm !== response.searchTerm
) {
// This is a response from a search that we are not interested in.
// The user may have entered a different search while one was still in flight.
// We can simply drop it on the floor.
return;
}
store.commit("messageSearchPendingQuery", null);
if (store.state.messageSearchResults) { if (store.state.messageSearchResults) {
store.commit("addMessageSearchResults", response); store.commit("addMessageSearchResults", response);
return; return;
} }
store.commit("messageSearchResults", response); store.commit("messageSearchResults", {results: response.results});
}); });

View file

@ -15,6 +15,7 @@ import type {
import type {InjectionKey} from "vue"; import type {InjectionKey} from "vue";
import {SettingsState} from "./settings"; import {SettingsState} from "./settings";
import {SearchQuery} from "../../server/plugins/messageStorage/types";
const appName = document.title; const appName = document.title;
@ -85,7 +86,7 @@ export type State = {
messageSearchResults: { messageSearchResults: {
results: ClientMessage[]; results: ClientMessage[];
} | null; } | null;
messageSearchInProgress: boolean; messageSearchPendingQuery: SearchQuery | null;
searchEnabled: boolean; searchEnabled: boolean;
}; };
@ -111,7 +112,7 @@ const state = () =>
versionDataExpired: false, versionDataExpired: false,
serverHasSettings: false, serverHasSettings: false,
messageSearchResults: null, messageSearchResults: null,
messageSearchInProgress: false, messageSearchPendingQuery: null,
searchEnabled: false, searchEnabled: false,
} as State); } as State);
@ -260,7 +261,7 @@ type Mutations = {
versionStatus(state: State, payload: State["versionStatus"]): void; versionStatus(state: State, payload: State["versionStatus"]): void;
versionDataExpired(state: State, payload: State["versionDataExpired"]): void; versionDataExpired(state: State, payload: State["versionDataExpired"]): void;
serverHasSettings(state: State, value: State["serverHasSettings"]): void; serverHasSettings(state: State, value: State["serverHasSettings"]): void;
messageSearchInProgress(state: State, value: State["messageSearchInProgress"]): void; messageSearchPendingQuery(state: State, value: State["messageSearchPendingQuery"]): void;
messageSearchResults(state: State, value: State["messageSearchResults"]): void; messageSearchResults(state: State, value: State["messageSearchResults"]): void;
addMessageSearchResults(state: State, value: NonNullable<State["messageSearchResults"]>): void; addMessageSearchResults(state: State, value: NonNullable<State["messageSearchResults"]>): void;
}; };
@ -338,8 +339,8 @@ const mutations: Mutations = {
serverHasSettings(state, value) { serverHasSettings(state, value) {
state.serverHasSettings = value; state.serverHasSettings = value;
}, },
messageSearchInProgress(state, value) { messageSearchPendingQuery(state, value) {
state.messageSearchInProgress = value; state.messageSearchPendingQuery = value;
}, },
messageSearchResults(state, value) { messageSearchResults(state, value) {
state.messageSearchResults = value; state.messageSearchResults = value;

View file

@ -17,7 +17,7 @@ import SqliteMessageStorage from "./plugins/messageStorage/sqlite";
import TextFileMessageStorage from "./plugins/messageStorage/text"; import TextFileMessageStorage from "./plugins/messageStorage/text";
import Network, {IgnoreListItem, NetworkWithIrcFramework} from "./models/network"; import Network, {IgnoreListItem, NetworkWithIrcFramework} from "./models/network";
import ClientManager from "./clientManager"; import ClientManager from "./clientManager";
import {MessageStorage, SearchQuery} from "./plugins/messageStorage/types"; import {MessageStorage, SearchQuery, SearchResponse} from "./plugins/messageStorage/types";
type OrderItem = Chan["id"] | Network["uuid"]; type OrderItem = Chan["id"] | Network["uuid"];
type Order = OrderItem[]; type Order = OrderItem[];
@ -618,15 +618,12 @@ class Client {
} }
} }
search(query: SearchQuery) { async search(query: SearchQuery): Promise<SearchResponse> {
if (!this.messageProvider?.isEnabled) { if (!this.messageProvider?.isEnabled) {
return Promise.resolve({ return {
...query,
results: [], results: [],
target: "", };
networkUuid: "",
offset: 0,
searchTerm: query?.searchTerm,
});
} }
return this.messageProvider.search(query); return this.messageProvider.search(query);

View file

@ -259,15 +259,10 @@ class SqliteMessageStorage implements ISqliteMessageStorage {
params.push(query.offset); params.push(query.offset);
const rows = await this.serialize_fetchall(select, ...params); const rows = await this.serialize_fetchall(select, ...params);
const response: SearchResponse = { return {
searchTerm: query.searchTerm, ...query,
target: query.channelName,
networkUuid: query.networkUuid,
offset: query.offset,
results: parseSearchRowsToMessages(query.offset, rows).reverse(), results: parseSearchRowsToMessages(query.offset, rows).reverse(),
}; };
return response;
} }
canProvideMessages() { canProvideMessages() {

View file

@ -29,12 +29,9 @@ export type SearchQuery = {
offset: number; offset: number;
}; };
export type SearchResponse = export type SearchResponse = SearchQuery & {
| Omit<SearchQuery, "channelName" | "offset"> & { results: Message[];
results: Message[]; };
target: string;
offset: number;
};
type SearchFunction = (query: SearchQuery) => Promise<SearchResponse>; type SearchFunction = (query: SearchQuery) => Promise<SearchResponse>;

View file

@ -760,9 +760,8 @@ function initializeClient(
}); });
socket.on("search", async (query) => { socket.on("search", async (query) => {
await client.search(query).then((results) => { const results = await client.search(query);
socket.emit("search:results", results); socket.emit("search:results", results);
});
}); });
socket.on("mute:change", ({target, setMutedTo}) => { socket.on("mute:change", ({target, setMutedTo}) => {

View file

@ -107,7 +107,7 @@ interface ServerToClientEvents {
token: string; token: string;
}) => void; }) => void;
"search:results": (response: {results: ClientMessage[]}) => void; "search:results": (response: SearchResponse) => void;
quit: (args: {network: string}) => void; quit: (args: {network: string}) => void;