Skip to content

Commit 589a731

Browse files
authored
fix: clear table messages after refine & minor bugs (#2420)
* add: clear table messages after refine * fix: bug publishing to signature extraction * fix: use same font * fix: use default folders filter && use \\All as a default if exists * fix: formatting
1 parent 2ee409a commit 589a731

File tree

4 files changed

+69
-73
lines changed

4 files changed

+69
-73
lines changed

backend/src/services/imap/ImapEmailsFetcher.ts

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ export default class ImapEmailsFetcher {
6767

6868
private totalFetched: number;
6969

70-
private connections: Connection[];
71-
7270
private hasAuthFailureLogged: boolean;
7371

7472
private readonly bodies: string[];
@@ -110,7 +108,6 @@ export default class ImapEmailsFetcher {
110108
// Set the key for the process set. used for caching.
111109
this.processSetKey = `caching:${miningId}`;
112110

113-
this.connections = [];
114111
this.totalFetched = 0;
115112

116113
this.isCanceled = false;
@@ -123,7 +120,7 @@ export default class ImapEmailsFetcher {
123120
intervalCap: 1, // only 1 job starts per interval
124121
interval: 100 // 100ms gap between job starts
125122
});
126-
this.bodies = this.fetchEmailBody ? ['HEADER', 'TEXT'] : ['HEADER'];
123+
this.bodies = this.fetchEmailBody ? ['TEXT'] : []; // HEADER is handled by ImapFlow;
127124
}
128125

129126
/**
@@ -337,38 +334,17 @@ export default class ImapEmailsFetcher {
337334

338335
let header: Record<string, string[]>;
339336
const { seq, headers, envelope } = msg;
337+
const from = envelope?.from?.pop();
338+
const date = envelope?.date?.toISOString?.();
340339

341-
if (envelope?.from?.pop()?.address === this.userEmail) continue;
340+
if (from?.address === this.userEmail) continue;
342341

343342
try {
344343
header = parseHeader((headers as Buffer).toString('utf8'));
345344
} catch {
346345
continue;
347346
}
348347

349-
let text = '';
350-
if (msg.bodyParts?.has('text')) {
351-
const textPart = msg.bodyParts.get('text');
352-
if (headers && textPart?.length) {
353-
try {
354-
const { text: parsedText } = await simpleParser(
355-
Buffer.concat([headers, textPart]),
356-
{
357-
skipHtmlToText: true,
358-
skipTextToHtml: true,
359-
skipImageLinks: true,
360-
skipTextLinks: true
361-
}
362-
);
363-
text = parsedText?.slice(0, this.EMAIL_TEXT_MAX_LENGTH) || '';
364-
} catch {
365-
text = '';
366-
}
367-
}
368-
}
369-
370-
const from = envelope?.from?.pop();
371-
const date = envelope?.date?.toISOString?.();
372348
const messageId = getMessageId(header);
373349
header['message-id'] = [messageId];
374350

@@ -396,6 +372,25 @@ export default class ImapEmailsFetcher {
396372
})
397373
);
398374

375+
let text = msg.bodyParts?.get('text') ?? '';
376+
377+
if (headers && text?.length) {
378+
try {
379+
const { text: parsedText } = await simpleParser(
380+
Buffer.concat([headers, text as Uint8Array<ArrayBufferLike>]),
381+
{
382+
skipHtmlToText: true,
383+
skipTextToHtml: true,
384+
skipImageLinks: true,
385+
skipTextLinks: true
386+
}
387+
);
388+
text = parsedText?.slice(0, this.EMAIL_TEXT_MAX_LENGTH) || '';
389+
} catch {
390+
text = '';
391+
}
392+
}
393+
399394
if (text.length && from && date) {
400395
await redisClient.xadd(
401396
this.signatureStream,

frontend/src/components/Mining/MiningSettingsDialog.vue

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,21 @@
66
:maximizable="$screenStore?.size?.md"
77
:pt:root:class="{ 'p-dialog-maximized': !$screenStore?.size?.md }"
88
:style="{ width: '60vw', height: '70vh' }"
9-
pt:content:class="grow p-3 border-y border-slate-200"
10-
pt:footer:class="p-3"
9+
pt:content:class="grow p-4 border-y border-slate-200"
10+
pt:footer:class="p-4"
1111
:header="t('fine_tune_mining')"
1212
>
13+
<!-- aligned switch (quick) -->
14+
<div class="flex items-center gap-2 pb-4">
15+
<ToggleSwitch
16+
v-model="$leadminerStore.extractSignatures"
17+
input-id="extractSignatures"
18+
/>
19+
<label for="extractSignatures" class="cursor-pointer">
20+
{{ t('extract_signatures_option') }} {{ t('extract_signatures_sub') }}
21+
</label>
22+
</div>
23+
1324
<div class="flex items-center gap-2">
1425
<div class="text-h6">{{ t('select_folders_to_mine') }}</div>
1526
<Button
@@ -28,22 +39,11 @@
2839
<i class="pi pi-envelope ml-1.5" />
2940
</Badge>
3041
</div>
31-
32-
<!-- aligned switch (quick) -->
33-
<div class="flex items-center gap-2 mt-4 pl-8">
34-
<ToggleSwitch
35-
v-model="$leadminerStore.extractSignatures"
36-
input-id="extractSignatures"
37-
/>
38-
<label for="extractSignatures" class="text-sm cursor-pointer">
39-
{{ t('extract_signatures_option') }}
40-
</label>
41-
<small class="">{{ t('extract_signatures_sub') }}</small>
42-
</div>
4342
<TreeCard
4443
v-if="shouldShowTreeCard"
4544
:class="{ disabled: $leadminerStore.activeMiningTask }"
4645
/>
46+
4747
<template #footer>
4848
<Button :label="$t('common.save')" @click="close" />
4949
</template>
@@ -103,14 +103,14 @@ defineExpose({
103103
"select_folders_to_mine": "Select folders to mine",
104104
"email_messages_selected": "Email messages selected",
105105
"extract_signatures_option": "Extract contact details from signatures",
106-
"extract_signatures_sub": "(this may take more time)"
106+
"extract_signatures_sub": "( this may take more time )"
107107
},
108108
"fr": {
109109
"fine_tune_mining": "Affinez l'extraction",
110110
"select_folders_to_mine": "Sélectionnez les dossiers à extraire",
111111
"email_messages_selected": "E-mails sélectionnés",
112112
"extract_signatures_option": "Extraire les coordonnées depuis les signatures",
113-
"extract_signatures_sub": "(cela peut prendre plus de temps)"
113+
"extract_signatures_sub": "( cela peut prendre plus de temps )"
114114
}
115115
}
116116
</i18n>

frontend/src/utils/boxes.ts

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,21 @@ export const EMAIL_EXCLUDED_FOLDERS = [
1515
'drafts',
1616
'junk',
1717
'trash',
18-
'\\all',
1918
'\\drafts',
2019
'\\junk',
2120
'\\trash',
2221
];
2322

24-
/**
25-
* Gets all selected folders
26-
* @param boxes - The array of folder names to filter
27-
* @returns The filtered array of boxes
28-
*/
29-
function getAllFolders(boxes: BoxNode[]) {
30-
const folders: TreeSelectionKeys = [];
31-
objectScan(['**.key'], {
32-
joined: true,
33-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34-
filterFn: ({ parent }: any) => {
35-
const { key } = parent;
36-
folders[key] = {
37-
checked: true,
38-
partialChecked: false,
39-
isNoSelect: Boolean(parent.attribs?.includes('\\Noselect')),
40-
};
41-
},
42-
})(boxes);
43-
return folders;
44-
}
45-
4623
/**
4724
* Filters out default selected folders from the input boxes based on email service
4825
* @param boxes - The array of folder names to filter
4926
* @returns The filtered array of boxes
5027
*/
51-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
28+
5229
function getFilteredFolders(boxes: BoxNode[]) {
5330
const filteredFolders: TreeSelectionKeys = [];
31+
let foundAllMailKey: string | null = null;
32+
5433
objectScan(['**.key'], {
5534
joined: true,
5635
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -59,24 +38,43 @@ function getFilteredFolders(boxes: BoxNode[]) {
5938
const folder = key.split('/');
6039
const folderName = folder.pop();
6140
const folderParent = folder.pop();
41+
const isAllMail = attribs?.includes('\\All');
42+
43+
if (foundAllMailKey && !isAllMail) return;
6244

6345
const isExcluded = [...(attribs ?? []), folderName, folderParent]
6446
.filter(Boolean)
6547
.map((name) => name.toLowerCase())
6648
.some((name) => EMAIL_EXCLUDED_FOLDERS.includes(name));
6749

68-
if (!isExcluded) {
69-
// Format to be like PrimeVue's TreeSelectionKeys
70-
const checked = attribs && !attribs.includes('\\HasChildren');
71-
const partialChecked = !checked;
50+
if (isExcluded) return;
7251

52+
// Format to be like PrimeVue's TreeSelectionKeys
53+
const checked = attribs && !attribs.includes('\\HasChildren');
54+
const partialChecked = !checked;
55+
const isNoSelect = Boolean(attribs?.includes('\\Noselect'));
56+
57+
if (isAllMail && !isNoSelect) {
58+
// skipcq: JS-0320
59+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
60+
Object.keys(filteredFolders).forEach((k) => delete filteredFolders[k]);
61+
// Add All Mail as the only selected folder
62+
filteredFolders[key] = {
63+
checked: true,
64+
partialChecked: false,
65+
isNoSelect,
66+
};
67+
foundAllMailKey = key;
68+
} else {
7369
filteredFolders[key] = {
7470
checked,
7571
partialChecked,
72+
isNoSelect,
7673
};
7774
}
7875
},
7976
})(boxes);
77+
8078
return filteredFolders;
8179
}
8280

@@ -86,6 +84,6 @@ function getFilteredFolders(boxes: BoxNode[]) {
8684
* @returns The filtered array of boxes
8785
*/
8886
export function getDefaultSelectedFolders(boxes: BoxNode[]) {
89-
const defaultFolders = getAllFolders(boxes);
87+
const defaultFolders = getFilteredFolders(boxes);
9088
return defaultFolders;
9189
}

supabase/migrations/20250122185859_optimize_refine_persons.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,8 @@ BEGIN
132132
DROP TABLE IF EXISTS real_names;
133133
DROP TABLE IF EXISTS email_aggregates;
134134
DROP TABLE IF EXISTS combined_data;
135+
136+
-- Clear table messages
137+
DELETE FROM private.messages m WHERE m.user_id = user_id
135138
END;
136139
$$;

0 commit comments

Comments
 (0)