Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/common/misc/TranslationKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2246,3 +2246,5 @@ export type TranslationKeyType =
| "emptyString_msg"
| "oneConversationSelected_msg"
| "nbrOfConversationsSelected_msg"
| "reIndexLocalData_msg"
| "rebuildSearchIndex_action"
21 changes: 21 additions & 0 deletions src/mail-app/settings/MailSettingsViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { elementIdPart } from "../../common/api/common/utils/EntityUtils.js"
import { DatePicker, DatePickerAttrs } from "../../calendar-app/calendar/gui/pickers/DatePicker"
import { OfflineStorageSettingsModel } from "../../common/offline/OfflineStorageSettingsModel"
import { client } from "../../common/misc/ClientDetector"
import { LoginButton } from "../../common/gui/base/buttons/LoginButton"

assertMainOrNode()

Expand Down Expand Up @@ -446,8 +447,28 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
}),
],
}),
this.renderClearLocalDataButton(),
]
}
private renderClearLocalDataButton() {
return m(
".flex-start",
m(
".mt-16",
m(LoginButton, {
label: "rebuildSearchIndex_action",
onclick: () => this.confirmClearData(),
}),
),
)
}

private async confirmClearData(): Promise<void> {
const confirm = await Dialog.confirm("reIndexLocalData_msg")
if (confirm) {
await mailLocator.indexerFacade.rebuildMailIndex()
}
}

private async onEditStoredDataTimeRangeClicked() {
if (mailLocator.logins.getUserController().isFreeAccount()) {
Expand Down
4 changes: 3 additions & 1 deletion src/mail-app/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,8 @@ export default {
"yourFolders_action": "DEINE ORDNER",
"yourMessage_label": "Deine Nachricht",
"zoomIn_action": "Hereinzoomen",
"zoomOut_action": "Herauszoomen"
"zoomOut_action": "Herauszoomen",
"reIndexLocalData_msg": "This will re-index all emails up to the current maximum storage date. This may be useful if you are missing emails in search.\n\nThis will be done in the background and may take some time.",
"rebuildSearchIndex_action": "Rebuild search index"
}
}
4 changes: 3 additions & 1 deletion src/mail-app/translations/de_sie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,8 @@ export default {
"yourFolders_action": "Ihre ORDNER",
"yourMessage_label": "Ihre Nachricht",
"zoomIn_action": "Hereinzoomen",
"zoomOut_action": "Herauszoomen"
"zoomOut_action": "Herauszoomen",
"reIndexLocalData_msg": "This will re-index all emails up to the current maximum storage date. This may be useful if you are missing emails in search.\n\nThis will be done in the background and may take some time.",
"rebuildSearchIndex_action": "Rebuild search index"
}
}
4 changes: 3 additions & 1 deletion src/mail-app/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,8 @@ export default {
"yourFolders_action": "YOUR FOLDERS",
"yourMessage_label": "Your message",
"zoomIn_action": "Zoom In",
"zoomOut_action": "Zoom Out"
"zoomOut_action": "Zoom Out",
"reIndexLocalData_msg": "This will re-index all emails up to the current maximum storage date. This may be useful if you are missing emails in search.\n\nThis will be done in the background and may take some time.",
"rebuildSearchIndex_action": "Rebuild search index"
}
}
4 changes: 4 additions & 0 deletions src/mail-app/workerUtils/index/IndexedDbIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -699,4 +699,8 @@ export class IndexedDbIndexer implements Indexer {
async resizeMailIndex(_: number) {
throw new ProgrammingError("resizeMailIndex can only be called with offline storage")
}

async rebuildMailIndex() {
await this.mailIndexer.rebuildIndex(this.initParams.user)
}
}
4 changes: 4 additions & 0 deletions src/mail-app/workerUtils/index/IndexedDbMailIndexerBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,8 @@ export class IndexedDbMailIndexerBackend implements MailIndexerBackend {
truncateAllCurrentIndexTimestamps(_newTimestamp: number): Promise<void> {
throw new ProgrammingError("truncateAllCurrentIndexTimestamps can only be called with offline storage")
}

async resetIndex() {
throw new ProgrammingError("resetIndex can only be called with offline storage")
}
}
2 changes: 2 additions & 0 deletions src/mail-app/workerUtils/index/Indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ export interface Indexer {

deleteIndex(userId: string): Promise<void>

rebuildMailIndex(): Promise<void>

cancelMailIndexing(): void
}
15 changes: 14 additions & 1 deletion src/mail-app/workerUtils/index/MailIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
MailDetails,
MailDetailsBlobTypeRef,
MailDetailsDraftTypeRef,
MailSetTypeRef,
MailSetEntry,
MailSetEntryTypeRef,
MailSetTypeRef,
MailTypeRef,
} from "../../../common/api/entities/tutanota/TypeRefs.js"
import { ConnectionError, NotAuthorizedError, NotFoundError } from "../../../common/api/common/error/RestError.js"
Expand Down Expand Up @@ -654,6 +654,19 @@ export class MailIndexer {
private get backend(): MailIndexerBackend {
return assertNotNull(this._backend)
}

async rebuildIndex(user: User) {
if (!this._mailIndexingEnabled) {
return
}
if (this._isIndexing) {
this.cancelMailIndexing()
}
const currentIndexTimestamp = this._currentIndexTimestamp
await this.backend.resetIndex()
await this.updateCurrentIndexTimestamp(user)
await this.indexMailboxes(user, currentIndexTimestamp)
}
}

