feat: Change the dev mode defaults to include nested tags
This commit is contained in:
@@ -120,7 +120,7 @@ const emails: MockEmail[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'email-002', threadId: 'thread-002', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$label:blue': true }, size: 5100, receivedAt: daysAgo(1),
|
id: 'email-002', threadId: 'thread-002', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$label:work/clients/acme': true }, size: 5100, receivedAt: daysAgo(1),
|
||||||
from: [{ name: 'Dubois, Pierre', email: 'pierre@dubois.example' }],
|
from: [{ name: 'Dubois, Pierre', email: 'pierre@dubois.example' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }],
|
||||||
cc: [{ name: 'de Vries, Karel', email: 'karel@devries.example' }],
|
cc: [{ name: 'de Vries, Karel', email: 'karel@devries.example' }],
|
||||||
@@ -152,7 +152,7 @@ const emails: MockEmail[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'email-004', threadId: 'thread-004', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:red': true }, size: 6200, receivedAt: daysAgo(0),
|
id: 'email-004', threadId: 'thread-004', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:work/clients': true, '$label:receipts': true }, size: 6200, receivedAt: daysAgo(0),
|
||||||
from: [{ name: 'GitHub Notifications', email: 'notifications@github.com' }],
|
from: [{ name: 'GitHub Notifications', email: 'notifications@github.com' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
||||||
subject: '[bulwark-webmail] New issue: Add dark mode toggle (#42)',
|
subject: '[bulwark-webmail] New issue: Add dark mode toggle (#42)',
|
||||||
@@ -181,7 +181,7 @@ const emails: MockEmail[] = [
|
|||||||
},
|
},
|
||||||
// Newsletter with full HTML
|
// Newsletter with full HTML
|
||||||
{
|
{
|
||||||
id: 'email-013', threadId: 'thread-012', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:purple': true }, size: 18200, receivedAt: daysAgo(0),
|
id: 'email-013', threadId: 'thread-012', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:personal/finance': true }, size: 18200, receivedAt: daysAgo(0),
|
||||||
from: [{ name: 'Launchpad Weekly', email: 'hello@launchpad.example' }],
|
from: [{ name: 'Launchpad Weekly', email: 'hello@launchpad.example' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
||||||
subject: 'Launchpad Weekly #47 - The future of the open web',
|
subject: 'Launchpad Weekly #47 - The future of the open web',
|
||||||
@@ -228,7 +228,7 @@ const emails: MockEmail[] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'email-016', threadId: 'thread-015', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:green': true }, size: 4100, receivedAt: hoursAgo(3),
|
id: 'email-016', threadId: 'thread-015', mailboxIds: { 'mb-inbox': true }, keywords: { '$label:personal': true }, size: 4100, receivedAt: hoursAgo(3),
|
||||||
from: [{ name: 'Élise Moreau', email: 'elise.moreau@fjord-systems.example' }],
|
from: [{ name: 'Élise Moreau', email: 'elise.moreau@fjord-systems.example' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
||||||
subject: 'Code review request: JMAP-342 contact import',
|
subject: 'Code review request: JMAP-342 contact import',
|
||||||
@@ -255,7 +255,7 @@ const emails: MockEmail[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'email-018', threadId: 'thread-017', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$label:orange': true }, size: 4700, receivedAt: daysAgo(1),
|
id: 'email-018', threadId: 'thread-017', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$label:work': true }, size: 4700, receivedAt: daysAgo(1),
|
||||||
from: [{ name: 'Hetzner Cloud', email: 'billing@hetzner.example' }],
|
from: [{ name: 'Hetzner Cloud', email: 'billing@hetzner.example' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
||||||
subject: 'Your Hetzner invoice is available - February 2026',
|
subject: 'Your Hetzner invoice is available - February 2026',
|
||||||
@@ -355,7 +355,7 @@ const emails: MockEmail[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'email-025', threadId: 'thread-024', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$label:blue': true }, size: 4100, receivedAt: daysAgo(6),
|
id: 'email-025', threadId: 'thread-024', mailboxIds: { 'mb-inbox': true }, keywords: { $seen: true, $flagged: true, '$color:work/archived': true }, size: 4100, receivedAt: daysAgo(6),
|
||||||
from: [{ name: 'Stripe Developer', email: 'developer-updates@stripe.example' }],
|
from: [{ name: 'Stripe Developer', email: 'developer-updates@stripe.example' }],
|
||||||
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
to: [{ name: 'Dev User', email: 'dev@localhost' }], cc: [],
|
||||||
subject: 'Action required: API v2023-10 deprecation on April 15, 2026',
|
subject: 'Action required: API v2023-10 deprecation on April 15, 2026',
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ const nextConfig: NextConfig = {
|
|||||||
NEXT_PUBLIC_GIT_COMMIT: gitCommitHash,
|
NEXT_PUBLIC_GIT_COMMIT: gitCommitHash,
|
||||||
NEXT_PUBLIC_APP_VERSION: appVersion,
|
NEXT_PUBLIC_APP_VERSION: appVersion,
|
||||||
NEXT_PUBLIC_BASE_PATH: basePath,
|
NEXT_PUBLIC_BASE_PATH: basePath,
|
||||||
|
NEXT_PUBLIC_DEV_MOCK_JMAP: process.env.DEV_MOCK_JMAP ?? "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
import { useSettingsStore, DEFAULT_KEYWORDS, KEYWORD_PALETTE, KEYWORD_PALETTE_ROWS, getKeywordVisibility } from '../settings-store';
|
import { useSettingsStore, DEFAULT_KEYWORDS, DEV_KEYWORDS, KEYWORD_PALETTE, KEYWORD_PALETTE_ROWS, getKeywordVisibility } from '../settings-store';
|
||||||
import type { KeywordDefinition } from '../settings-store';
|
import type { KeywordDefinition } from '../settings-store';
|
||||||
|
|
||||||
describe('settings-store keywords', () => {
|
describe('settings-store keywords', () => {
|
||||||
@@ -24,6 +24,31 @@ describe('settings-store keywords', () => {
|
|||||||
const ids = DEFAULT_KEYWORDS.map((k) => k.id);
|
const ids = DEFAULT_KEYWORDS.map((k) => k.id);
|
||||||
expect(new Set(ids).size).toBe(ids.length);
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ships no nested tag, which is opt-in', () => {
|
||||||
|
DEFAULT_KEYWORDS.forEach((kw) => expect(kw.id).not.toContain('/'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DEV_KEYWORDS', () => {
|
||||||
|
it('every nested tag has its parent defined, so the tree has no gaps', () => {
|
||||||
|
const ids = new Set(DEV_KEYWORDS.map((k) => k.id));
|
||||||
|
DEV_KEYWORDS.forEach((kw) => {
|
||||||
|
const cut = kw.id.lastIndexOf('/');
|
||||||
|
if (cut > 0) expect(ids, `orphan: ${kw.id}`).toContain(kw.id.slice(0, cut));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('nests deeply enough to exercise the tree', () => {
|
||||||
|
const depths = DEV_KEYWORDS.map((k) => k.id.split('/').length);
|
||||||
|
expect(Math.max(...depths)).toBeGreaterThanOrEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('each dev keyword has a valid palette color and a unique id', () => {
|
||||||
|
const ids = DEV_KEYWORDS.map((k) => k.id);
|
||||||
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
|
DEV_KEYWORDS.forEach((kw) => expect(KEYWORD_PALETTE[kw.color]).toBeDefined());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('KEYWORD_PALETTE', () => {
|
describe('KEYWORD_PALETTE', () => {
|
||||||
|
|||||||
@@ -215,6 +215,17 @@ export const DEFAULT_KEYWORDS: KeywordDefinition[] = [
|
|||||||
{ id: 'pink', label: 'Pink', color: 'pink' },
|
{ id: 'pink', label: 'Pink', color: 'pink' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const DEV_KEYWORDS: KeywordDefinition[] = [
|
||||||
|
{ id: 'work', label: 'Work', color: 'blue' },
|
||||||
|
{ id: 'work/clients', label: 'Clients', color: 'teal' },
|
||||||
|
{ id: 'work/clients/acme', label: 'Acme', color: 'green' },
|
||||||
|
{ id: 'personal', label: 'Personal', color: 'purple' },
|
||||||
|
{ id: 'personal/finance', label: 'Finance', color: 'amber' },
|
||||||
|
{ id: 'receipts', label: 'Receipts', color: 'gray' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const USING_MOCK_SERVER = process.env.NEXT_PUBLIC_DEV_MOCK_JMAP === 'true';
|
||||||
|
|
||||||
interface SettingsState {
|
interface SettingsState {
|
||||||
// Appearance
|
// Appearance
|
||||||
fontSize: FontSize;
|
fontSize: FontSize;
|
||||||
@@ -557,8 +568,8 @@ const DEFAULT_SETTINGS = {
|
|||||||
folderIcons: {} as Record<string, string>,
|
folderIcons: {} as Record<string, string>,
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
emailKeywords: DEFAULT_KEYWORDS,
|
emailKeywords: USING_MOCK_SERVER ? DEV_KEYWORDS : DEFAULT_KEYWORDS,
|
||||||
nestedTags: false,
|
nestedTags: USING_MOCK_SERVER,
|
||||||
|
|
||||||
// Attachment Reminder
|
// Attachment Reminder
|
||||||
attachmentReminderEnabled: true,
|
attachmentReminderEnabled: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user