fix: clear identity signature fields when emptied

This commit is contained in:
Linus Rath
2026-05-18 00:53:54 +02:00
parent 7a72903632
commit ed6b5d5f33
5 changed files with 40 additions and 33 deletions
+14 -12
View File
@@ -36,10 +36,10 @@ function truncateToUtf8Bytes(s: string, maxBytes: number): string {
interface IdentityFormData { interface IdentityFormData {
name: string; name: string;
email: string; email: string;
replyTo?: EmailAddress[]; replyTo?: EmailAddress[] | null;
bcc?: EmailAddress[]; bcc?: EmailAddress[] | null;
textSignature?: string; textSignature?: string | null;
htmlSignature?: string; htmlSignature?: string | null;
} }
interface IdentityFormProps { interface IdentityFormProps {
@@ -121,14 +121,16 @@ export function IdentityForm({ identity, onSave, onCancel }: IdentityFormProps)
setIsSubmitting(true); setIsSubmitting(true);
try { try {
// Sanitize HTML signature before sending to server // JMAP needs explicit null to clear a field; undefined would be dropped
// from the JSON payload and leave the server-side value untouched.
const trimmedText = formData.textSignature?.trim() ?? '';
const trimmedHtml = formData.htmlSignature?.trim() ?? '';
const sanitizedData: IdentityFormData = { const sanitizedData: IdentityFormData = {
...formData, ...formData,
replyTo: parseEmailList(replyToInput), textSignature: trimmedText ? formData.textSignature : null,
bcc: parseEmailList(bccInput), htmlSignature: trimmedHtml ? sanitizeSignatureHtml(formData.htmlSignature!) : null,
htmlSignature: formData.htmlSignature replyTo: parseEmailList(replyToInput) ?? null,
? sanitizeSignatureHtml(formData.htmlSignature) bcc: parseEmailList(bccInput) ?? null,
: undefined,
}; };
await onSave(sanitizedData); await onSave(sanitizedData);
@@ -271,7 +273,7 @@ export function IdentityForm({ identity, onSave, onCancel }: IdentityFormProps)
</label> </label>
<textarea <textarea
id="identity-text-sig" id="identity-text-sig"
value={formData.textSignature} value={formData.textSignature ?? ''}
onChange={(e) => setFormData({ ...formData, textSignature: truncateToUtf8Bytes(e.target.value, SIGNATURE_MAX_BYTES) })} onChange={(e) => setFormData({ ...formData, textSignature: truncateToUtf8Bytes(e.target.value, SIGNATURE_MAX_BYTES) })}
rows={3} rows={3}
disabled={isSubmitting} disabled={isSubmitting}
@@ -289,7 +291,7 @@ export function IdentityForm({ identity, onSave, onCancel }: IdentityFormProps)
</label> </label>
<textarea <textarea
id="identity-html-sig" id="identity-html-sig"
value={formData.htmlSignature} value={formData.htmlSignature ?? ''}
onChange={(e) => setFormData({ ...formData, htmlSignature: truncateToUtf8Bytes(e.target.value, SIGNATURE_MAX_BYTES) })} onChange={(e) => setFormData({ ...formData, htmlSignature: truncateToUtf8Bytes(e.target.value, SIGNATURE_MAX_BYTES) })}
rows={5} rows={5}
disabled={isSubmitting} disabled={isSubmitting}
@@ -32,10 +32,10 @@ function emailMatchesUsername(email: string, username: string): boolean {
interface IdentityFormData { interface IdentityFormData {
name: string; name: string;
email: string; email: string;
replyTo?: EmailAddress[]; replyTo?: EmailAddress[] | null;
bcc?: EmailAddress[]; bcc?: EmailAddress[] | null;
textSignature?: string; textSignature?: string | null;
htmlSignature?: string; htmlSignature?: string | null;
} }
interface IdentityManagerModalProps { interface IdentityManagerModalProps {
+8 -3
View File
@@ -530,7 +530,7 @@ export class DemoJMAPClient implements IJMAPClient {
async createIdentity( async createIdentity(
name: string, email: string, name: string, email: string,
replyTo?: EmailAddress[] | null, bcc?: EmailAddress[] | null, replyTo?: EmailAddress[] | null, bcc?: EmailAddress[] | null,
htmlSignature?: string, textSignature?: string, textSignature?: string | null, htmlSignature?: string | null,
): Promise<Identity> { ): Promise<Identity> {
const identity: Identity = { const identity: Identity = {
id: generateDemoId('identity'), name, email, id: generateDemoId('identity'), name, email,
@@ -542,9 +542,14 @@ export class DemoJMAPClient implements IJMAPClient {
return identity; return identity;
} }
async updateIdentity(identityId: string, updates: { name?: string; replyTo?: EmailAddress[] | null; bcc?: EmailAddress[] | null; htmlSignature?: string; textSignature?: string }): Promise<void> { async updateIdentity(identityId: string, updates: { name?: string | null; replyTo?: EmailAddress[] | null; bcc?: EmailAddress[] | null; textSignature?: string | null; htmlSignature?: string | null }): Promise<void> {
const identity = this.data.identities.find(i => i.id === identityId); const identity = this.data.identities.find(i => i.id === identityId);
if (identity) Object.assign(identity, updates); if (!identity) return;
if (updates.name !== undefined) identity.name = updates.name ?? '';
if (updates.replyTo !== undefined) identity.replyTo = updates.replyTo ?? undefined;
if (updates.bcc !== undefined) identity.bcc = updates.bcc ?? undefined;
if (updates.textSignature !== undefined) identity.textSignature = updates.textSignature ?? '';
if (updates.htmlSignature !== undefined) identity.htmlSignature = updates.htmlSignature ?? '';
} }
async deleteIdentity(identityId: string): Promise<void> { async deleteIdentity(identityId: string): Promise<void> {
+5 -5
View File
@@ -183,17 +183,17 @@ export interface IJMAPClient {
email: string, email: string,
replyTo?: EmailAddress[] | null, replyTo?: EmailAddress[] | null,
bcc?: EmailAddress[] | null, bcc?: EmailAddress[] | null,
htmlSignature?: string, textSignature?: string | null,
textSignature?: string, htmlSignature?: string | null,
): Promise<Identity>; ): Promise<Identity>;
updateIdentity( updateIdentity(
identityId: string, identityId: string,
updates: { updates: {
name?: string; name?: string | null;
replyTo?: EmailAddress[] | null; replyTo?: EmailAddress[] | null;
bcc?: EmailAddress[] | null; bcc?: EmailAddress[] | null;
htmlSignature?: string; textSignature?: string | null;
textSignature?: string; htmlSignature?: string | null;
}, },
): Promise<void>; ): Promise<void>;
deleteIdentity(identityId: string): Promise<void>; deleteIdentity(identityId: string): Promise<void>;
+9 -9
View File
@@ -1813,10 +1813,10 @@ export class JMAPClient implements IJMAPClient {
async createIdentity( async createIdentity(
name: string, name: string,
email: string, email: string,
replyTo?: EmailAddress[], replyTo?: EmailAddress[] | null,
bcc?: EmailAddress[], bcc?: EmailAddress[] | null,
textSignature?: string, textSignature?: string | null,
htmlSignature?: string htmlSignature?: string | null
): Promise<Identity> { ): Promise<Identity> {
const response = await this.request([ const response = await this.request([
["Identity/set", { ["Identity/set", {
@@ -1859,11 +1859,11 @@ export class JMAPClient implements IJMAPClient {
async updateIdentity( async updateIdentity(
identityId: string, identityId: string,
updates: { updates: {
name?: string; name?: string | null;
replyTo?: EmailAddress[]; replyTo?: EmailAddress[] | null;
bcc?: EmailAddress[]; bcc?: EmailAddress[] | null;
textSignature?: string; textSignature?: string | null;
htmlSignature?: string; htmlSignature?: string | null;
} }
): Promise<void> { ): Promise<void> {
const response = await this.request([ const response = await this.request([