// Given all index timestamps find a common denominator.
Expand Down
2 changes: 2 additions & 0 deletions src/mail-app/workerUtils/index/MailIndexerBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ export interface MailIndexerBackend {
enableIndexing(): Promise<void>

isMailIndexingEnabled(): Promise<boolean>

resetIndex(): Promise<void>
}
4 changes: 4 additions & 0 deletions src/mail-app/workerUtils/index/OfflineStorageIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,8 @@ export class OfflineStorageIndexer implements Indexer {
cancelMailIndexing() {
this.mailIndexer.cancelMailIndexing()
}

async rebuildMailIndex() {
await this.mailIndexer.rebuildIndex(assertNotNull(this.userFacade.getUser()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ export class OfflineStorageMailIndexerBackend implements MailIndexerBackend {
async onBeforeMailDeleted(mailId: IdTuple): Promise<void> {
await this.persistence.deleteMailData(mailId)
}

async resetIndex() {
await this.persistence.resetMailIndex()
}
}
21 changes: 20 additions & 1 deletion src/mail-app/workerUtils/index/OfflineStoragePersistence.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SqlCipherFacade } from "../../../common/native/common/generatedipc/SqlCipherFacade"
import { sql } from "../../../common/api/worker/offline/Sql"
import { SqlValue, untagSqlObject, untagSqlValue } from "../../../common/api/worker/offline/SqlValue"
import { GroupType } from "../../../common/api/common/TutanotaConstants"
import { GroupType, NOTHING_INDEXED_TIMESTAMP } from "../../../common/api/common/TutanotaConstants"
import { MailWithDetailsAndAttachments } from "./MailIndexerBackend"
import { getTypeString, TypeRef } from "@tutao/tutanota-utils"
import { Contact, ContactTypeRef, Mail, MailAddress, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
Expand Down Expand Up @@ -265,6 +265,25 @@ export class OfflineStoragePersistence {
}
return untagSqlObject(rowIdResult).rowid
}

async resetMailIndex() {
{
const { query, params } = sql`UPDATE search_group_data
SET indexedTimestamp = ${NOTHING_INDEXED_TIMESTAMP}
WHERE groupType = ${GroupType.Mail}`
await this.sqlCipherFacade.run(query, params)
}
{
const { query, params } = sql`DELETE
FROM mail_index`
await this.sqlCipherFacade.run(query, params)
}
{
const { query, params } = sql`DELETE
FROM content_mail_index`
await this.sqlCipherFacade.run(query, params)
}
}
}

function serializeMailAddresses(recipients: readonly MailAddress[]): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,9 @@ o.spec("OfflineStorageMailIndexerBackend", function () {

verify(persistence.deleteMailData(mailId))
})

o.test("resetIndex", async function () {
await backend.resetIndex()
verify(persistence.resetMailIndex())
})
})
Loading