Skip to content

Commit

Permalink
UI for Export mailbox in settings
Browse files Browse the repository at this point in the history
close: #7952

Co-authored-by: ivk <[email protected]>
  • Loading branch information
BijinDev and charlag committed Nov 21, 2024
1 parent a4f8354 commit 310ccc0
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 8 deletions.
9 changes: 5 additions & 4 deletions src/common/misc/TranslationKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1800,7 +1800,8 @@ export type TranslationKeyType =
| "yourMessage_label"
| "you_label"
| "emptyString_msg"
| "editLabel_action"
| "importantLabel_label"
| "labelLimitExceeded_msg"
| "confirmDeleteLabel_msg"
| "exportMailbox_label"
| "mailboxToExport_label"
| "lastExportTime_Label"
| "exportingEmails_label"
| "mailsExported_label"
46 changes: 46 additions & 0 deletions src/mail-app/mail/model/MailExportController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { MailboxDetail } from "../../../common/mailFunctionality/MailboxModel"
import Stream from "mithril/stream"
import stream from "mithril/stream"

export type MailExportState =
| { type: "idle"; lastExport: Date | null }
| { type: "exporting"; mailbox: MailboxDetail; progress: number; exportedMails: number }
| {
type: "finished"
mailbox: MailboxDetail
exportedMails: number
}

export class MailExportController {
private _state: Stream<MailExportState> = stream({ type: "idle", lastExport: new Date() })
private progressTimeout: number | null = null

get state(): Stream<MailExportState> {
return this._state
}

startExport(mailbox: MailboxDetail) {
this._state({ type: "exporting", mailbox: mailbox, progress: 0, exportedMails: 0 })
this.progressTimeout = window.setInterval(() => {
const oldState = this._state()
if (oldState.type === "exporting") {
if (oldState.progress >= 0.9) {
this._state({ type: "finished", mailbox: mailbox, exportedMails: oldState.exportedMails })
} else {
this._state({
...oldState,
progress: oldState.progress + 0.1,
exportedMails: oldState.exportedMails + 100,
})
}
}
}, 1000)
}

cancelExport() {
if (this.progressTimeout) {
clearInterval(this.progressTimeout)
this.progressTimeout = null
}
}
}
5 changes: 5 additions & 0 deletions src/mail-app/mailLocator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import type { CalendarContactPreviewViewModel } from "../calendar-app/calendar/g
import { KeyLoaderFacade } from "../common/api/worker/facades/KeyLoaderFacade.js"
import { MobileContactSuggestionProvider } from "../common/native/main/MobileContactSuggestionProvider"
import { ContactSuggestion } from "../common/native/common/generatedipc/ContactSuggestion"
import { MailExportController } from "./mail/model/MailExportController"

assertMainOrNode()

Expand Down Expand Up @@ -1167,6 +1168,10 @@ class MailLocator {
return this.loginFacade.migrateKdfType(KdfType.Bcrypt, passphrase, currentUser)
}

mailExportController: () => Promise<MailExportController> = lazyMemoized(async () => {
return new MailExportController()
})

/**
* Factory method for credentials provider that will return an instance injected with the implementations appropriate for the platform.
*/
Expand Down
124 changes: 124 additions & 0 deletions src/mail-app/settings/MailExportSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import m, { Children, Component, Vnode } from "mithril"
import { lang } from "../../common/misc/LanguageViewModel"
import { theme } from "../../common/gui/theme"
import { px } from "../../common/gui/size"
import { ProgressBar } from "../../common/gui/base/ProgressBar"
import { DropDownSelector, type DropDownSelectorAttrs } from "../../common/gui/base/DropDownSelector"
import { MailboxDetail } from "../../common/mailFunctionality/MailboxModel"
import { getMailboxName } from "../../common/mailFunctionality/SharedMailUtils"
import { mailLocator } from "../mailLocator"
import { first } from "@tutao/tutanota-utils"
import { LoginController } from "../../common/api/main/LoginController"
import { Button, ButtonType } from "../../common/gui/base/Button"
import { MailExportController } from "../mail/model/MailExportController"
import { formatDate } from "../../common/misc/Formatter"
import Stream from "mithril/stream"

interface MailExportSettingsAttrs {
mailboxDetails: MailboxDetail[]
logins: LoginController
mailExportController: MailExportController
}

