/** * Google Sheets operation enum + form schema — single source of truth across * the API, Dashboard, and Message Broker. Used by: * - sheetsAction entity / DTO (api): operation field + validation * - dashboard SheetsAction detail page: the whole operation form * * The api already accepted the first six; the dashboard's own `SheetsAction` * type only listed four (it never learned about appendOrUpdateRow and * createSpreadsheet), which is exactly the drift this enum removes. * `deleteRow` came later (2026-10-16, mejora #61): before it, the only way to * "remove" a row was to blank it with updateRow. */ export declare const SHEETS_OPERATIONS: readonly ["appendRow", "updateRow", "appendOrUpdateRow", "deleteRow", "readRange", "getRows", "createSpreadsheet"]; export type SheetsOperation = (typeof SHEETS_OPERATIONS)[number]; /** Type guard — useful when validating untrusted input (DTOs, AI tool calls). */ export declare function isSheetsOperation(value: unknown): value is SheetsOperation; /** * Per-operation form schema, same idea as SLACK_OPERATION_SPECS and * GOOGLE_CONTACTS_OPERATION_SPECS: the detail page renders it with one loop * instead of a branch per operation. * * Two things make this node's schema different from the others, and both are * deliberate: * * 1. **The values are top-level entity fields, not an `operationConfig` * record.** `name` here is the property on the sheetsAction document * (`spreadsheetId`, `sheetName`, …), and `columnMapping` is a complex field. * A renderer copied from Contacts would write to the wrong place. * 2. **Half the fields are discovered at run time.** The column list comes from * the chosen sheet's header row, fetched live. So the schema names the * *picker* rather than carrying options — the same trick Discord's * `channel` / `guild` / `role` types use. */ export interface SheetsParamSpec { /** Field key — the property name on the sheetsAction document. */ name: string; /** UI label. Empty string where the control has never shown one. */ label: string; /** * Param type for form rendering. * * - `string` — one-line input with `{{payload.x}}` templating. * - `spreadsheet` — the spreadsheet picker **plus** the "or paste ID / URL" * input that sits under it. They are one field with two ways in, not two * fields, and the paste box extracts the id out of a full URL. * - `sheetTab` — the tab picker for the chosen spreadsheet. Picking a tab * clears `columnMapping`, because the headers just changed. * - `headerColumn` — a dropdown of the sheet's live header row. * - `columnMapping` — the header-to-template editor. It owns the three * states of the header fetch (loading, loaded, failed), which is what * used to be six copies of the same conditional in the page. */ type: 'string' | 'spreadsheet' | 'sheetTab' | 'headerColumn' | 'columnMapping'; /** Required by the operation. Metadata — the form does not gate on it. */ required?: boolean; /** Help text under the control. Absent where the form shows none. */ description?: string; /** Hint shown inside the input. */ placeholder?: string; /** * Section this field is rendered inside. Fields without one share the first * section with the operation picker; the mapping fields sit in a second * section whose title changes per operation ("Columns to Append", * "Update Row", "Match & Upsert"). */ section?: string; /** `columnMapping` only — the line shown while no column has been added. */ emptyText?: string; } export interface SheetsOperationSpec { /** UI label for the operation picker. */ label: string; /** Sub-line under the label in the picker. */ description: string; /** googleapis call the operation maps to (sheets v4). */ apiMethod: string; /** Parameter schema. Order matters for form rendering. */ params: SheetsParamSpec[]; } export declare const SHEETS_OPERATION_SPECS: Record;