From 19aab434dad7ef2d7758b06431824ff8695c4704 Mon Sep 17 00:00:00 2001 From: Prajwal Lokhande Date: Sat, 8 Nov 2025 16:56:23 +0530 Subject: [PATCH 01/10] Added 6 new actions to support advanced cell formatting, data validation, and protection --- .../add-conditional-format-rule.mjs | 492 +++++++++++++++++ .../add-protected-range.mjs | 118 +++++ .../delete-conditional-format-rule.mjs | 62 +++ .../actions/merge-cells/merge-cells.mjs | 88 ++++ .../set-data-validation.mjs | 124 +++++ .../update-conditional-format-rule.mjs | 498 ++++++++++++++++++ 6 files changed, 1382 insertions(+) create mode 100644 components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs create mode 100644 components/google_sheets/actions/add-protected-range/add-protected-range.mjs create mode 100644 components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs create mode 100644 components/google_sheets/actions/merge-cells/merge-cells.mjs create mode 100644 components/google_sheets/actions/set-data-validation/set-data-validation.mjs create mode 100644 components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs diff --git a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs new file mode 100644 index 0000000000000..9ea6d7b97d456 --- /dev/null +++ b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs @@ -0,0 +1,492 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +function rgbToCssColor(red, green, blue) { + var rgbNumber = (red << 16) | (green << 8) | blue; + var hexString = rgbNumber.toString(16); + var missingZeros = 6 - hexString.length; + var resultBuilder = [ + "#", + ]; + for (var i = 0; i < missingZeros; i++) { + resultBuilder.push("0"); + } + resultBuilder.push(hexString); + return resultBuilder.join(""); +} + +export default { + key: "google_sheets-add-conditional-format-rule", + name: "Add Conditional Format Rule", + description: "Create conditional formatting with color scales or custom formulas. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + range: { + propDefinition: [ + googleSheets, + "range", + ], + description: "The range of cells to protect (e.g., `A1:A10`)", + }, + conditionType: { + type: "string", + label: "Validation Type", + description: "The type of data condition", + options: [ + "ONE_OF_LIST", + "NUMBER_GREATER", + "NUMBER_LESS", + "DATE_BEFORE", + "DATE_AFTER", + "TEXT_CONTAINS", + "TEXT_IS_EMAIL", + "TEXT_IS_URL", + "BOOLEAN", + ], + optional: true, + }, + conditionValues: { + type: "string[]", + label: "Condition Values", + description: "Values for condition (e.g., color scales or custom formulas)", + optional: true, + }, + formattingType: { + type: "string", + label: "Formatting Type", + description: "Choose between boolean condition or gradient color scale", + options: [ + "BOOLEAN_RULE", + "GRADIENT_RULE", + ], + default: "BOOLEAN_RULE", + }, + numberFormatType: { + type: "string", + label: "Number Format Type", + description: "The type of number format", + options: [ + "NUMBER", + "CURRENCY", + "PERCENT", + "SCIENTIFIC", + "TEXT", + "TIME", + "DATE", + "DATE_TIME", + "SCIENTIFIC", + ], + optional: true, + }, + rgbColor: { + type: "object", + label: "RGB Color", + description: "The RGB color value (e.g., {red: 1.0, green: 0.5, blue: 0.2})", + optional: true, + }, + themeColorType: { + type: "string", + label: "Theme Color Type", + description: "The theme color type", + options: [ + "TEXT", + "BACKGROUND", + "ACCENT1", + "ACCENT2", + "ACCENT3", + "ACCENT4", + "ACCENT5", + "ACCENT6", + "LINK", + ], + optional: true, + }, + borderStyle: { + type: "string", + label: "Border Style", + description: "The border style", + options: [ + "SOLID", + "DASHED", + "DOTTED", + "DOUBLE", + "GROOVE", + "RIDGE", + "INSET", + "OUTSET", + ], + optional: true, + }, + topPadding: { + type: "integer", + label: "Top Padding", + description: "The top padding in pixels", + optional: true, + default: 0, + }, + rightPadding: { + type: "integer", + label: "Right Padding", + description: "The right padding in pixels", + optional: true, + default: 0, + }, + bottomPadding: { + type: "integer", + label: "Bottom Padding", + description: "The bottom padding in pixels", + optional: true, + default: 0, + }, + leftPadding: { + type: "integer", + label: "Left Padding", + description: "The left padding in pixels", + optional: true, + default: 0, + }, + horizontalAlign: { + type: "string", + label: "Horizontal Align", + description: "The horizontal alignment", + options: [ + "LEFT", + "CENTER", + "RIGHT", + ], + optional: true, + }, + verticalAlign: { + type: "string", + label: "Vertical Align", + description: "The vertical alignment", + options: [ + "TOP", + "MIDDLE", + "BOTTOM", + ], + optional: true, + }, + wrapStrategy: { + type: "string", + label: "Wrap Strategy", + description: "The wrap strategy", + options: [ + "OVERFLOW_CELL", + "LEGACY_WRAP", + "CLIP", + "WRAP", + ], + optional: true, + }, + textDirection: { + type: "string", + label: "Text Direction", + description: "The text direction", + options: [ + "LEFT_TO_RIGHT", + "RIGHT_TO_LEFT", + ], + optional: true, + }, + textFormat: { + type: "object", + label: "Text Format", + description: "The text format options", + optional: true, + }, + fontFamily: { + type: "string", + label: "Font Family", + description: "The font family", + optional: true, + }, + fontSize: { + type: "integer", + label: "Font Size", + description: "The font size", + optional: true, + }, + bold: { + type: "boolean", + label: "Bold", + description: "Whether the text is bold", + optional: true, + }, + italic: { + type: "boolean", + label: "Italic", + description: "Whether the text is italic", + optional: true, + }, + underline: { + type: "boolean", + label: "Underline", + description: "Whether the text is underlined", + optional: true, + }, + strikethrough: { + type: "boolean", + label: "Strikethrough", + description: "Whether the text is strikethrough", + optional: true, + }, + url: { + type: "string", + label: "URL", + description: "The URL for the link", + optional: true, + }, + hyperlinkDisplayType: { + type: "string", + label: "Hyperlink Display Type", + description: "The hyperlink display type", + options: [ + "PLAIN_TEXT", + "LINKED", + ], + optional: true, + }, + InterpolationPointType: { + type: "string", + label: "Interpolation Point Type", + description: "The interpolation point type", + options: [ + "MIN", + "MAX", + "NUMBER", + "PERCENT", + "PERCENTILE", + ], + optional: true, + }, + index: { + type: "integer", + label: "Index", + description: "The zero-based index of the rule", + }, + }, + async run() { + const { + startCol, + endCol, + startRow, + endRow, + } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + + const rule = { + range: { + sheetId: this.props.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + }; + + const protoToCssColor = (rgbColor) => { + var redFrac = rgbColor.red || 0.0; + var greenFrac = rgbColor.green || 0.0; + var blueFrac = rgbColor.blue || 0.0; + var red = Math.floor(redFrac * 255); + var green = Math.floor(greenFrac * 255); + var blue = Math.floor(blueFrac * 255); + + if (!("alpha" in rgbColor)) { + return rgbToCssColor(red, green, blue); + } + + var alphaFrac = rgbColor.alpha.value || 0.0; + var rgbParams = [ + red, + green, + blue, + ].join(","); + return [ + "rgba(", + rgbParams, + ",", + alphaFrac, + ")", + ] + .join(""); + }; + + this.props.formattingType === "GRADIENT_RULE" ? + rule.gradientRule = { + minpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MIN", + }, + }, + midpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MID", + }, + }, + maxpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MAX", + }, + }, + } : + rule.booleanRule = { + condition: { + type: this.props.conditionType, + values: this.props.conditionValues?.map((v) => ({ + userEnteredValue: v, + })) || [], + }, + format: { + cellFormat: { + numberFormat: { + type: this.props.numberFormatType, + }, + backgroundColorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + borders: { + top: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + bottom: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + left: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + right: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + }, + padding: { + top: this.props.topPadding, + right: this.props.rightPadding, + bottom: this.props.bottomPadding, + left: this.props.leftPadding, + }, + horizontalAlignment: this.props.horizontalAlign, + verticalAlignment: this.props.verticalAlign, + wrapStrategy: this.props.wrapStrategy, + textDirection: this.props.textDirection, + textFormat: { + ...this.props.textFormat, + foregroundColorStyle: { + rgbColor: this.props.rgbColor, + themeColor: { + type: this.props.themeColorType, + }, + }, + fontFamily: this.props.fontFamily, + fontSize: this.props.fontSize, + bold: this.props.bold, + italic: this.props.italic, + underline: this.props.underline, + strikethrough: this.props.strikethrough, + link: { + url: this.props.url, + }, + }, + hyperlinkDisplayType: this.props.hyperlinkDisplayType, + textRotation: { + angle: 0, + vertical: false, + }, + }, + }, + }; + + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + addConditionalFormatRuleRequest: { + rule, + index: this.props.index, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; diff --git a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs new file mode 100644 index 0000000000000..db3f099273cc4 --- /dev/null +++ b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs @@ -0,0 +1,118 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +export default { + key: "google_sheets-add-protected-range", + name: "Add Protected Range", + description: "Add edit protection to cell range with permissions. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + protectedRangeId: { + type: "integer", + label: "Protected Range ID", + description: "The ID of the protected range (required for update and delete operations). This is a unique identifier assigned by Google Sheets", + optional: true, + }, + range: { + propDefinition: [ + googleSheets, + "range", + ], + description: "The range of cells to protect (e.g., `A1:A10`). Required for add and update operations", + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "A description of the protected range", + optional: true, + }, + warningOnly: { + type: "boolean", + label: "Warning Only", + description: "If true, users will see a warning when editing but can still modify. If false, editing is blocked", + optional: true, + default: false, + }, + requestingUserCanEdit: { + type: "boolean", + label: "Requesting User Can Edit", + description: "If true, the user making this request can edit the protected range", + optional: true, + default: false, + }, + protectors: { + type: "string[]", + label: "Protectors", + description: "Email addresses of users/groups who can edit the protected range (e.g., user@example.com)", + optional: true, + }, + }, + async run() { + const { + startCol, + endCol, + startRow, + endRow, + } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + addProtectedRangeRequest: { + protectedRange: { + protectedRangeId: this.props.protectedRangeId, + range: { + sheetId: this.props.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + description: this.props.description, + warningOnly: this.props.warningOnly, + requestingUserCanEdit: this.props.requestingUserCanEdit, + editors: { + users: this.props.protectors || [], + }, + }, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; diff --git a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs new file mode 100644 index 0000000000000..ae36064d3e57c --- /dev/null +++ b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs @@ -0,0 +1,62 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +export default { + key: "google_sheets-delete-conditional-format-rule", + name: "Delete Conditional Format Rule", + description: "Remove conditional formatting rule by index. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: true, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + index: { + type: "integer", + label: "Index", + description: "The zero-based index of the rule", + }, + }, + async run() { + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + deleteConditionalFormatRuleRequest: { + sheetId: this.props.worksheetId, + index: this.props.index, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; diff --git a/components/google_sheets/actions/merge-cells/merge-cells.mjs b/components/google_sheets/actions/merge-cells/merge-cells.mjs new file mode 100644 index 0000000000000..2a12e9f6a6fa8 --- /dev/null +++ b/components/google_sheets/actions/merge-cells/merge-cells.mjs @@ -0,0 +1,88 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +export default { + key: "google_sheets-merge-cells", + name: "Merge Cells", + description: "Merge a range of cells into a single cell. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + range: { + propDefinition: [ + googleSheets, + "range", + ], + description: "The range of cells to apply validation (e.g., `A1:A10`)", + }, + mergeType: { + type: "string", + label: "Merge Type", + description: "The type of merge to perform", + options: [ + "MERGE_ALL", + "MERGE_COLUMNS", + "MERGE_ROWS", + ], + default: "MERGE_ALL", + }, + }, + async run() { + const { + startCol, + endCol, + startRow, + endRow, + } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + mergeCellsRequest: { + range: { + sheetId: this.props.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + mergeType: this.props.mergeType, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; diff --git a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs new file mode 100644 index 0000000000000..4ee140f9a14ec --- /dev/null +++ b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs @@ -0,0 +1,124 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +export default { + key: "google_sheets-set-data-validation", + name: "Set Data Validation", + description: "Add data validation rules to cells (dropdowns, checkboxes, date/number validation). [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + range: { + propDefinition: [ + googleSheets, + "range", + ], + description: "The range of cells to apply validation (e.g., `A1:A10`)", + }, + validationType: { + type: "string", + label: "Validation Type", + description: "The type of data validation", + options: [ + "NUMBER_GREATER", + "NUMBER_GREATER_THAN_EQ", + "NUMBER_LESS_THAN_EQ", + "NUMBER_LESS", + "NUMBER_BETWEEN", + "TEXT_CONTAINS", + "TEXT_NOT_CONTAINS", + "DATE_EQUAL_TO", + "DATE_BEFORE", + "DATE_AFTER", + "ONE_OF_LIST", + "DATE_AFTER", + "DATE_ON_OR_AFTER", + "DATE_BEFORE", + "DATE_ON_OR_BEFORE", + "DATE_BETWEEN", + "TEXT_STARTS_WITH", + "TEXT_ENDS_WITH", + "TEXT_EQUAL_TO", + "TEXT_NOT_EQUAL_TO", + "CUSTOM_FORMULA", + "NUMBER_EQUAL_TO", + "NUMBER_NOT_EQUAL_TO", + "NUMBER_BETWEEN", + "NUMBER_NOT_BETWEEN", + ], + }, + validationValues: { + type: "string[]", + label: "Validation Values", + description: "Values for validation (e.g., dropdown options)", + optional: true, + }, + }, + async run() { + const { + startCol, + endCol, + startRow, + endRow, + } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + setDataValidation: { + range: { + sheetId: this.props.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + rule: { + condition: { + type: this.props.validationType, + values: this.props.validationValues?.map((v) => ({ + userEnteredValue: v, + })) || [], + }, + showCustomUi: true, + strict: true, + }, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; diff --git a/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs new file mode 100644 index 0000000000000..dc0412317f014 --- /dev/null +++ b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs @@ -0,0 +1,498 @@ +import googleSheets from "../../google_sheets.app.mjs"; + +function rgbToCssColor(red, green, blue) { + var rgbNumber = (red << 16) | (green << 8) | blue; + var hexString = rgbNumber.toString(16); + var missingZeros = 6 - hexString.length; + var resultBuilder = [ + "#", + ]; + for (var i = 0; i < missingZeros; i++) { + resultBuilder.push("0"); + } + resultBuilder.push(hexString); + return resultBuilder.join(""); +} + +export default { + key: "google_sheets-update-conditional-format-rule", + name: "Update Conditional Format Rule", + description: "Modify existing conditional formatting rule. [See the documentation](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest)", + version: "0.0.1", + type: "action", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: false, + }, + props: { + googleSheets, + drive: { + propDefinition: [ + googleSheets, + "watchedDrive", + ], + }, + sheetId: { + propDefinition: [ + googleSheets, + "sheetID", + (c) => ({ + driveId: googleSheets.methods.getDriveId(c.drive), + }), + ], + }, + worksheetId: { + propDefinition: [ + googleSheets, + "worksheetIDs", + (c) => ({ + sheetId: c.sheetId, + }), + ], + }, + range: { + propDefinition: [ + googleSheets, + "range", + ], + description: "The range of cells to protect (e.g., `A1:A10`)", + }, + conditionType: { + type: "string", + label: "Validation Type", + description: "The type of data condition", + options: [ + "ONE_OF_LIST", + "NUMBER_GREATER", + "NUMBER_LESS", + "DATE_BEFORE", + "DATE_AFTER", + "TEXT_CONTAINS", + "TEXT_IS_EMAIL", + "TEXT_IS_URL", + "BOOLEAN", + ], + optional: true, + }, + conditionValues: { + type: "string[]", + label: "Condition Values", + description: "Values for condition (e.g., color scales or custom formulas)", + optional: true, + }, + formattingType: { + type: "string", + label: "Formatting Type", + description: "Choose between boolean condition or gradient color scale", + options: [ + "BOOLEAN_RULE", + "GRADIENT_RULE", + ], + default: "BOOLEAN_RULE", + }, + numberFormatType: { + type: "string", + label: "Number Format Type", + description: "The type of number format", + options: [ + "NUMBER", + "CURRENCY", + "PERCENT", + "SCIENTIFIC", + "TEXT", + "TIME", + "DATE", + "DATE_TIME", + "SCIENTIFIC", + ], + optional: true, + }, + rgbColor: { + type: "object", + label: "RGB Color", + description: "The RGB color value", + optional: true, + }, + themeColorType: { + type: "string", + label: "Theme Color Type", + description: "The theme color type", + options: [ + "TEXT", + "BACKGROUND", + "ACCENT1", + "ACCENT2", + "ACCENT3", + "ACCENT4", + "ACCENT5", + "ACCENT6", + "LINK", + ], + optional: true, + }, + borderStyle: { + type: "string", + label: "Border Style", + description: "The border style", + options: [ + "SOLID", + "DASHED", + "DOTTED", + "DOUBLE", + "GROOVE", + "RIDGE", + "INSET", + "OUTSET", + ], + optional: true, + }, + topPadding: { + type: "integer", + label: "Top Padding", + description: "The top padding in pixels", + optional: true, + default: 0, + }, + rightPadding: { + type: "integer", + label: "Right Padding", + description: "The right padding in pixels", + optional: true, + default: 0, + }, + bottomPadding: { + type: "integer", + label: "Bottom Padding", + description: "The bottom padding in pixels", + optional: true, + default: 0, + }, + leftPadding: { + type: "integer", + label: "Left Padding", + description: "The left padding in pixels", + optional: true, + default: 0, + }, + horizontalAlign: { + type: "string", + label: "Horizontal Align", + description: "The horizontal alignment", + options: [ + "LEFT", + "CENTER", + "RIGHT", + ], + optional: true, + }, + verticalAlign: { + type: "string", + label: "Vertical Align", + description: "The vertical alignment", + options: [ + "TOP", + "MIDDLE", + "BOTTOM", + ], + optional: true, + }, + wrapStrategy: { + type: "string", + label: "Wrap Strategy", + description: "The wrap strategy", + options: [ + "OVERFLOW_CELL", + "LEGACY_WRAP", + "CLIP", + "WRAP", + ], + optional: true, + }, + textDirection: { + type: "string", + label: "Text Direction", + description: "The text direction", + options: [ + "LEFT_TO_RIGHT", + "RIGHT_TO_LEFT", + ], + optional: true, + }, + textFormat: { + type: "object", + label: "Text Format", + description: "The text format options", + optional: true, + }, + fontFamily: { + type: "string", + label: "Font Family", + description: "The font family", + optional: true, + }, + fontSize: { + type: "integer", + label: "Font Size", + description: "The font size", + optional: true, + }, + bold: { + type: "boolean", + label: "Bold", + description: "Whether the text is bold", + optional: true, + }, + italic: { + type: "boolean", + label: "Italic", + description: "Whether the text is italic", + optional: true, + }, + underline: { + type: "boolean", + label: "Underline", + description: "Whether the text is underlined", + optional: true, + }, + strikethrough: { + type: "boolean", + label: "Strikethrough", + description: "Whether the text is strikethrough", + optional: true, + }, + url: { + type: "string", + label: "URL", + description: "The URL for the link", + optional: true, + }, + hyperlinkDisplayType: { + type: "string", + label: "Hyperlink Display Type", + description: "The hyperlink display type", + options: [ + "PLAIN_TEXT", + "LINKED", + ], + optional: true, + }, + InterpolationPointType: { + type: "string", + label: "Interpolation Point Type", + description: "The interpolation point type", + options: [ + "MIN", + "MAX", + "NUMBER", + "PERCENT", + "PERCENTILE", + ], + optional: true, + }, + index: { + type: "integer", + label: "Index", + description: "The zero-based index of the rule", + }, + newIndex: { + type: "integer", + label: "New Index", + description: "The new zero-based index of the rule", + }, + }, + async run() { + const { + startCol, + endCol, + startRow, + endRow, + } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + + const rule = { + range: { + sheetId: this.props.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + }; + const protoToCssColor = (rgbColor) => { + var redFrac = rgbColor.red || 0.0; + var greenFrac = rgbColor.green || 0.0; + var blueFrac = rgbColor.blue || 0.0; + var red = Math.floor(redFrac * 255); + var green = Math.floor(greenFrac * 255); + var blue = Math.floor(blueFrac * 255); + + if (!("alpha" in rgbColor)) { + return rgbToCssColor(red, green, blue); + } + + var alphaFrac = rgbColor.alpha.value || 0.0; + var rgbParams = [ + red, + green, + blue, + ].join(","); + return [ + "rgba(", + rgbParams, + ",", + alphaFrac, + ")", + ] + .join(""); + }; + + this.props.formattingType === "GRADIENT_RULE" ? + rule.gradientRule = { + minpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MIN", + }, + }, + midpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MID", + }, + }, + maxpoint: { + interpolationPoint: { + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + type: this.props.InterpolationPointType, + value: "MAX", + }, + }, + } : + rule.booleanRule = { + condition: { + type: this.props.conditionType, + values: this.props.conditionValues?.map((v) => ({ + userEnteredValue: v, + })) || [], + }, + format: { + cellFormat: { + numberFormat: { + type: this.props.numberFormatType, + }, + backgroundColorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + borders: { + top: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + bottom: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + left: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + right: { + style: this.props.borderStyle, + colorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + }, + }, + padding: { + top: this.props.topPadding, + right: this.props.rightPadding, + bottom: this.props.bottomPadding, + left: this.props.leftPadding, + }, + horizontalAlignment: this.props.horizontalAlign, + verticalAlignment: this.props.verticalAlign, + wrapStrategy: this.props.wrapStrategy, + textDirection: this.props.textDirection, + textFormat: { + ...this.textFormat, + foregroundColorStyle: { + rgbColor: protoToCssColor(this.props.rgbColor), + themeColor: { + type: this.props.themeColorType, + }, + }, + fontFamily: this.props.fontFamily, + fontSize: this.props.fontSize, + bold: this.props.bold, + italic: this.props.italic, + underline: this.props.underline, + strikethrough: this.props.strikethrough, + link: { + url: this.props.url, + }, + }, + hyperlinkDisplayType: this.props.hyperlinkDisplayType, + textRotation: { + angle: 0, + vertical: false, + }, + }, + }, + }; + + const request = { + spreadsheetId: this.props.sheetId, + requestBody: { + requests: [ + { + updateConditionalFormatRuleRequest: { + index: this.props.index, + sheetId: this.props.worksheetId, + rule, + newIndex: this.props.newIndex, + }, + }, + ], + }, + }; + return await this.props.googleSheets.batchUpdate(request); + }, +}; From fccb924768f68fa9345f0b1294de08f2e2d8b20c Mon Sep 17 00:00:00 2001 From: Prajwal Lokhande Date: Tue, 11 Nov 2025 11:09:44 +0530 Subject: [PATCH 02/10] resolve PR comment --- .../add-conditional-format-rule.mjs | 105 ++++++++--------- .../add-protected-range.mjs | 21 ++-- .../delete-conditional-format-rule.mjs | 11 +- .../actions/merge-cells/merge-cells.mjs | 13 ++- .../set-data-validation.mjs | 15 +-- .../update-conditional-format-rule.mjs | 108 +++++++++--------- components/google_sheets/package.json | 2 +- 7 files changed, 140 insertions(+), 135 deletions(-) diff --git a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs index 9ea6d7b97d456..817253cd23573 100644 --- a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs +++ b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs @@ -296,17 +296,17 @@ export default { description: "The zero-based index of the rule", }, }, - async run() { + async run({ $ }) { const { startCol, endCol, startRow, endRow, - } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const rule = { range: { - sheetId: this.props.worksheetId, + sheetId: this.worksheetId, startRowIndex: startRow, endRowIndex: endRow, startColumnIndex: startCol.charCodeAt(0) - 65, @@ -342,130 +342,130 @@ export default { .join(""); }; - this.props.formattingType === "GRADIENT_RULE" ? + this.formattingType === "GRADIENT_RULE" ? rule.gradientRule = { minpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MIN", }, }, midpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MID", }, }, maxpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MAX", }, }, } : rule.booleanRule = { condition: { - type: this.props.conditionType, - values: this.props.conditionValues?.map((v) => ({ + type: this.conditionType, + values: this.conditionValues?.map((v) => ({ userEnteredValue: v, })) || [], }, format: { cellFormat: { numberFormat: { - type: this.props.numberFormatType, + type: this.numberFormatType, }, backgroundColorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, borders: { top: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, bottom: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, left: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, right: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, }, padding: { - top: this.props.topPadding, - right: this.props.rightPadding, - bottom: this.props.bottomPadding, - left: this.props.leftPadding, + top: this.topPadding, + right: this.rightPadding, + bottom: this.bottomPadding, + left: this.leftPadding, }, - horizontalAlignment: this.props.horizontalAlign, - verticalAlignment: this.props.verticalAlign, - wrapStrategy: this.props.wrapStrategy, - textDirection: this.props.textDirection, + horizontalAlignment: this.horizontalAlign, + verticalAlignment: this.verticalAlign, + wrapStrategy: this.wrapStrategy, + textDirection: this.textDirection, textFormat: { - ...this.props.textFormat, + ...this.textFormat, foregroundColorStyle: { - rgbColor: this.props.rgbColor, + rgbColor: this.rgbColor, themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - fontFamily: this.props.fontFamily, - fontSize: this.props.fontSize, - bold: this.props.bold, - italic: this.props.italic, - underline: this.props.underline, - strikethrough: this.props.strikethrough, + fontFamily: this.fontFamily, + fontSize: this.fontSize, + bold: this.bold, + italic: this.italic, + underline: this.underline, + strikethrough: this.strikethrough, link: { - url: this.props.url, + url: this.url, }, }, - hyperlinkDisplayType: this.props.hyperlinkDisplayType, + hyperlinkDisplayType: this.hyperlinkDisplayType, textRotation: { angle: 0, vertical: false, @@ -475,18 +475,19 @@ export default { }; const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { addConditionalFormatRuleRequest: { rule, - index: this.props.index, + index: this.index, }, }, ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully added conditional format rule."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs index db3f099273cc4..37683454093f0 100644 --- a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs +++ b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs @@ -78,34 +78,34 @@ export default { optional: true, }, }, - async run() { + async run({ $ }) { const { startCol, endCol, startRow, endRow, - } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { addProtectedRangeRequest: { protectedRange: { - protectedRangeId: this.props.protectedRangeId, + protectedRangeId: this.protectedRangeId, range: { - sheetId: this.props.worksheetId, + sheetId: this.worksheetId, startRowIndex: startRow, endRowIndex: endRow, startColumnIndex: startCol.charCodeAt(0) - 65, endColumnIndex: endCol.charCodeAt(0) - 64, }, - description: this.props.description, - warningOnly: this.props.warningOnly, - requestingUserCanEdit: this.props.requestingUserCanEdit, + description: this.description, + warningOnly: this.warningOnly, + requestingUserCanEdit: this.requestingUserCanEdit, editors: { - users: this.props.protectors || [], + users: this.protectors || [], }, }, }, @@ -113,6 +113,7 @@ export default { ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully added protected range."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs index ae36064d3e57c..c6ed3f9d071b0 100644 --- a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs +++ b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs @@ -43,20 +43,21 @@ export default { description: "The zero-based index of the rule", }, }, - async run() { + async run({ $ }) { const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { deleteConditionalFormatRuleRequest: { - sheetId: this.props.worksheetId, - index: this.props.index, + sheetId: this.worksheetId, + index: this.index, }, }, ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully deleted conditional format rule."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/actions/merge-cells/merge-cells.mjs b/components/google_sheets/actions/merge-cells/merge-cells.mjs index 2a12e9f6a6fa8..062511db35377 100644 --- a/components/google_sheets/actions/merge-cells/merge-cells.mjs +++ b/components/google_sheets/actions/merge-cells/merge-cells.mjs @@ -56,33 +56,34 @@ export default { default: "MERGE_ALL", }, }, - async run() { + async run({ $ }) { const { startCol, endCol, startRow, endRow, - } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { mergeCellsRequest: { range: { - sheetId: this.props.worksheetId, + sheetId: this.worksheetId, startRowIndex: startRow, endRowIndex: endRow, startColumnIndex: startCol.charCodeAt(0) - 65, endColumnIndex: endCol.charCodeAt(0) - 64, }, - mergeType: this.props.mergeType, + mergeType: this.mergeType, }, }, ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully merged cells."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs index 4ee140f9a14ec..4b407d6ceef92 100644 --- a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs +++ b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs @@ -83,22 +83,22 @@ export default { optional: true, }, }, - async run() { + async run({ $ }) { const { startCol, endCol, startRow, endRow, - } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { setDataValidation: { range: { - sheetId: this.props.worksheetId, + sheetId: this.worksheetId, startRowIndex: startRow, endRowIndex: endRow, startColumnIndex: startCol.charCodeAt(0) - 65, @@ -106,8 +106,8 @@ export default { }, rule: { condition: { - type: this.props.validationType, - values: this.props.validationValues?.map((v) => ({ + type: this.validationType, + values: this.validationValues?.map((v) => ({ userEnteredValue: v, })) || [], }, @@ -119,6 +119,7 @@ export default { ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully set data validation."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs index dc0412317f014..e6e5c58a78bb3 100644 --- a/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs +++ b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs @@ -104,7 +104,6 @@ export default { "TIME", "DATE", "DATE_TIME", - "SCIENTIFIC", ], optional: true, }, @@ -301,17 +300,17 @@ export default { description: "The new zero-based index of the rule", }, }, - async run() { + async run({ $ }) { const { startCol, endCol, startRow, endRow, - } = this.props.googleSheets._parseRangeString(`${this.props.worksheetId}!${this.props.range}`); + } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const rule = { range: { - sheetId: this.props.worksheetId, + sheetId: this.worksheetId, startRowIndex: startRow, endRowIndex: endRow, startColumnIndex: startCol.charCodeAt(0) - 65, @@ -346,130 +345,130 @@ export default { .join(""); }; - this.props.formattingType === "GRADIENT_RULE" ? + this.formattingType === "GRADIENT_RULE" ? rule.gradientRule = { minpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MIN", }, }, midpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MID", }, }, maxpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - type: this.props.InterpolationPointType, + type: this.InterpolationPointType, value: "MAX", }, }, } : rule.booleanRule = { condition: { - type: this.props.conditionType, - values: this.props.conditionValues?.map((v) => ({ + type: this.conditionType, + values: this.conditionValues?.map((v) => ({ userEnteredValue: v, })) || [], }, format: { cellFormat: { numberFormat: { - type: this.props.numberFormatType, + type: this.numberFormatType, }, backgroundColorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, borders: { top: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, bottom: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, left: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, right: { - style: this.props.borderStyle, + style: this.borderStyle, colorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, }, }, padding: { - top: this.props.topPadding, - right: this.props.rightPadding, - bottom: this.props.bottomPadding, - left: this.props.leftPadding, + top: this.topPadding, + right: this.rightPadding, + bottom: this.bottomPadding, + left: this.leftPadding, }, - horizontalAlignment: this.props.horizontalAlign, - verticalAlignment: this.props.verticalAlign, - wrapStrategy: this.props.wrapStrategy, - textDirection: this.props.textDirection, + horizontalAlignment: this.horizontalAlign, + verticalAlignment: this.verticalAlign, + wrapStrategy: this.wrapStrategy, + textDirection: this.textDirection, textFormat: { ...this.textFormat, foregroundColorStyle: { - rgbColor: protoToCssColor(this.props.rgbColor), + rgbColor: protoToCssColor(this.rgbColor), themeColor: { - type: this.props.themeColorType, + type: this.themeColorType, }, }, - fontFamily: this.props.fontFamily, - fontSize: this.props.fontSize, - bold: this.props.bold, - italic: this.props.italic, - underline: this.props.underline, - strikethrough: this.props.strikethrough, + fontFamily: this.fontFamily, + fontSize: this.fontSize, + bold: this.bold, + italic: this.italic, + underline: this.underline, + strikethrough: this.strikethrough, link: { - url: this.props.url, + url: this.url, }, }, - hyperlinkDisplayType: this.props.hyperlinkDisplayType, + hyperlinkDisplayType: this.hyperlinkDisplayType, textRotation: { angle: 0, vertical: false, @@ -479,20 +478,21 @@ export default { }; const request = { - spreadsheetId: this.props.sheetId, + spreadsheetId: this.sheetId, requestBody: { requests: [ { updateConditionalFormatRuleRequest: { - index: this.props.index, - sheetId: this.props.worksheetId, + index: this.index, + sheetId: this.worksheetId, rule, - newIndex: this.props.newIndex, + newIndex: this.newIndex, }, }, ], }, }; - return await this.props.googleSheets.batchUpdate(request); + $.export("$summary", "Successfully updated conditional format rule."); + return await this.googleSheets.batchUpdate(request); }, }; diff --git a/components/google_sheets/package.json b/components/google_sheets/package.json index 0b0021b697c69..65bc7365d07b2 100644 --- a/components/google_sheets/package.json +++ b/components/google_sheets/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/google_sheets", - "version": "0.10.0", + "version": "0.11.0", "description": "Pipedream Google_sheets Components", "main": "google_sheets.app.mjs", "keywords": [ From 1fd1c8747baf1ebfadf3479c21a5caba018fcc1c Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Tue, 11 Nov 2025 10:40:27 -0500 Subject: [PATCH 03/10] Update components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../add-conditional-format-rule/add-conditional-format-rule.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs index 817253cd23573..af7d0a2db7c7f 100644 --- a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs +++ b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs @@ -104,7 +104,6 @@ export default { "TIME", "DATE", "DATE_TIME", - "SCIENTIFIC", ], optional: true, }, From 2bd89c2d782cb881ff4062c175bfbf552cd82da1 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Tue, 11 Nov 2025 10:41:20 -0500 Subject: [PATCH 04/10] Update components/google_sheets/actions/set-data-validation/set-data-validation.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../actions/set-data-validation/set-data-validation.mjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs index 4b407d6ceef92..99ee81ab45e0a 100644 --- a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs +++ b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs @@ -53,12 +53,9 @@ export default { "NUMBER_GREATER_THAN_EQ", "NUMBER_LESS_THAN_EQ", "NUMBER_LESS", - "NUMBER_BETWEEN", "TEXT_CONTAINS", "TEXT_NOT_CONTAINS", "DATE_EQUAL_TO", - "DATE_BEFORE", - "DATE_AFTER", "ONE_OF_LIST", "DATE_AFTER", "DATE_ON_OR_AFTER", From 9f4436346bdc0a2aa04c497ebcfeb2bdf8f9ff50 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 13:16:28 -0500 Subject: [PATCH 05/10] add-conditional-format-rule updates --- .../add-conditional-format-rule.mjs | 361 +++--------------- 1 file changed, 46 insertions(+), 315 deletions(-) diff --git a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs index af7d0a2db7c7f..4abe7ae7d062a 100644 --- a/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs +++ b/components/google_sheets/actions/add-conditional-format-rule/add-conditional-format-rule.mjs @@ -1,18 +1,5 @@ import googleSheets from "../../google_sheets.app.mjs"; - -function rgbToCssColor(red, green, blue) { - var rgbNumber = (red << 16) | (green << 8) | blue; - var hexString = rgbNumber.toString(16); - var missingZeros = 6 - hexString.length; - var resultBuilder = [ - "#", - ]; - for (var i = 0; i < missingZeros; i++) { - resultBuilder.push("0"); - } - resultBuilder.push(hexString); - return resultBuilder.join(""); -} +import { ConfigurationError } from "@pipedream/platform"; export default { key: "google_sheets-add-conditional-format-rule", @@ -56,7 +43,7 @@ export default { googleSheets, "range", ], - description: "The range of cells to protect (e.g., `A1:A10`)", + description: "The range of cells to format (e.g., `A1:A10`)", }, conditionType: { type: "string", @@ -73,13 +60,11 @@ export default { "TEXT_IS_URL", "BOOLEAN", ], - optional: true, }, conditionValues: { type: "string[]", label: "Condition Values", description: "Values for condition (e.g., color scales or custom formulas)", - optional: true, }, formattingType: { type: "string", @@ -91,131 +76,10 @@ export default { ], default: "BOOLEAN_RULE", }, - numberFormatType: { - type: "string", - label: "Number Format Type", - description: "The type of number format", - options: [ - "NUMBER", - "CURRENCY", - "PERCENT", - "SCIENTIFIC", - "TEXT", - "TIME", - "DATE", - "DATE_TIME", - ], - optional: true, - }, rgbColor: { type: "object", label: "RGB Color", - description: "The RGB color value (e.g., {red: 1.0, green: 0.5, blue: 0.2})", - optional: true, - }, - themeColorType: { - type: "string", - label: "Theme Color Type", - description: "The theme color type", - options: [ - "TEXT", - "BACKGROUND", - "ACCENT1", - "ACCENT2", - "ACCENT3", - "ACCENT4", - "ACCENT5", - "ACCENT6", - "LINK", - ], - optional: true, - }, - borderStyle: { - type: "string", - label: "Border Style", - description: "The border style", - options: [ - "SOLID", - "DASHED", - "DOTTED", - "DOUBLE", - "GROOVE", - "RIDGE", - "INSET", - "OUTSET", - ], - optional: true, - }, - topPadding: { - type: "integer", - label: "Top Padding", - description: "The top padding in pixels", - optional: true, - default: 0, - }, - rightPadding: { - type: "integer", - label: "Right Padding", - description: "The right padding in pixels", - optional: true, - default: 0, - }, - bottomPadding: { - type: "integer", - label: "Bottom Padding", - description: "The bottom padding in pixels", - optional: true, - default: 0, - }, - leftPadding: { - type: "integer", - label: "Left Padding", - description: "The left padding in pixels", - optional: true, - default: 0, - }, - horizontalAlign: { - type: "string", - label: "Horizontal Align", - description: "The horizontal alignment", - options: [ - "LEFT", - "CENTER", - "RIGHT", - ], - optional: true, - }, - verticalAlign: { - type: "string", - label: "Vertical Align", - description: "The vertical alignment", - options: [ - "TOP", - "MIDDLE", - "BOTTOM", - ], - optional: true, - }, - wrapStrategy: { - type: "string", - label: "Wrap Strategy", - description: "The wrap strategy", - options: [ - "OVERFLOW_CELL", - "LEGACY_WRAP", - "CLIP", - "WRAP", - ], - optional: true, - }, - textDirection: { - type: "string", - label: "Text Direction", - description: "The text direction", - options: [ - "LEFT_TO_RIGHT", - "RIGHT_TO_LEFT", - ], + description: "The RGB color value (e.g., {\"red\": 1.0, \"green\": 0.5, \"blue\": 0.2})", optional: true, }, textFormat: { @@ -224,18 +88,6 @@ export default { description: "The text format options", optional: true, }, - fontFamily: { - type: "string", - label: "Font Family", - description: "The font family", - optional: true, - }, - fontSize: { - type: "integer", - label: "Font Size", - description: "The font size", - optional: true, - }, bold: { type: "boolean", label: "Bold", @@ -248,35 +100,13 @@ export default { description: "Whether the text is italic", optional: true, }, - underline: { - type: "boolean", - label: "Underline", - description: "Whether the text is underlined", - optional: true, - }, strikethrough: { type: "boolean", label: "Strikethrough", description: "Whether the text is strikethrough", optional: true, }, - url: { - type: "string", - label: "URL", - description: "The URL for the link", - optional: true, - }, - hyperlinkDisplayType: { - type: "string", - label: "Hyperlink Display Type", - description: "The hyperlink display type", - options: [ - "PLAIN_TEXT", - "LINKED", - ], - optional: true, - }, - InterpolationPointType: { + interpolationPointType: { type: "string", label: "Interpolation Point Type", description: "The interpolation point type", @@ -304,80 +134,50 @@ export default { } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const rule = { - range: { - sheetId: this.worksheetId, - startRowIndex: startRow, - endRowIndex: endRow, - startColumnIndex: startCol.charCodeAt(0) - 65, - endColumnIndex: endCol.charCodeAt(0) - 64, - }, + ranges: [ + { + sheetId: this.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + ], }; - const protoToCssColor = (rgbColor) => { - var redFrac = rgbColor.red || 0.0; - var greenFrac = rgbColor.green || 0.0; - var blueFrac = rgbColor.blue || 0.0; - var red = Math.floor(redFrac * 255); - var green = Math.floor(greenFrac * 255); - var blue = Math.floor(blueFrac * 255); - - if (!("alpha" in rgbColor)) { - return rgbToCssColor(red, green, blue); + const parseRgbColor = (rgbColor = {}) => { + if (typeof rgbColor === "string") { + try { + rgbColor = JSON.parse(rgbColor); + } catch { + throw new ConfigurationError("Could not parse RGB Color. Please provide a valid JSON object."); + } } - - var alphaFrac = rgbColor.alpha.value || 0.0; - var rgbParams = [ - red, - green, - blue, - ].join(","); - return [ - "rgba(", - rgbParams, - ",", - alphaFrac, - ")", - ] - .join(""); + return rgbColor; }; this.formattingType === "GRADIENT_RULE" ? rule.gradientRule = { minpoint: { - interpolationPoint: { - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - type: this.InterpolationPointType, - value: "MIN", + colorStyle: { + rgbColor: parseRgbColor(this.rgbColor), }, + type: this.interpolationPointType, + value: "MIN", }, midpoint: { - interpolationPoint: { - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - type: this.InterpolationPointType, - value: "MID", + colorStyle: { + rgbColor: parseRgbColor(this.rgbColor), }, + type: this.interpolationPointType, + value: "MID", }, maxpoint: { - interpolationPoint: { - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - type: this.InterpolationPointType, - value: "MAX", + colorStyle: { + rgbColor: parseRgbColor(this.rgbColor), }, + type: this.interpolationPointType, + value: "MAX", }, } : rule.booleanRule = { @@ -388,87 +188,17 @@ export default { })) || [], }, format: { - cellFormat: { - numberFormat: { - type: this.numberFormatType, - }, - backgroundColorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - borders: { - top: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - bottom: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - left: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - right: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - }, - padding: { - top: this.topPadding, - right: this.rightPadding, - bottom: this.bottomPadding, - left: this.leftPadding, - }, - horizontalAlignment: this.horizontalAlign, - verticalAlignment: this.verticalAlign, - wrapStrategy: this.wrapStrategy, - textDirection: this.textDirection, - textFormat: { - ...this.textFormat, - foregroundColorStyle: { - rgbColor: this.rgbColor, - themeColor: { - type: this.themeColorType, - }, - }, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - bold: this.bold, - italic: this.italic, - underline: this.underline, - strikethrough: this.strikethrough, - link: { - url: this.url, - }, - }, - hyperlinkDisplayType: this.hyperlinkDisplayType, - textRotation: { - angle: 0, - vertical: false, + backgroundColorStyle: { + rgbColor: parseRgbColor(this.rgbColor), + }, + textFormat: { + ...this.textFormat, + foregroundColorStyle: { + rgbColor: parseRgbColor(this.rgbColor), }, + bold: this.bold, + italic: this.italic, + strikethrough: this.strikethrough, }, }, }; @@ -478,7 +208,7 @@ export default { requestBody: { requests: [ { - addConditionalFormatRuleRequest: { + addConditionalFormatRule: { rule, index: this.index, }, @@ -486,7 +216,8 @@ export default { ], }, }; + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully added conditional format rule."); - return await this.googleSheets.batchUpdate(request); + return response; }, }; From 4258d3faa4aab2ec76a1180d23d0d53f409c286d Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 13:34:32 -0500 Subject: [PATCH 06/10] add-protected-range updates --- .../add-protected-range/add-protected-range.mjs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs index 37683454093f0..50849f26f6a18 100644 --- a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs +++ b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs @@ -49,7 +49,6 @@ export default { "range", ], description: "The range of cells to protect (e.g., `A1:A10`). Required for add and update operations", - optional: true, }, description: { type: "string", @@ -57,13 +56,6 @@ export default { description: "A description of the protected range", optional: true, }, - warningOnly: { - type: "boolean", - label: "Warning Only", - description: "If true, users will see a warning when editing but can still modify. If false, editing is blocked", - optional: true, - default: false, - }, requestingUserCanEdit: { type: "boolean", label: "Requesting User Can Edit", @@ -91,7 +83,7 @@ export default { requestBody: { requests: [ { - addProtectedRangeRequest: { + addProtectedRange: { protectedRange: { protectedRangeId: this.protectedRangeId, range: { @@ -102,7 +94,6 @@ export default { endColumnIndex: endCol.charCodeAt(0) - 64, }, description: this.description, - warningOnly: this.warningOnly, requestingUserCanEdit: this.requestingUserCanEdit, editors: { users: this.protectors || [], From 8b35e3224e75c0ec583b67586f2fdbe03bc952b3 Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 13:39:16 -0500 Subject: [PATCH 07/10] delete-conditional-format-rule update --- .../delete-conditional-format-rule.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs index c6ed3f9d071b0..ba4cfcd44ca1a 100644 --- a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs +++ b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs @@ -49,7 +49,7 @@ export default { requestBody: { requests: [ { - deleteConditionalFormatRuleRequest: { + deleteConditionalFormatRule: { sheetId: this.worksheetId, index: this.index, }, From 64cbac5a1d6094dbcc3ecd1dcaf3f676a5161a9f Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 13:44:25 -0500 Subject: [PATCH 08/10] merge-cells update --- .../actions/add-protected-range/add-protected-range.mjs | 3 ++- .../delete-conditional-format-rule.mjs | 3 ++- components/google_sheets/actions/merge-cells/merge-cells.mjs | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs index 50849f26f6a18..374cfe7a9ddb3 100644 --- a/components/google_sheets/actions/add-protected-range/add-protected-range.mjs +++ b/components/google_sheets/actions/add-protected-range/add-protected-range.mjs @@ -104,7 +104,8 @@ export default { ], }, }; + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully added protected range."); - return await this.googleSheets.batchUpdate(request); + return response; }, }; diff --git a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs index ba4cfcd44ca1a..5fff05f0293e0 100644 --- a/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs +++ b/components/google_sheets/actions/delete-conditional-format-rule/delete-conditional-format-rule.mjs @@ -57,7 +57,8 @@ export default { ], }, }; + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully deleted conditional format rule."); - return await this.googleSheets.batchUpdate(request); + return response; }, }; diff --git a/components/google_sheets/actions/merge-cells/merge-cells.mjs b/components/google_sheets/actions/merge-cells/merge-cells.mjs index 062511db35377..d4312f374856c 100644 --- a/components/google_sheets/actions/merge-cells/merge-cells.mjs +++ b/components/google_sheets/actions/merge-cells/merge-cells.mjs @@ -69,7 +69,7 @@ export default { requestBody: { requests: [ { - mergeCellsRequest: { + mergeCells: { range: { sheetId: this.worksheetId, startRowIndex: startRow, @@ -83,7 +83,8 @@ export default { ], }, }; + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully merged cells."); - return await this.googleSheets.batchUpdate(request); + return response; }, }; From e158d5dc91dfe43fe9214de67be153bf7452554d Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 13:48:30 -0500 Subject: [PATCH 09/10] set-data-validation update --- .../actions/set-data-validation/set-data-validation.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs index 99ee81ab45e0a..00bae5364bb73 100644 --- a/components/google_sheets/actions/set-data-validation/set-data-validation.mjs +++ b/components/google_sheets/actions/set-data-validation/set-data-validation.mjs @@ -77,7 +77,6 @@ export default { type: "string[]", label: "Validation Values", description: "Values for validation (e.g., dropdown options)", - optional: true, }, }, async run({ $ }) { @@ -116,7 +115,8 @@ export default { ], }, }; + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully set data validation."); - return await this.googleSheets.batchUpdate(request); + return response; }, }; From 1ff970d1676565c4fb5280ba101470fc43d301fe Mon Sep 17 00:00:00 2001 From: Michelle Bergeron Date: Tue, 11 Nov 2025 14:09:42 -0500 Subject: [PATCH 10/10] update-conditional-format-rule updates --- .../update-conditional-format-rule.mjs | 338 ++---------------- 1 file changed, 39 insertions(+), 299 deletions(-) diff --git a/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs index e6e5c58a78bb3..ff8357f0df9a9 100644 --- a/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs +++ b/components/google_sheets/actions/update-conditional-format-rule/update-conditional-format-rule.mjs @@ -1,18 +1,5 @@ import googleSheets from "../../google_sheets.app.mjs"; - -function rgbToCssColor(red, green, blue) { - var rgbNumber = (red << 16) | (green << 8) | blue; - var hexString = rgbNumber.toString(16); - var missingZeros = 6 - hexString.length; - var resultBuilder = [ - "#", - ]; - for (var i = 0; i < missingZeros; i++) { - resultBuilder.push("0"); - } - resultBuilder.push(hexString); - return resultBuilder.join(""); -} +import { ConfigurationError } from "@pipedream/platform"; export default { key: "google_sheets-update-conditional-format-rule", @@ -73,13 +60,11 @@ export default { "TEXT_IS_URL", "BOOLEAN", ], - optional: true, }, conditionValues: { type: "string[]", label: "Condition Values", description: "Values for condition (e.g., color scales or custom formulas)", - optional: true, }, formattingType: { type: "string", @@ -91,131 +76,10 @@ export default { ], default: "BOOLEAN_RULE", }, - numberFormatType: { - type: "string", - label: "Number Format Type", - description: "The type of number format", - options: [ - "NUMBER", - "CURRENCY", - "PERCENT", - "SCIENTIFIC", - "TEXT", - "TIME", - "DATE", - "DATE_TIME", - ], - optional: true, - }, rgbColor: { type: "object", label: "RGB Color", - description: "The RGB color value", - optional: true, - }, - themeColorType: { - type: "string", - label: "Theme Color Type", - description: "The theme color type", - options: [ - "TEXT", - "BACKGROUND", - "ACCENT1", - "ACCENT2", - "ACCENT3", - "ACCENT4", - "ACCENT5", - "ACCENT6", - "LINK", - ], - optional: true, - }, - borderStyle: { - type: "string", - label: "Border Style", - description: "The border style", - options: [ - "SOLID", - "DASHED", - "DOTTED", - "DOUBLE", - "GROOVE", - "RIDGE", - "INSET", - "OUTSET", - ], - optional: true, - }, - topPadding: { - type: "integer", - label: "Top Padding", - description: "The top padding in pixels", - optional: true, - default: 0, - }, - rightPadding: { - type: "integer", - label: "Right Padding", - description: "The right padding in pixels", - optional: true, - default: 0, - }, - bottomPadding: { - type: "integer", - label: "Bottom Padding", - description: "The bottom padding in pixels", - optional: true, - default: 0, - }, - leftPadding: { - type: "integer", - label: "Left Padding", - description: "The left padding in pixels", - optional: true, - default: 0, - }, - horizontalAlign: { - type: "string", - label: "Horizontal Align", - description: "The horizontal alignment", - options: [ - "LEFT", - "CENTER", - "RIGHT", - ], - optional: true, - }, - verticalAlign: { - type: "string", - label: "Vertical Align", - description: "The vertical alignment", - options: [ - "TOP", - "MIDDLE", - "BOTTOM", - ], - optional: true, - }, - wrapStrategy: { - type: "string", - label: "Wrap Strategy", - description: "The wrap strategy", - options: [ - "OVERFLOW_CELL", - "LEGACY_WRAP", - "CLIP", - "WRAP", - ], - optional: true, - }, - textDirection: { - type: "string", - label: "Text Direction", - description: "The text direction", - options: [ - "LEFT_TO_RIGHT", - "RIGHT_TO_LEFT", - ], + description: "The RGB color value (e.g., {\"red\": 1.0, \"green\": 0.5, \"blue\": 0.2})", optional: true, }, textFormat: { @@ -224,18 +88,6 @@ export default { description: "The text format options", optional: true, }, - fontFamily: { - type: "string", - label: "Font Family", - description: "The font family", - optional: true, - }, - fontSize: { - type: "integer", - label: "Font Size", - description: "The font size", - optional: true, - }, bold: { type: "boolean", label: "Bold", @@ -248,35 +100,13 @@ export default { description: "Whether the text is italic", optional: true, }, - underline: { - type: "boolean", - label: "Underline", - description: "Whether the text is underlined", - optional: true, - }, strikethrough: { type: "boolean", label: "Strikethrough", description: "Whether the text is strikethrough", optional: true, }, - url: { - type: "string", - label: "URL", - description: "The URL for the link", - optional: true, - }, - hyperlinkDisplayType: { - type: "string", - label: "Hyperlink Display Type", - description: "The hyperlink display type", - options: [ - "PLAIN_TEXT", - "LINKED", - ], - optional: true, - }, - InterpolationPointType: { + interpolationPointType: { type: "string", label: "Interpolation Point Type", description: "The interpolation point type", @@ -298,6 +128,7 @@ export default { type: "integer", label: "New Index", description: "The new zero-based index of the rule", + optional: true, }, }, async run({ $ }) { @@ -309,40 +140,25 @@ export default { } = this.googleSheets._parseRangeString(`${this.worksheetId}!${this.range}`); const rule = { - range: { - sheetId: this.worksheetId, - startRowIndex: startRow, - endRowIndex: endRow, - startColumnIndex: startCol.charCodeAt(0) - 65, - endColumnIndex: endCol.charCodeAt(0) - 64, - }, + ranges: [ + { + sheetId: this.worksheetId, + startRowIndex: startRow, + endRowIndex: endRow, + startColumnIndex: startCol.charCodeAt(0) - 65, + endColumnIndex: endCol.charCodeAt(0) - 64, + }, + ], }; - const protoToCssColor = (rgbColor) => { - var redFrac = rgbColor.red || 0.0; - var greenFrac = rgbColor.green || 0.0; - var blueFrac = rgbColor.blue || 0.0; - var red = Math.floor(redFrac * 255); - var green = Math.floor(greenFrac * 255); - var blue = Math.floor(blueFrac * 255); - - if (!("alpha" in rgbColor)) { - return rgbToCssColor(red, green, blue); + const parseRgbColor = (rgbColor = {}) => { + if (typeof rgbColor === "string") { + try { + rgbColor = JSON.parse(rgbColor); + } catch { + throw new ConfigurationError("Could not parse RGB Color. Please provide a valid JSON object."); + } } - - var alphaFrac = rgbColor.alpha.value || 0.0; - var rgbParams = [ - red, - green, - blue, - ].join(","); - return [ - "rgba(", - rgbParams, - ",", - alphaFrac, - ")", - ] - .join(""); + return rgbColor; }; this.formattingType === "GRADIENT_RULE" ? @@ -350,10 +166,7 @@ export default { minpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, + rgbColor: parseRgbColor(this.rgbColor), }, type: this.InterpolationPointType, value: "MIN", @@ -362,10 +175,7 @@ export default { midpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, + rgbColor: parseRgbColor(this.rgbColor), }, type: this.InterpolationPointType, value: "MID", @@ -374,10 +184,7 @@ export default { maxpoint: { interpolationPoint: { colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, + rgbColor: parseRgbColor(this.rgbColor), }, type: this.InterpolationPointType, value: "MAX", @@ -392,87 +199,18 @@ export default { })) || [], }, format: { - cellFormat: { - numberFormat: { - type: this.numberFormatType, - }, - backgroundColorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - borders: { - top: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - bottom: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - left: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - right: { - style: this.borderStyle, - colorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - }, - }, - padding: { - top: this.topPadding, - right: this.rightPadding, - bottom: this.bottomPadding, - left: this.leftPadding, - }, - horizontalAlignment: this.horizontalAlign, - verticalAlignment: this.verticalAlign, - wrapStrategy: this.wrapStrategy, - textDirection: this.textDirection, - textFormat: { - ...this.textFormat, - foregroundColorStyle: { - rgbColor: protoToCssColor(this.rgbColor), - themeColor: { - type: this.themeColorType, - }, - }, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - bold: this.bold, - italic: this.italic, - underline: this.underline, - strikethrough: this.strikethrough, - link: { - url: this.url, - }, - }, - hyperlinkDisplayType: this.hyperlinkDisplayType, - textRotation: { - angle: 0, - vertical: false, + backgroundColorStyle: { + rgbColor: parseRgbColor(this.rgbColor), + }, + textFormat: { + ...this.textFormat, + foregroundColorStyle: { + rgbColor: parseRgbColor(this.rgbColor), + }, + bold: this.bold, + italic: this.italic, + strikethrough: this.strikethrough, }, }, }; @@ -482,7 +220,7 @@ export default { requestBody: { requests: [ { - updateConditionalFormatRuleRequest: { + updateConditionalFormatRule: { index: this.index, sheetId: this.worksheetId, rule, @@ -492,7 +230,9 @@ export default { ], }, }; + + const response = await this.googleSheets.batchUpdate(request); $.export("$summary", "Successfully updated conditional format rule."); - return await this.googleSheets.batchUpdate(request); + return response; }, };