export class MailExportSettings implements Component<MailExportSettingsAttrs> {
private selectedMailbox: MailboxDetail | null = null
private controllerSubscription: Stream<void> | null = null

oncreate(vnode: Vnode<MailExportSettingsAttrs>) {
this.controllerSubscription = vnode.attrs.mailExportController.state.map(m.redraw)
}

onremove() {
if (this.controllerSubscription) {
this.controllerSubscription.end()
this.controllerSubscription = null
}
}

view(vnode: Vnode<MailExportSettingsAttrs>): Children {
const { mailboxDetails } = vnode.attrs
this.selectedMailbox = this.selectedMailbox ?? first(mailboxDetails)
const state = vnode.attrs.mailExportController.state()
return [
m(DropDownSelector, {
label: "mailboxToExport_label",
items: mailboxDetails.map((mailboxDetail) => {
return { name: getMailboxName(mailLocator.logins, mailboxDetail), value: mailboxDetail }
}),
selectedValue: this.selectedMailbox,
selectionChangedHandler: (selectedMailbox) => {
this.selectedMailbox = selectedMailbox
},
dropdownWidth: 300,
disabled: state.type === "exporting",
} satisfies DropDownSelectorAttrs<MailboxDetail>),
state.type === "exporting"
? [
m(".flex-space-between.items-center.mt.mb-s", [
m(".flex-grow.mr", [
m(
"small.noselect",
lang.get("exportingEmails_label", {
"{count}": state.exportedMails,
}),
),
m(
".rel.full-width.mt-s",
{
style: {
"background-color": theme.content_border,
height: px(2),
},
},
m(ProgressBar, { progress: state.progress }),
),
]),
m(Button, {
label: "cancel_action",
type: ButtonType.Secondary,
click: () => {
vnode.attrs.mailExportController.cancelExport()
},
}),
]),
]
: state.type === "idle"
? [
m(".flex-space-between.items-center.mt.mb-s", [
m(
"small.noselect",
state.lastExport
? lang.get("lastExportTime_Label", {
"{date}": formatDate(state.lastExport),
})
: null,
),
m(Button, {
label: "export_action",
click: () => {
if (this.selectedMailbox) {
vnode.attrs.mailExportController.startExport(this.selectedMailbox)
}
},
type: ButtonType.Secondary,
}),
]),
]
: [
m(".flex-space-between.items-center.mt.mb-s", [
m(
"small.noselect",
lang.get("mailsExported_label", {
"{numbers}": state.exportedMails,
}),
),
m(Button, {
label: "open_action",
click: () => {},
type: ButtonType.Secondary,
}),
]),
],
]
}
}
15 changes: 15 additions & 0 deletions src/mail-app/settings/MailSettingsViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import { UpdatableSettingsViewer } from "../../common/settings/Interfaces.js"
import { mailLocator } from "../mailLocator.js"
import { getDefaultSenderFromUser, getFolderName } from "../mail/model/MailUtils.js"
import { elementIdPart } from "../../common/api/common/utils/EntityUtils.js"
import { MailExportSettings } from "./MailExportSettings"
import { MailExportController } from "../mail/model/MailExportController"

assertMainOrNode()

Expand All @@ -70,6 +72,7 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
private customerInfo: CustomerInfo | null
private mailAddressTableModel: MailAddressTableModel | null = null
private mailAddressTableExpanded: boolean
private mailExportController: MailExportController | null = null

private offlineStorageSettings = new OfflineStorageSettingsModel(mailLocator.logins.getUserController(), deviceConfig)

Expand All @@ -87,6 +90,10 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
this._inboxRulesTableLines = stream<Array<TableLineAttrs>>([])
this._outOfOfficeStatus = stream(lang.get("deactivated_label"))
this._indexStateWatch = null
mailLocator.mailExportController().then((controller) => {
this.mailExportController = controller
m.redraw()
})
// normally we would maybe like to get it as an argument but these viewers are created in an odd way
mailLocator.mailAddressTableModelForOwnMailbox().then((model) => {
this.mailAddressTableModel = model
Expand Down Expand Up @@ -382,6 +389,14 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
}),
),
],
m(".h4.mt-l", lang.get("exportMailbox_label")),
this.mailExportController
? m(MailExportSettings, {
mailboxDetails: mailLocator.mailboxModel.mailboxDetails(),
logins: mailLocator.logins,
mailExportController: this.mailExportController,
})
: null,
],
),
]
Expand Down
7 changes: 6 additions & 1 deletion src/mail-app/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1820,6 +1820,11 @@ export default {
"yourFolders_action": "DEINE ORDNER",
"yourMessage_label": "Deine Nachricht",
"you_label": "Du",
"confirmDeleteLabel_msg": "Möchtest du wirklich das Label \"{1}\" löschen?"
"confirmDeleteLabel_msg": "Möchtest du wirklich das Label \"{1}\" löschen?",
"exportMailbox_label": "",
"mailboxToExport_label": "",
"lastExportTime_Label": "",
"exportingEmails_label": "",
"mailsExported_label": "",
}
}
9 changes: 7 additions & 2 deletions src/mail-app/translations/de_sie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1819,7 +1819,12 @@ export default {
"yourCalendars_label": "Deine Kalender",
"yourFolders_action": "Ihre ORDNER",
"yourMessage_label": "Ihre Nachricht",
"you_label": "Sie",
"confirmDeleteLabel_msg": "Möchten Sie wirklich das Label \"{1}\" löschen?"
"you_label": "Sie",
"confirmDeleteLabel_msg": "Möchten Sie wirklich das Label \"{1}\" löschen?",
"exportMailbox_label": "",
"mailboxToExport_label": "",
"lastExportTime_Label": "",
"exportingEmails_label": "",
"mailsExported_label": "",
}
}
7 changes: 6 additions & 1 deletion src/mail-app/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1816,6 +1816,11 @@ export default {
"yourFolders_action": "YOUR FOLDERS",
"yourMessage_label": "Your message",
"you_label": "You",
"confirmDeleteLabel_msg": "Are you sure that you want to delete the label \"{1}\"?"
"confirmDeleteLabel_msg": "Are you sure that you want to delete the label \"{1}\"?",
"exportMailbox_label": "Export Mailbox",
"mailboxToExport_label": "Mailbox to Export",
"lastExportTime_Label": "Last export: {date}",
"exportingEmails_label": "Exporting emails: {count}",
"mailsExported_label": "Emails exported: {numbers}",
}
}

0 comments on commit 310ccc0

Please sign in to comment.