mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 00:14:18 +00:00
feat: move a message from its own window with Message > Move to…
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import React from 'react';
|
||||
import { ProTabFocusContext } from '@/hooks/use-pane-context';
|
||||
@@ -26,6 +26,20 @@ vi.mock('@/components/error', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('next-intl', () => ({ useTranslations: () => (key: string) => key }));
|
||||
|
||||
// A message window: the Message menu's Move to… opens the folder list there.
|
||||
const popout = vi.hoisted(() => ({ value: false }));
|
||||
vi.mock('@/lib/popout/window-role', async (importOriginal) => ({
|
||||
...await importOriginal<typeof import('@/lib/popout/window-role')>(),
|
||||
isPopoutWindow: () => popout.value,
|
||||
}));
|
||||
const moveDialog = vi.hoisted(() => ({ current: null as { email: unknown } | null }));
|
||||
vi.mock('@/components/email/move-to-dialog', () => ({
|
||||
MoveToDialog: (props: { email: unknown }) => {
|
||||
moveDialog.current = props;
|
||||
return null;
|
||||
},
|
||||
}));
|
||||
vi.mock('@/stores/toast-store', () => ({ toast: { error: () => {}, success: () => {} } }));
|
||||
const multiAccount = vi.hoisted(() => ({
|
||||
value: { enabled: false, groups: [] as unknown[], allIdentities: [] as Array<{ id: string; email: string; name: string }> },
|
||||
@@ -79,6 +93,7 @@ vi.mock('@/stores/pro-tab-store', () => ({
|
||||
}));
|
||||
|
||||
import { ProEmailView } from '../pro-email-tab-body';
|
||||
import { resetDesktopCommands, runDesktopCommand } from '@/lib/desktop/commands';
|
||||
|
||||
const DRAFT = {
|
||||
id: 'eaaaaab',
|
||||
@@ -307,3 +322,24 @@ describe('Pro email view - keyboard', () => {
|
||||
expect(openComposeTab).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Message > Move to… in a message window', () => {
|
||||
it('opens the folder list for the message on screen', async () => {
|
||||
popout.value = true;
|
||||
window.bulwarkDesktop = { version: 1, platform: 'win32', menu: { setState: vi.fn() } } as never;
|
||||
try {
|
||||
const client = { getEmail: vi.fn().mockResolvedValue(DRAFT), getUsername: () => 'userb@example.org', getAccountId: () => 'e' };
|
||||
render(<ProEmailView emailId="eaaaaab" client={client as never} onClose={vi.fn()} />);
|
||||
await waitFor(() => expect(viewerProps.current?.email).toBeTruthy());
|
||||
expect(moveDialog.current?.email ?? null).toBeNull();
|
||||
act(() => {
|
||||
expect(runDesktopCommand('message.move')).toBe(true);
|
||||
});
|
||||
await waitFor(() => expect(moveDialog.current?.email).toMatchObject({ id: 'eaaaaab' }));
|
||||
} finally {
|
||||
popout.value = false;
|
||||
window.bulwarkDesktop = undefined;
|
||||
resetDesktopCommands();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useCallback, useEffect, useState, useMemo, useRef } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { EmailViewer } from "@/components/email/email-viewer";
|
||||
import { MoveToDialog } from "@/components/email/move-to-dialog";
|
||||
import { ErrorBoundary, EmailViewerErrorFallback } from "@/components/error";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import { useEmailStore, resolveEmailBlobContext, type EmailBlobContext, type EmailWriteSource } from "@/stores/email-store";
|
||||
@@ -472,6 +473,8 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId,
|
||||
// In a pop-out this message is all there is, so the menu bar's Message menu means it.
|
||||
const inOwnWindow = typeof window !== 'undefined' && isPopoutWindow();
|
||||
const seen = !!email?.keywords?.$seen;
|
||||
// Message > Move to… in a pop-out: the same folder list the command palette opens.
|
||||
const [moveDialogOpen, setMoveDialogOpen] = useState(false);
|
||||
useDesktopCommands({
|
||||
'message.reply': () => handleReply(),
|
||||
'message.replyAll': handleReplyAll,
|
||||
@@ -481,6 +484,7 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId,
|
||||
'message.star': () => void handleToggleStar(),
|
||||
'message.archive': archiveActionEnabled ? () => void handleArchive() : undefined,
|
||||
'message.delete': () => void handleDelete(),
|
||||
'message.move': () => { if (email) setMoveDialogOpen(true); },
|
||||
}, {
|
||||
'message.reply': !!email,
|
||||
'message.replyAll': !!email,
|
||||
@@ -490,6 +494,7 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId,
|
||||
'message.star': !!email,
|
||||
'message.archive': !!email && archiveActionEnabled,
|
||||
'message.delete': !!email,
|
||||
'message.move': !!email,
|
||||
}, inOwnWindow);
|
||||
|
||||
const handleMoveToMailbox = useCallback(async (mailboxId: string) => {
|
||||
@@ -642,6 +647,15 @@ export function ProEmailView({ emailId, client: clientOverride, clientAccountId,
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<ConfirmDialog {...confirmDialogProps} />
|
||||
{inOwnWindow && (
|
||||
<MoveToDialog
|
||||
email={moveDialogOpen ? email : null}
|
||||
mailboxes={mailboxes}
|
||||
selectedMailbox=""
|
||||
onClose={() => setMoveDialogOpen(false)}
|
||||
onMove={(mailboxId) => void handleMoveToMailbox(mailboxId)}
|
||||
/>
|
||||
)}
|
||||
{preview && (
|
||||
<FilePreviewModal
|
||||
name={preview.name}
|
||||
|
||||
Reference in New Issue
Block a user