import * as z from "zod" import { defineAction } from "../../../automation/actions" import { toGoogleConditionalFormatRule } from "../lib/formatting" import { getGoogleSheetsApi, normalizeConditionalFormatRule, normalizeSpreadsheetId, resolveSameSheetRangeTargets, resolveSheet, } from "../lib/google-sheets" import { GOOGLE_SHEETS_WRITE_REQUIREMENT } from "../lib/scopes" import { CONDITIONAL_FORMAT_RULE_INPUT_SCHEMA, CONDITIONAL_FORMAT_RULE_SCHEMA, RANGE_TARGET_SCHEMA, SHEET_REFERENCE_SCHEMA, SPREADSHEET_REFERENCE_SCHEMA, } from "../lib/schemas" /** Replaces a conditional-format rule at a sheet's zero-based index. */ export const updateGoogleSheetsConditionalFormatRule = defineAction( "Update Google Sheets conditional format rule", ) .describe("Replaces a conditional-format rule without changing its index.") .account("google", GOOGLE_SHEETS_WRITE_REQUIREMENT) .input( z.object({ /** Zero-based rule index on the sheet. */ index: z.number().int().nonnegative(), /** Complete replacement ranges on one sheet. */ ranges: RANGE_TARGET_SCHEMA.array().min(1), /** Complete replacement rule definition. */ rule: CONDITIONAL_FORMAT_RULE_INPUT_SCHEMA, /** Sheet title or immutable numeric sheet ID. */ sheet: SHEET_REFERENCE_SCHEMA, /** Spreadsheet ID or standard Google Sheets URL. */ spreadsheet: SPREADSHEET_REFERENCE_SCHEMA, }), ) .output(CONDITIONAL_FORMAT_RULE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { const sheetsApi = getGoogleSheetsApi(account.secret) const spreadsheetId = normalizeSpreadsheetId(input.spreadsheet) const [{ ranges, sheetId }, selectedSheet] = await Promise.all([ resolveSameSheetRangeTargets(sheetsApi, spreadsheetId, input.ranges), resolveSheet(sheetsApi, spreadsheetId, input.sheet), ]) if (selectedSheet.properties!.sheetId !== sheetId) { throw new Error( "The replacement conditional-format ranges must be on the selected sheet.", ) } const { data } = await sheetsApi.spreadsheets.batchUpdate({ requestBody: { requests: [ { updateConditionalFormatRule: { index: input.index, rule: toGoogleConditionalFormatRule(input.rule, ranges), }, }, ], }, spreadsheetId, }) const reply = data.replies?.[0]?.updateConditionalFormatRule const rule = reply?.newRule if (!rule) throw new Error("Google did not return the updated rule.") return normalizeConditionalFormatRule(rule, reply.newIndex ?? input.index) })