mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
Merge pull request #1370 from maxhaomh/feat/disable-quick-reply
This commit is contained in:
@@ -76,6 +76,7 @@ function makeEmail(overrides: Record<string, unknown> = {}): Email {
|
||||
let toastError: ReturnType<typeof vi.spyOn>;
|
||||
|
||||
beforeEach(() => {
|
||||
useSettingsStore.setState({ quickReplyEnabled: true });
|
||||
toastError = vi.spyOn(toast, 'error').mockImplementation(() => {});
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
});
|
||||
@@ -85,6 +86,15 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe('viewer send failures', () => {
|
||||
it('hides quick reply when disabled and restores it when enabled', () => {
|
||||
useSettingsStore.setState({ quickReplyEnabled: false });
|
||||
render(<EmailViewer email={makeEmail()} mailboxes={mailboxes} selectedMailbox="inbox" currentMailboxRole="inbox" />);
|
||||
|
||||
expect(screen.queryByPlaceholderText('quick_reply_placeholder')).not.toBeInTheDocument();
|
||||
act(() => useSettingsStore.getState().updateSetting('quickReplyEnabled', true));
|
||||
expect(screen.getByPlaceholderText('quick_reply_placeholder')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('reports a failed quick reply and keeps the text on Stalwart 1.0', async () => {
|
||||
const onQuickReply = vi.fn().mockRejectedValue(new SubmissionQuotaError(QUOTA, true));
|
||||
render(
|
||||
|
||||
@@ -1084,6 +1084,7 @@ export function EmailViewer({
|
||||
const tContextMenu = useTranslations('context_menu');
|
||||
const copyLink = useCopyLink();
|
||||
const tWelcome = useTranslations('welcome');
|
||||
const quickReplyEnabled = useSettingsStore((state) => state.quickReplyEnabled);
|
||||
const externalContentPolicy = useSettingsStore((state) => state.externalContentPolicy);
|
||||
const messageSpacing = useSettingsStore((state) => state.messageSpacing);
|
||||
const plainTextFont = useSettingsStore((state) => state.plainTextFont);
|
||||
@@ -6380,7 +6381,7 @@ export function EmailViewer({
|
||||
)}
|
||||
|
||||
{/* Quick Reply Section - hidden for drafts and while loading a new email */}
|
||||
{!mvReplyRow && !isDraft && !isScheduled && !isBodyLoading && (effectiveEmailContent.isHtml ? iframeReady : true) && (<div className="bg-background border-t border-border px-6 mt-auto" style={{ paddingBlock: 'var(--density-header-py)' }}>
|
||||
{quickReplyEnabled && !mvReplyRow && !isDraft && !isScheduled && !isBodyLoading && (effectiveEmailContent.isHtml ? iframeReady : true) && (<div className="bg-background border-t border-border px-6 mt-auto" style={{ paddingBlock: 'var(--density-header-py)' }}>
|
||||
<div className="flex items-start" style={{ gap: 'var(--density-item-gap)' }}>
|
||||
<div className="flex-shrink-0">
|
||||
<Avatar
|
||||
|
||||
@@ -23,6 +23,7 @@ export function ComposingSettings() {
|
||||
const [newKeyword, setNewKeyword] = useState('');
|
||||
|
||||
const {
|
||||
quickReplyEnabled,
|
||||
autoSelectReplyIdentity,
|
||||
replyIdentityMatch,
|
||||
plainTextMode,
|
||||
@@ -84,6 +85,13 @@ export function ComposingSettings() {
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection id="replying" title={tPage('sections.replying')}>
|
||||
<SettingItem label={t('quick_reply.label')} description={t('quick_reply.description')}>
|
||||
<ToggleSwitch
|
||||
checked={quickReplyEnabled}
|
||||
onChange={(checked) => updateSetting('quickReplyEnabled', checked)}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t('auto_select_reply_identity.label')} description={t('auto_select_reply_identity.description')}>
|
||||
<ToggleSwitch
|
||||
checked={autoSelectReplyIdentity}
|
||||
|
||||
@@ -1536,6 +1536,10 @@
|
||||
"label": "Plain Text Only",
|
||||
"description": "Disable the rich text editor and send all emails as plain text only, including replies and forwards"
|
||||
},
|
||||
"quick_reply": {
|
||||
"label": "Quick Reply",
|
||||
"description": "Show the quick reply box below messages."
|
||||
},
|
||||
"auto_select_reply_identity": {
|
||||
"label": "Reply From Received Address",
|
||||
"description": "When replying, send from the address the message was originally sent to. Your configured identities always match; whether other addresses on your domains count too (catch-all) is set by “Received Address Matching” below."
|
||||
|
||||
@@ -6,6 +6,14 @@ describe('settings-store attachment action', () => {
|
||||
useSettingsStore.getState().resetToDefaults();
|
||||
});
|
||||
|
||||
it('enables quick reply by default and exports the disabled preference', () => {
|
||||
expect(useSettingsStore.getState().quickReplyEnabled).toBe(true);
|
||||
useSettingsStore.getState().updateSetting('quickReplyEnabled', false);
|
||||
expect(JSON.parse(useSettingsStore.getState().exportSettings()).quickReplyEnabled).toBe(false);
|
||||
useSettingsStore.getState().resetToDefaults();
|
||||
expect(useSettingsStore.getState().quickReplyEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it('defaults to preview when settings are reset', () => {
|
||||
expect(useSettingsStore.getState().mailAttachmentAction).toBe('preview');
|
||||
});
|
||||
|
||||
@@ -528,6 +528,7 @@ interface SettingsState {
|
||||
// Composer
|
||||
autoSaveDraftInterval: number; // milliseconds
|
||||
sendConfirmation: boolean;
|
||||
quickReplyEnabled: boolean;
|
||||
defaultReplyMode: ReplyMode;
|
||||
autoSelectReplyIdentity: boolean;
|
||||
replyIdentityMatch: ReplyIdentityMatch; // With autoSelectReplyIdentity on: 'exact' = configured identities only, 'domain' = also same-domain catch-all addresses (rewrites From) #1000
|
||||
@@ -836,6 +837,7 @@ const DEFAULT_SETTINGS = {
|
||||
// Composer
|
||||
autoSaveDraftInterval: 60000, // 1 minute
|
||||
sendConfirmation: false,
|
||||
quickReplyEnabled: true,
|
||||
defaultReplyMode: 'reply' as ReplyMode,
|
||||
autoSelectReplyIdentity: false,
|
||||
replyIdentityMatch: 'domain' as ReplyIdentityMatch,
|
||||
@@ -1202,6 +1204,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
trustedSenders: state.trustedSenders,
|
||||
autoSaveDraftInterval: state.autoSaveDraftInterval,
|
||||
sendConfirmation: state.sendConfirmation,
|
||||
quickReplyEnabled: state.quickReplyEnabled,
|
||||
defaultReplyMode: state.defaultReplyMode,
|
||||
autoSelectReplyIdentity: state.autoSelectReplyIdentity,
|
||||
replyIdentityMatch: state.replyIdentityMatch,
|
||||
|
||||
Reference in New Issue
Block a user