mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-31 21:19:21 +03:00
Allow searching on keyword/tag/label #419
This commit is contained in:
parent
fba1c59f84
commit
875dae0755
42 changed files with 789 additions and 712 deletions
|
|
@ -8,7 +8,7 @@ import { encodeHtml, plainToHtml, cleanHtml } from 'Common/Html';
|
|||
import { isArray, arrayLength, forEachObjectEntry } from 'Common/Utils';
|
||||
import { serverRequestRaw, proxy } from 'Common/Links';
|
||||
|
||||
import { FolderUserStore } from 'Stores/User/Folder';
|
||||
import { FolderUserStore, isAllowedKeyword } from 'Stores/User/Folder';
|
||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||
|
||||
import { FileInfo } from 'Common/File';
|
||||
|
|
@ -30,40 +30,6 @@ const
|
|||
return result;
|
||||
},
|
||||
|
||||
ignoredTags = [
|
||||
// rfc5788
|
||||
'$forwarded',
|
||||
'$mdnsent',
|
||||
'$submitpending',
|
||||
'$submitted',
|
||||
// rfc9051
|
||||
'$junk',
|
||||
'$notjunk',
|
||||
'$phishing',
|
||||
// Mailo
|
||||
'sent',
|
||||
// KMail
|
||||
'$attachment',
|
||||
'$encrypted',
|
||||
'$error',
|
||||
'$ignored',
|
||||
'$invitation',
|
||||
'$queued',
|
||||
'$replied',
|
||||
'$sent',
|
||||
'$signed',
|
||||
'$todo',
|
||||
'$watched',
|
||||
// GMail
|
||||
'$replied',
|
||||
'$attachment',
|
||||
'$notphishing',
|
||||
'junk',
|
||||
'nonjunk',
|
||||
// Others
|
||||
'$readreceipt'
|
||||
],
|
||||
|
||||
toggleTag = (message, keyword) => {
|
||||
const lower = keyword.toLowerCase(),
|
||||
isSet = message.flags().includes(lower);
|
||||
|
|
@ -161,16 +127,16 @@ export class MessageModel extends AbstractModel {
|
|||
// isPhishing: () => this.flags().includes('$phishing'),
|
||||
|
||||
tagsToHTML: () => this.flags().map(value =>
|
||||
('\\' == value[0] || ignoredTags.includes(value))
|
||||
? ''
|
||||
: '<span class="focused msgflag-'+value+'">' + i18n('MESSAGE_TAGS/'+value,0,value) + '</span>'
|
||||
isAllowedKeyword(value)
|
||||
? '<span class="focused msgflag-'+value+'">' + i18n('MESSAGE_TAGS/'+value,0,value) + '</span>'
|
||||
: ''
|
||||
).join(' '),
|
||||
|
||||
tagOptions: () => {
|
||||
const tagOptions = [];
|
||||
FolderUserStore.currentFolder().permanentFlags.forEach(value => {
|
||||
let lower = value.toLowerCase();
|
||||
if ('\\' != value[0] && !ignoredTags.includes(lower)) {
|
||||
if (isAllowedKeyword(value)) {
|
||||
let lower = value.toLowerCase();
|
||||
tagOptions.push({
|
||||
css: 'msgflag-' + lower,
|
||||
value: value,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,45 @@ import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache';
|
|||
import { Settings, SettingsCapa } from 'Common/Globals';
|
||||
//import Remote from 'Remote/User/Fetch'; // Circular dependency
|
||||
|
||||
export const FolderUserStore = new class {
|
||||
export const
|
||||
|
||||
ignoredKeywords = [
|
||||
// rfc5788
|
||||
'$forwarded',
|
||||
'$mdnsent',
|
||||
'$submitpending',
|
||||
'$submitted',
|
||||
// rfc9051
|
||||
'$junk',
|
||||
'$notjunk',
|
||||
'$phishing',
|
||||
// Mailo
|
||||
'sent',
|
||||
// KMail
|
||||
'$attachment',
|
||||
'$encrypted',
|
||||
'$error',
|
||||
'$ignored',
|
||||
'$invitation',
|
||||
'$queued',
|
||||
'$replied',
|
||||
'$sent',
|
||||
'$signed',
|
||||
'$todo',
|
||||
'$watched',
|
||||
// GMail
|
||||
'$replied',
|
||||
'$attachment',
|
||||
'$notphishing',
|
||||
'junk',
|
||||
'nonjunk',
|
||||
// Others
|
||||
'$readreceipt'
|
||||
],
|
||||
|
||||
isAllowedKeyword = value => '\\' != value[0] && !ignoredKeywords.includes(value.toLowerCase()),
|
||||
|
||||
FolderUserStore = new class {
|
||||
constructor() {
|
||||
const self = this;
|
||||
addObservablesTo(self, {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import { koComputable } from 'External/ko';
|
||||
|
||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||
import { pString } from 'Common/Utils';
|
||||
|
||||
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||
|
||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||
import { FolderUserStore } from 'Stores/User/Folder';
|
||||
import { FolderUserStore, isAllowedKeyword } from 'Stores/User/Folder';
|
||||
|
||||
export class AdvancedSearchPopupView extends AbstractViewPopup {
|
||||
constructor() {
|
||||
|
|
@ -17,6 +15,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
to: '',
|
||||
subject: '',
|
||||
text: '',
|
||||
keyword: '',
|
||||
repliedValue: -1,
|
||||
selectedDateValue: -1,
|
||||
selectedTreeValue: '',
|
||||
|
|
@ -26,39 +25,58 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
unseen: false
|
||||
});
|
||||
|
||||
this.showMultisearch = koComputable(() => FolderUserStore.hasCapability('MULTISEARCH'));
|
||||
this.addComputables({
|
||||
showMultisearch: () => FolderUserStore.hasCapability('MULTISEARCH'),
|
||||
|
||||
this.repliedOptions = koComputable(() => {
|
||||
translatorTrigger();
|
||||
return [
|
||||
{ id: -1, name: '' },
|
||||
{ id: 1, name: i18n('GLOBAL/YES') },
|
||||
{ id: 0, name: i18n('GLOBAL/NO') }
|
||||
];
|
||||
});
|
||||
// Almost the same as MessageModel.tagOptions
|
||||
keywords: () => {
|
||||
const keywords = [{value:'',label:''}];
|
||||
FolderUserStore.currentFolder().permanentFlags.forEach(value => {
|
||||
if (isAllowedKeyword(value)) {
|
||||
let lower = value.toLowerCase();
|
||||
keywords.push({
|
||||
value: value,
|
||||
label: i18n('MESSAGE_TAGS/'+lower, 0, lower)
|
||||
});
|
||||
}
|
||||
});
|
||||
return keywords
|
||||
},
|
||||
|
||||
this.selectedDates = koComputable(() => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_DATE_';
|
||||
return [
|
||||
{ id: -1, name: i18n(prefix + 'ALL') },
|
||||
{ id: 3, name: i18n(prefix + '3_DAYS') },
|
||||
{ id: 7, name: i18n(prefix + '7_DAYS') },
|
||||
{ id: 30, name: i18n(prefix + 'MONTH') },
|
||||
{ id: 90, name: i18n(prefix + '3_MONTHS') },
|
||||
{ id: 180, name: i18n(prefix + '6_MONTHS') },
|
||||
{ id: 365, name: i18n(prefix + 'YEAR') }
|
||||
];
|
||||
});
|
||||
showKeywords: () => FolderUserStore.currentFolder().permanentFlags().some(isAllowedKeyword),
|
||||
|
||||
this.selectedTree = koComputable(() => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_SUBFOLDERS_';
|
||||
return [
|
||||
{ id: '', name: i18n(prefix + 'NONE') },
|
||||
{ id: 'subtree-one', name: i18n(prefix + 'SUBTREE_ONE') },
|
||||
{ id: 'subtree', name: i18n(prefix + 'SUBTREE') }
|
||||
];
|
||||
repliedOptions: () => {
|
||||
translatorTrigger();
|
||||
return [
|
||||
{ id: -1, name: '' },
|
||||
{ id: 1, name: i18n('GLOBAL/YES') },
|
||||
{ id: 0, name: i18n('GLOBAL/NO') }
|
||||
];
|
||||
},
|
||||
|
||||
selectedDates: () => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_DATE_';
|
||||
return [
|
||||
{ id: -1, name: i18n(prefix + 'ALL') },
|
||||
{ id: 3, name: i18n(prefix + '3_DAYS') },
|
||||
{ id: 7, name: i18n(prefix + '7_DAYS') },
|
||||
{ id: 30, name: i18n(prefix + 'MONTH') },
|
||||
{ id: 90, name: i18n(prefix + '3_MONTHS') },
|
||||
{ id: 180, name: i18n(prefix + '6_MONTHS') },
|
||||
{ id: 365, name: i18n(prefix + 'YEAR') }
|
||||
];
|
||||
},
|
||||
|
||||
selectedTree: () => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_SUBFOLDERS_';
|
||||
return [
|
||||
{ id: '', name: i18n(prefix + 'NONE') },
|
||||
{ id: 'subtree-one', name: i18n(prefix + 'SUBTREE_ONE') },
|
||||
{ id: 'subtree', name: i18n(prefix + 'SUBTREE') }
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +99,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
append('to', self.to().trim());
|
||||
append('subject', self.subject().trim());
|
||||
append('text', self.text().trim());
|
||||
append('keyword', self.keyword());
|
||||
append('in', self.selectedTreeValue());
|
||||
if (-1 < self.selectedDateValue()) {
|
||||
let d = new Date();
|
||||
|
|
@ -88,7 +107,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
append('since', d.toISOString().split('T')[0]);
|
||||
}
|
||||
|
||||
let result = new URLSearchParams(data).toString();
|
||||
let result = new URLSearchParams(data).toString().replace('%24','$');
|
||||
|
||||
if (self.hasAttachment()) {
|
||||
result += '&attachment';
|
||||
|
|
@ -116,6 +135,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
self.to(pString(params.get('to')));
|
||||
self.subject(pString(params.get('subject')));
|
||||
self.text(pString(params.get('text')));
|
||||
self.keyword(pString(params.get('keyword')));
|
||||
self.selectedTreeValue(pString(params.get('in')));
|
||||
// self.selectedDateValue(params.get('since'));
|
||||
self.selectedDateValue(-1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue