Fix Monday.com push failures and improve error visibility

- Fix toast showing success when all cards fail (now shows error/warning)
- Fix column value formatting: booleans use checkbox format, JSON arrays
  join as comma-separated strings, objects serialize properly
- Filter out empty/null/undefined string values before sending to API
- Add verbose logging to Monday.com GraphQL client for debugging

Made-with: Cursor
This commit is contained in:
Randall Stillwell 2026-04-07 13:50:44 -05:00
parent 034c73128f
commit a0f5022de2
3 changed files with 48 additions and 5 deletions

View file

@ -408,8 +408,13 @@ export default function SettingsPage() {
if (res.ok) {
if (data.synced === 0 && data.failed === 0) {
toast.success("All cards are already synced to Monday.com");
} else if (data.failed > 0 && data.synced === 0) {
const errDetail = data.errors?.[0] ? `\n${data.errors[0]}` : "";
toast.error(`All ${data.failed} card(s) failed to push to Monday.com${errDetail}`);
} else if (data.failed > 0) {
toast.warning(`Pushed ${data.synced} card(s), but ${data.failed} failed`);
} else {
toast.success(`Pushed ${data.synced} card(s) to Monday.com${data.failed > 0 ? ` (${data.failed} failed)` : ""}`);
toast.success(`Pushed ${data.synced} card(s) to Monday.com`);
}
} else {
toast.error(data.error || "Sync failed");

View file

@ -203,6 +203,8 @@ export async function pushCardToMonday(
const columnValues = mapCardToColumnValues(cardData, columnMap);
const itemName = (card.name as string) || "Unnamed Card";
console.log(`[pushCardToMonday] Card "${itemName}" (${cardId}), columnValues:`, JSON.stringify(columnValues));
if (card.mondayItemId) {
await updateItem(token, boardId, card.mondayItemId, columnValues);
return { action: "updated" as const, mondayItemId: card.mondayItemId };

View file

@ -4,6 +4,9 @@ const MONDAY_FILE_API = "https://api.monday.com/v2/file";
type MondayColumn = { id: string; title: string; type: string };
async function gql(token: string, query: string, variables?: Record<string, unknown>) {
const body = JSON.stringify({ query, variables });
console.log("[monday gql] request:", body.slice(0, 500));
const res = await fetch(MONDAY_API, {
method: "POST",
headers: {
@ -11,7 +14,7 @@ async function gql(token: string, query: string, variables?: Record<string, unkn
Authorization: token,
"API-Version": "2024-10",
},
body: JSON.stringify({ query, variables }),
body,
});
if (!res.ok) {
const text = await res.text().catch(() => "");
@ -21,10 +24,12 @@ async function gql(token: string, query: string, variables?: Record<string, unkn
if (json.errors?.length) {
const err = json.errors[0];
const detail = err.extensions ? ` (${JSON.stringify(err.extensions)})` : "";
console.error("[monday gql] GraphQL error:", JSON.stringify(json.errors));
throw new Error(`Monday.com GraphQL: ${err.message}${detail}`);
}
if (json.error_message) {
throw new Error(`Monday.com: ${json.error_message}`);
console.error("[monday gql] API error:", json.error_message, json.error_code);
throw new Error(`Monday.com: ${json.error_message} (${json.error_code || "unknown"})`);
}
return json.data;
}
@ -135,6 +140,33 @@ export async function readItem(
};
}
const BOOLEAN_CARD_FIELDS = new Set([
"iSaidYesBookSent",
"ftGuestLetterSent",
"prayerForTeam",
"prayerConfidential",
]);
function formatValue(cardField: string, val: unknown): unknown | null {
if (BOOLEAN_CARD_FIELDS.has(cardField) || typeof val === "boolean") {
return { checked: val === true || val === "true" ? "true" : "false" };
}
if (Array.isArray(val)) {
const joined = val.filter(Boolean).join(", ");
return joined || null;
}
if (typeof val === "object") {
const s = JSON.stringify(val);
return s === "{}" || s === "[]" ? null : s;
}
const strVal = String(val).trim();
if (strVal === "" || strVal === "null" || strVal === "undefined" || strVal === "[object Object]") return null;
return strVal;
}
export function mapCardToColumnValues(
card: Record<string, unknown>,
columnMap: Record<string, string>
@ -142,10 +174,14 @@ export function mapCardToColumnValues(
const values: Record<string, unknown> = {};
for (const [cardField, colId] of Object.entries(columnMap)) {
if (!colId || !cardField) continue;
if (!colId || !cardField || cardField.startsWith("_")) continue;
const val = card[cardField];
if (val === null || val === undefined) continue;
values[colId] = String(val);
const formatted = formatValue(cardField, val);
if (formatted !== null) {
values[colId] = formatted;
}
}
return values;