diff --git a/apps/docs/content/docs/en/tools/microsoft_excel.mdx b/apps/docs/content/docs/en/tools/microsoft_excel.mdx index f46f5462b1..f260e0653f 100644 --- a/apps/docs/content/docs/en/tools/microsoft_excel.mdx +++ b/apps/docs/content/docs/en/tools/microsoft_excel.mdx @@ -27,7 +27,7 @@ In Sim, the Microsoft Excel integration provides seamless access to spreadsheet ## Usage Instructions -Integrate Microsoft Excel into the workflow. Can read, write, update, and add to table. +Integrate Microsoft Excel into the workflow. Can read, write, update, add to table, and create new worksheets. @@ -94,6 +94,23 @@ Add new rows to a Microsoft Excel table | `values` | array | Array of rows that were added to the table | | `metadata` | object | Spreadsheet metadata | +### `microsoft_excel_worksheet_add` + +Create a new worksheet (sheet) in a Microsoft Excel workbook + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `spreadsheetId` | string | Yes | The ID of the Excel workbook to add the worksheet to | +| `worksheetName` | string | Yes | The name of the new worksheet. Must be unique within the workbook and cannot exceed 31 characters | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `worksheet` | object | Details of the newly created worksheet | + ## Notes diff --git a/apps/sim/blocks/blocks/microsoft_excel.ts b/apps/sim/blocks/blocks/microsoft_excel.ts index f6b9d58ec4..d05c1fc7e7 100644 --- a/apps/sim/blocks/blocks/microsoft_excel.ts +++ b/apps/sim/blocks/blocks/microsoft_excel.ts @@ -9,7 +9,7 @@ export const MicrosoftExcelBlock: BlockConfig = { description: 'Read, write, and update data', authMode: AuthMode.OAuth, longDescription: - 'Integrate Microsoft Excel into the workflow. Can read, write, update, and add to table.', + 'Integrate Microsoft Excel into the workflow. Can read, write, update, add to table, and create new worksheets.', docsLink: 'https://docs.sim.ai/tools/microsoft_excel', category: 'tools', bgColor: '#E0E0E0', @@ -23,6 +23,7 @@ export const MicrosoftExcelBlock: BlockConfig = { { label: 'Read Data', id: 'read' }, { label: 'Write/Update Data', id: 'write' }, { label: 'Add to Table', id: 'table_add' }, + { label: 'Add Worksheet', id: 'worksheet_add' }, ], value: () => 'read', }, @@ -80,6 +81,14 @@ export const MicrosoftExcelBlock: BlockConfig = { condition: { field: 'operation', value: ['table_add'] }, required: true, }, + { + id: 'worksheetName', + title: 'Worksheet Name', + type: 'short-input', + placeholder: 'Name of the new worksheet (max 31 characters)', + condition: { field: 'operation', value: ['worksheet_add'] }, + required: true, + }, { id: 'values', title: 'Values', @@ -129,7 +138,12 @@ export const MicrosoftExcelBlock: BlockConfig = { }, ], tools: { - access: ['microsoft_excel_read', 'microsoft_excel_write', 'microsoft_excel_table_add'], + access: [ + 'microsoft_excel_read', + 'microsoft_excel_write', + 'microsoft_excel_table_add', + 'microsoft_excel_worksheet_add', + ], config: { tool: (params) => { switch (params.operation) { @@ -139,13 +153,22 @@ export const MicrosoftExcelBlock: BlockConfig = { return 'microsoft_excel_write' case 'table_add': return 'microsoft_excel_table_add' + case 'worksheet_add': + return 'microsoft_excel_worksheet_add' default: throw new Error(`Invalid Microsoft Excel operation: ${params.operation}`) } }, params: (params) => { - const { credential, values, spreadsheetId, manualSpreadsheetId, tableName, ...rest } = - params + const { + credential, + values, + spreadsheetId, + manualSpreadsheetId, + tableName, + worksheetName, + ...rest + } = params const effectiveSpreadsheetId = (spreadsheetId || manualSpreadsheetId || '').trim() @@ -164,6 +187,10 @@ export const MicrosoftExcelBlock: BlockConfig = { throw new Error('Table name is required for table operations.') } + if (params.operation === 'worksheet_add' && !worksheetName) { + throw new Error('Worksheet name is required for worksheet operations.') + } + const baseParams = { ...rest, spreadsheetId: effectiveSpreadsheetId, @@ -178,6 +205,13 @@ export const MicrosoftExcelBlock: BlockConfig = { } } + if (params.operation === 'worksheet_add') { + return { + ...baseParams, + worksheetName, + } + } + return baseParams }, }, @@ -189,6 +223,7 @@ export const MicrosoftExcelBlock: BlockConfig = { manualSpreadsheetId: { type: 'string', description: 'Manual spreadsheet identifier' }, range: { type: 'string', description: 'Cell range' }, tableName: { type: 'string', description: 'Table name' }, + worksheetName: { type: 'string', description: 'Worksheet name' }, values: { type: 'string', description: 'Cell values data' }, valueInputOption: { type: 'string', description: 'Value input option' }, }, @@ -207,5 +242,9 @@ export const MicrosoftExcelBlock: BlockConfig = { }, index: { type: 'number', description: 'Row index for table add operations' }, values: { type: 'json', description: 'Cell values array for table add operations' }, + worksheet: { + type: 'json', + description: 'Details of the newly created worksheet (worksheet_add operations)', + }, }, } diff --git a/apps/sim/tools/microsoft_excel/index.ts b/apps/sim/tools/microsoft_excel/index.ts index 019f0beac9..757b331d91 100644 --- a/apps/sim/tools/microsoft_excel/index.ts +++ b/apps/sim/tools/microsoft_excel/index.ts @@ -1,7 +1,9 @@ import { readTool } from '@/tools/microsoft_excel/read' import { tableAddTool } from '@/tools/microsoft_excel/table_add' +import { worksheetAddTool } from '@/tools/microsoft_excel/worksheet_add' import { writeTool } from '@/tools/microsoft_excel/write' export const microsoftExcelReadTool = readTool export const microsoftExcelTableAddTool = tableAddTool +export const microsoftExcelWorksheetAddTool = worksheetAddTool export const microsoftExcelWriteTool = writeTool diff --git a/apps/sim/tools/microsoft_excel/types.ts b/apps/sim/tools/microsoft_excel/types.ts index a3ed2d8036..c07e0b3f65 100644 --- a/apps/sim/tools/microsoft_excel/types.ts +++ b/apps/sim/tools/microsoft_excel/types.ts @@ -48,6 +48,18 @@ export interface MicrosoftExcelTableAddResponse extends ToolResponse { } } +export interface MicrosoftExcelWorksheetAddResponse extends ToolResponse { + output: { + worksheet: { + id: string + name: string + position: number + visibility: string + } + metadata: MicrosoftExcelMetadata + } +} + export interface MicrosoftExcelToolParams { accessToken: string spreadsheetId: string @@ -68,7 +80,14 @@ export interface MicrosoftExcelTableToolParams { rowIndex?: number } +export interface MicrosoftExcelWorksheetToolParams { + accessToken: string + spreadsheetId: string + worksheetName: string +} + export type MicrosoftExcelResponse = | MicrosoftExcelReadResponse | MicrosoftExcelWriteResponse | MicrosoftExcelTableAddResponse + | MicrosoftExcelWorksheetAddResponse diff --git a/apps/sim/tools/microsoft_excel/worksheet_add.ts b/apps/sim/tools/microsoft_excel/worksheet_add.ts new file mode 100644 index 0000000000..71af58017d --- /dev/null +++ b/apps/sim/tools/microsoft_excel/worksheet_add.ts @@ -0,0 +1,161 @@ +import type { + MicrosoftExcelWorksheetAddResponse, + MicrosoftExcelWorksheetToolParams, +} from '@/tools/microsoft_excel/types' +import { getSpreadsheetWebUrl } from '@/tools/microsoft_excel/utils' +import type { ToolConfig } from '@/tools/types' + +/** + * Tool for adding a new worksheet to a Microsoft Excel workbook + * Uses Microsoft Graph API endpoint: POST /me/drive/items/{id}/workbook/worksheets/add + */ +export const worksheetAddTool: ToolConfig< + MicrosoftExcelWorksheetToolParams, + MicrosoftExcelWorksheetAddResponse +> = { + id: 'microsoft_excel_worksheet_add', + name: 'Add Worksheet to Microsoft Excel', + description: 'Create a new worksheet (sheet) in a Microsoft Excel workbook', + version: '1.0', + + oauth: { + required: true, + provider: 'microsoft-excel', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'The access token for the Microsoft Excel API', + }, + spreadsheetId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The ID of the Excel workbook to add the worksheet to', + }, + worksheetName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The name of the new worksheet. Must be unique within the workbook and cannot exceed 31 characters', + }, + }, + + request: { + url: (params) => { + const spreadsheetId = params.spreadsheetId?.trim() + if (!spreadsheetId) { + throw new Error('Spreadsheet ID is required') + } + return `https://graph.microsoft.com/v1.0/me/drive/items/${spreadsheetId}/workbook/worksheets/add` + }, + method: 'POST', + headers: (params) => { + if (!params.accessToken) { + throw new Error('Access token is required') + } + + return { + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + } + }, + body: (params) => { + const worksheetName = params.worksheetName?.trim() + + if (!worksheetName) { + throw new Error('Worksheet name is required') + } + + // Validate worksheet name length (Excel limitation) + if (worksheetName.length > 31) { + throw new Error('Worksheet name cannot exceed 31 characters. Please provide a shorter name') + } + + // Validate worksheet name doesn't contain invalid characters + const invalidChars = ['\\', '/', '?', '*', '[', ']', ':'] + for (const char of invalidChars) { + if (worksheetName.includes(char)) { + throw new Error(`Worksheet name cannot contain the following characters: \\ / ? * [ ] :`) + } + } + + return { + name: worksheetName, + } + }, + }, + + transformResponse: async (response: Response, params?: MicrosoftExcelWorksheetToolParams) => { + if (!response.ok) { + const errorData = await response.json().catch(() => ({})) + const errorMessage = + errorData?.error?.message || `Failed to create worksheet: ${response.statusText}` + + // Handle specific error cases + if (response.status === 409) { + throw new Error('A worksheet with this name already exists. Please choose a different name') + } + + throw new Error(errorMessage) + } + + const data = await response.json() + + const urlParts = response.url.split('/drive/items/') + const spreadsheetId = urlParts[1]?.split('/')[0] || '' + + // Fetch the browser-accessible web URL + const accessToken = params?.accessToken + if (!accessToken) { + throw new Error('Access token is required') + } + const webUrl = await getSpreadsheetWebUrl(spreadsheetId, accessToken) + + const result: MicrosoftExcelWorksheetAddResponse = { + success: true, + output: { + worksheet: { + id: data.id || '', + name: data.name || '', + position: data.position ?? 0, + visibility: data.visibility || 'Visible', + }, + metadata: { + spreadsheetId, + spreadsheetUrl: webUrl, + }, + }, + } + + return result + }, + + outputs: { + worksheet: { + type: 'object', + description: 'Details of the newly created worksheet', + properties: { + id: { type: 'string', description: 'The unique ID of the worksheet' }, + name: { type: 'string', description: 'The name of the worksheet' }, + position: { type: 'number', description: 'The zero-based position of the worksheet' }, + visibility: { + type: 'string', + description: 'The visibility state of the worksheet (Visible/Hidden/VeryHidden)', + }, + }, + }, + metadata: { + type: 'object', + description: 'Spreadsheet metadata', + properties: { + spreadsheetId: { type: 'string', description: 'The ID of the spreadsheet' }, + spreadsheetUrl: { type: 'string', description: 'URL to access the spreadsheet' }, + }, + }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 94689d6b78..243c4988e0 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -348,6 +348,7 @@ import { memoryAddTool, memoryDeleteTool, memoryGetAllTool, memoryGetTool } from import { microsoftExcelReadTool, microsoftExcelTableAddTool, + microsoftExcelWorksheetAddTool, microsoftExcelWriteTool, } from '@/tools/microsoft_excel' import { @@ -1172,6 +1173,7 @@ export const tools: Record = { microsoft_excel_read: microsoftExcelReadTool, microsoft_excel_write: microsoftExcelWriteTool, microsoft_excel_table_add: microsoftExcelTableAddTool, + microsoft_excel_worksheet_add: microsoftExcelWorksheetAddTool, microsoft_planner_create_task: microsoftPlannerCreateTaskTool, microsoft_planner_read_task: microsoftPlannerReadTaskTool, microsoft_planner_update_task: microsoftPlannerUpdateTaskTool,