feat: Make it easier to handle multiple tags

- Tags can now be removed straight from the email header
- Tagging control now allows the user to (de)select multiple tags in one go
This commit is contained in:
Mathy Vanvoorden
2026-07-29 17:18:42 +02:00
parent 108406a885
commit d9d9f91a86
11 changed files with 221 additions and 108 deletions
+25
View File
@@ -5,6 +5,7 @@ import {
getThreadParticipants,
mergeThreadEmails,
getEmailTagId,
getEmailTagIds,
getThreadTagId,
getThreadTagIds,
} from '../thread-utils';
@@ -246,6 +247,30 @@ describe('mergeThreadEmails', () => {
});
});
describe('getEmailTagIds', () => {
it('gathers every tag set on the message', () => {
expect(getEmailTagIds({ '$label:red': true, '$label:work': true, $seen: true }))
.toEqual(['red', 'work']);
});
it('reads the legacy prefix alongside the current one', () => {
expect(getEmailTagIds({ '$label:red': true, '$color:blue': true })).toEqual(['red', 'blue']);
});
it('reports a tag written under both prefixes once', () => {
expect(getEmailTagIds({ '$label:red': true, '$color:red': true })).toEqual(['red']);
});
it('ignores keywords set to false', () => {
expect(getEmailTagIds({ '$label:red': false, '$label:work': true })).toEqual(['work']);
});
it('is empty for an untagged message or none at all', () => {
expect(getEmailTagIds({ $seen: true })).toEqual([]);
expect(getEmailTagIds(undefined)).toEqual([]);
});
});
describe('getEmailTagId', () => {
it('returns label from $label: keyword', () => {
expect(getEmailTagId({ '$label:red': true, $seen: true })).toBe('red');
+4 -3
View File
@@ -170,20 +170,21 @@ export const KEYWORD_PREFIX_LEGACY = "$color:";
/**
* Gets every tag id set on a message.
* Reads both the current $label: prefix and the legacy $color: prefix.
* A tag written under both spellings is one tag, so it is returned once.
*/
export function getEmailTagIds(keywords: Record<string, boolean> | undefined): string[] {
if (!keywords) return [];
const tags: string[] = [];
const tags = new Set<string>();
for (const key of Object.keys(keywords)) {
if ((key.startsWith(KEYWORD_PREFIX) || key.startsWith(KEYWORD_PREFIX_LEGACY)) && keywords[key] === true) {
tags.push(
tags.add(
key.startsWith(KEYWORD_PREFIX)
? key.slice(KEYWORD_PREFIX.length)
: key.slice(KEYWORD_PREFIX_LEGACY.length)
);
}
}
return tags;
return [...tags];
}
/**