mirror of
https://github.com/root-fr/jmap-webmail.git
synced 2026-09-30 00:01:26 +00:00
fix: resolve calendar crash on undefined duration and sieve filter save error
parseDuration() now handles undefined event.duration gracefully instead of crashing on .match(). CalendarEvent.duration type updated to reflect that JMAP servers may omit this field. Sieve filter activation replaced isActive (server-set per RFC 9661) with onSuccessActivateScript. Create/update calls merged with activation into single JMAP roundtrips. Closes #31, closes #21
This commit is contained in:
@@ -28,7 +28,8 @@ function getEventColor(event: CalendarEvent, calendar?: Calendar): string {
|
||||
return sanitizeColor(event.color, sanitizeColor(calendar?.color));
|
||||
}
|
||||
|
||||
function parseDuration(duration: string): number {
|
||||
function parseDuration(duration: string | undefined): number {
|
||||
if (!duration) return 0;
|
||||
let totalMinutes = 0;
|
||||
const weekMatch = duration.match(/(\d+)W/);
|
||||
const hourMatch = duration.match(/(\d+)H/);
|
||||
|
||||
+39
-37
@@ -1433,17 +1433,22 @@ export class JMAPClient {
|
||||
throw new Error('Invalid upload response: blobId not found');
|
||||
}
|
||||
|
||||
async createSieveScript(name: string, content: string): Promise<SieveScript> {
|
||||
async createSieveScript(name: string, content: string, activate?: boolean): Promise<SieveScript> {
|
||||
const blobId = await this.uploadSieveBlob(content);
|
||||
const accountId = this.getSieveAccountId();
|
||||
|
||||
const setArgs: Record<string, unknown> = {
|
||||
accountId,
|
||||
create: {
|
||||
"new-script": { name, blobId }
|
||||
},
|
||||
};
|
||||
if (activate) {
|
||||
setArgs.onSuccessActivateScript = "#new-script";
|
||||
}
|
||||
|
||||
const response = await this.request([
|
||||
["SieveScript/set", {
|
||||
accountId,
|
||||
create: {
|
||||
"new-script": { name, blobId }
|
||||
}
|
||||
}, "0"]
|
||||
["SieveScript/set", setArgs, "0"]
|
||||
], this.sieveUsing());
|
||||
|
||||
if (response.methodResponses?.[0]?.[0] === "SieveScript/set") {
|
||||
@@ -1462,17 +1467,22 @@ export class JMAPClient {
|
||||
throw new Error("Failed to create sieve script");
|
||||
}
|
||||
|
||||
async updateSieveScript(scriptId: string, content: string): Promise<void> {
|
||||
async updateSieveScript(scriptId: string, content: string, activate?: boolean): Promise<void> {
|
||||
const blobId = await this.uploadSieveBlob(content);
|
||||
const accountId = this.getSieveAccountId();
|
||||
|
||||
const setArgs: Record<string, unknown> = {
|
||||
accountId,
|
||||
update: {
|
||||
[scriptId]: { blobId }
|
||||
},
|
||||
};
|
||||
if (activate) {
|
||||
setArgs.onSuccessActivateScript = scriptId;
|
||||
}
|
||||
|
||||
const response = await this.request([
|
||||
["SieveScript/set", {
|
||||
accountId,
|
||||
update: {
|
||||
[scriptId]: { blobId }
|
||||
}
|
||||
}, "0"]
|
||||
["SieveScript/set", setArgs, "0"]
|
||||
], this.sieveUsing());
|
||||
|
||||
if (response.methodResponses?.[0]?.[0] === "SieveScript/set") {
|
||||
@@ -1513,44 +1523,36 @@ export class JMAPClient {
|
||||
const response = await this.request([
|
||||
["SieveScript/set", {
|
||||
accountId,
|
||||
update: {
|
||||
[scriptId]: { isActive: true }
|
||||
}
|
||||
onSuccessActivateScript: scriptId,
|
||||
}, "0"]
|
||||
], this.sieveUsing());
|
||||
|
||||
if (response.methodResponses?.[0]?.[0] === "SieveScript/set") {
|
||||
const result = response.methodResponses[0][1];
|
||||
if (result.notUpdated?.[scriptId]) {
|
||||
const error = result.notUpdated[scriptId];
|
||||
throw new Error(error.description || "Failed to activate sieve script");
|
||||
}
|
||||
return;
|
||||
const [methodName, result] = response.methodResponses?.[0] || [];
|
||||
if (methodName === "error") {
|
||||
throw new Error(result?.description || "Failed to activate sieve script");
|
||||
}
|
||||
if (methodName !== "SieveScript/set") {
|
||||
throw new Error("Failed to activate sieve script");
|
||||
}
|
||||
throw new Error("Failed to activate sieve script");
|
||||
}
|
||||
|
||||
async deactivateSieveScript(scriptId: string): Promise<void> {
|
||||
async deactivateSieveScript(): Promise<void> {
|
||||
const accountId = this.getSieveAccountId();
|
||||
|
||||
const response = await this.request([
|
||||
["SieveScript/set", {
|
||||
accountId,
|
||||
update: {
|
||||
[scriptId]: { isActive: false }
|
||||
}
|
||||
onSuccessActivateScript: null,
|
||||
}, "0"]
|
||||
], this.sieveUsing());
|
||||
|
||||
if (response.methodResponses?.[0]?.[0] === "SieveScript/set") {
|
||||
const result = response.methodResponses[0][1];
|
||||
if (result.notUpdated?.[scriptId]) {
|
||||
const error = result.notUpdated[scriptId];
|
||||
throw new Error(error.description || "Failed to deactivate sieve script");
|
||||
}
|
||||
return;
|
||||
const [methodName, result] = response.methodResponses?.[0] || [];
|
||||
if (methodName === "error") {
|
||||
throw new Error(result?.description || "Failed to deactivate sieve script");
|
||||
}
|
||||
if (methodName !== "SieveScript/set") {
|
||||
throw new Error("Failed to deactivate sieve script");
|
||||
}
|
||||
throw new Error("Failed to deactivate sieve script");
|
||||
}
|
||||
|
||||
async validateSieveScript(content: string): Promise<{ isValid: boolean; errors?: string[] }> {
|
||||
|
||||
+1
-1
@@ -312,7 +312,7 @@ export interface CalendarEvent {
|
||||
updated: string;
|
||||
sequence: number;
|
||||
start: string;
|
||||
duration: string;
|
||||
duration?: string;
|
||||
timeZone: string | null;
|
||||
showWithoutTime: boolean;
|
||||
status: 'tentative' | 'confirmed' | 'cancelled';
|
||||
|
||||
@@ -94,11 +94,9 @@ export const useFilterStore = create<FilterStore>()((set, get) => ({
|
||||
}
|
||||
|
||||
if (activeScriptId) {
|
||||
await client.updateSieveScript(activeScriptId, content);
|
||||
await client.activateSieveScript(activeScriptId);
|
||||
await client.updateSieveScript(activeScriptId, content, true);
|
||||
} else {
|
||||
const script = await client.createSieveScript('filters', content);
|
||||
await client.activateSieveScript(script.id);
|
||||
const script = await client.createSieveScript('filters', content, true);
|
||||
set({ activeScriptId: script.id });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user