mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
feat(Google Sheets Node): Add "By Name" option to selector for Sheets (#8241)
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
parent
e796e7f06d
commit
dce28f9cb9
|
@ -12,7 +12,7 @@ import { apiRequest } from './v2/transport';
|
|||
import { sheetsSearch, spreadSheetsSearch } from './v2/methods/listSearch';
|
||||
import { GoogleSheet } from './v2/helpers/GoogleSheet';
|
||||
import { getSheetHeaderRowAndSkipEmpty } from './v2/methods/loadOptions';
|
||||
import type { ValueRenderOption } from './v2/helpers/GoogleSheets.types';
|
||||
import type { ResourceLocator, ValueRenderOption } from './v2/helpers/GoogleSheets.types';
|
||||
|
||||
import {
|
||||
arrayOfArraysToJson,
|
||||
|
@ -399,11 +399,21 @@ export class GoogleSheetsTrigger implements INodeType {
|
|||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
let sheetId = this.getNodeParameter('sheetName', undefined, {
|
||||
const sheetWithinDocument = this.getNodeParameter('sheetName', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const { mode: sheetMode } = this.getNodeParameter('sheetName', 0) as {
|
||||
mode: ResourceLocator;
|
||||
};
|
||||
|
||||
sheetId = sheetId === 'gid=0' ? '0' : sheetId;
|
||||
const googleSheet = new GoogleSheet(documentId, this);
|
||||
const { sheetId, title: sheetName } = await googleSheet.spreadsheetGetSheet(
|
||||
this.getNode(),
|
||||
sheetMode,
|
||||
sheetWithinDocument,
|
||||
);
|
||||
|
||||
const options = this.getNodeParameter('options') as IDataObject;
|
||||
|
||||
// If the documentId or sheetId changed, reset the workflow static data
|
||||
if (
|
||||
|
@ -417,13 +427,6 @@ export class GoogleSheetsTrigger implements INodeType {
|
|||
workflowStaticData.lastIndexChecked = undefined;
|
||||
}
|
||||
|
||||
const googleSheet = new GoogleSheet(documentId, this);
|
||||
const sheetName: string = await googleSheet.spreadsheetGetSheetNameById(
|
||||
this.getNode(),
|
||||
sheetId,
|
||||
);
|
||||
const options = this.getNodeParameter('options') as IDataObject;
|
||||
|
||||
const previousRevision = workflowStaticData.lastRevision as number;
|
||||
const previousRevisionLink = workflowStaticData.lastRevisionLink as string;
|
||||
|
||||
|
|
|
@ -29,17 +29,25 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
|
|||
const googleSheet = new GoogleSheet(spreadsheetId, this);
|
||||
|
||||
let sheetId = '';
|
||||
let sheetName = '';
|
||||
|
||||
if (operation !== 'create') {
|
||||
sheetId = this.getNodeParameter('sheetName', 0, undefined, {
|
||||
const sheetWithinDocument = this.getNodeParameter('sheetName', 0, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const { mode: sheetMode } = this.getNodeParameter('sheetName', 0) as {
|
||||
mode: ResourceLocator;
|
||||
};
|
||||
|
||||
const result = await googleSheet.spreadsheetGetSheet(
|
||||
this.getNode(),
|
||||
sheetMode,
|
||||
sheetWithinDocument,
|
||||
);
|
||||
sheetId = result.sheetId.toString();
|
||||
sheetName = result.title;
|
||||
}
|
||||
|
||||
if (sheetId === 'gid=0') {
|
||||
sheetId = '0';
|
||||
}
|
||||
|
||||
let sheetName = '';
|
||||
switch (operation) {
|
||||
case 'create':
|
||||
sheetName = spreadsheetId;
|
||||
|
@ -50,8 +58,6 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
|
|||
case 'remove':
|
||||
sheetName = `${spreadsheetId}||${sheetId}`;
|
||||
break;
|
||||
default:
|
||||
sheetName = await googleSheet.spreadsheetGetSheetNameById(this.getNode(), sheetId);
|
||||
}
|
||||
|
||||
results = await sheet[googleSheets.operation].execute.call(
|
||||
|
|
|
@ -184,6 +184,12 @@ export const descriptions: INodeProperties[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'By Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
placeholder: 'Sheet1',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
import get from 'lodash/get';
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
IDataObject,
|
||||
IPollFunctions,
|
||||
INode,
|
||||
IPollFunctions,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError, NodeOperationError } from 'n8n-workflow';
|
||||
import { utils as xlsxUtils } from 'xlsx';
|
||||
import get from 'lodash/get';
|
||||
import { apiRequest } from '../transport';
|
||||
import type {
|
||||
ILookupValues,
|
||||
ISheetUpdateData,
|
||||
ResourceLocator,
|
||||
SheetCellDecoded,
|
||||
SheetRangeData,
|
||||
SheetRangeDecoded,
|
||||
SpreadSheetResponse,
|
||||
ValueInputOption,
|
||||
ValueRenderOption,
|
||||
} from './GoogleSheets.types';
|
||||
import { removeEmptyColumns } from './GoogleSheets.utils';
|
||||
import { getSheetId, removeEmptyColumns } from './GoogleSheets.utils';
|
||||
|
||||
export class GoogleSheet {
|
||||
id: string;
|
||||
|
@ -116,32 +118,35 @@ export class GoogleSheet {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the name of a sheet from a sheet id
|
||||
* Returns the sheet within a spreadsheet based on name or ID
|
||||
*/
|
||||
async spreadsheetGetSheetNameById(node: INode, sheetId: string) {
|
||||
async spreadsheetGetSheet(node: INode, mode: ResourceLocator, value: string) {
|
||||
const query = {
|
||||
fields: 'sheets.properties',
|
||||
};
|
||||
|
||||
const response = await apiRequest.call(
|
||||
const response = (await apiRequest.call(
|
||||
this.executeFunctions,
|
||||
'GET',
|
||||
`/v4/spreadsheets/${this.id}`,
|
||||
{},
|
||||
query,
|
||||
);
|
||||
)) as SpreadSheetResponse;
|
||||
|
||||
const foundItem = response.sheets.find(
|
||||
(item: { properties: { sheetId: number } }) => item.properties.sheetId === +sheetId,
|
||||
);
|
||||
const foundItem = response.sheets.find((item) => {
|
||||
if (mode === 'name') return item.properties.title === value;
|
||||
return item.properties.sheetId === getSheetId(value);
|
||||
});
|
||||
|
||||
if (!foundItem?.properties?.title) {
|
||||
throw new NodeOperationError(node, `Sheet with ID ${sheetId} not found`, {
|
||||
level: 'warning',
|
||||
});
|
||||
throw new NodeOperationError(
|
||||
node,
|
||||
`Sheet with ${mode === 'name' ? 'name' : 'ID'} ${value} not found`,
|
||||
{ level: 'warning' },
|
||||
);
|
||||
}
|
||||
|
||||
return foundItem.properties.title;
|
||||
return foundItem.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -62,12 +62,24 @@ export type GoogleSheetsSheet = Entity<GoogleSheetsMap, 'sheet'>;
|
|||
export type SpreadSheetProperties = PropertiesOf<GoogleSheetsSpreadSheet>;
|
||||
export type SheetProperties = PropertiesOf<GoogleSheetsSheet>;
|
||||
|
||||
export type ResourceLocator = 'id' | 'url' | 'list';
|
||||
export type ResourceLocator = 'id' | 'url' | 'list' | 'name';
|
||||
|
||||
export const ResourceLocatorUiNames = {
|
||||
id: 'By ID',
|
||||
url: 'By URL',
|
||||
list: 'From List',
|
||||
name: 'By Name',
|
||||
};
|
||||
|
||||
type SpreadSheetResponseSheet = {
|
||||
properties: {
|
||||
title: string;
|
||||
sheetId: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type SpreadSheetResponse = {
|
||||
sheets: SpreadSheetResponseSheet[];
|
||||
};
|
||||
|
||||
export type SheetCellDecoded = {
|
||||
|
|
|
@ -45,6 +45,11 @@ export function getSpreadsheetId(
|
|||
return value;
|
||||
}
|
||||
|
||||
export function getSheetId(value: string): number {
|
||||
if (value === 'gid=0') return 0;
|
||||
return parseInt(value);
|
||||
}
|
||||
|
||||
// Convert number to Sheets / Excel column name
|
||||
export function getColumnName(colNumber: number): string {
|
||||
const baseChar = 'A'.charCodeAt(0);
|
||||
|
|
|
@ -47,15 +47,18 @@ export async function getSheetHeaderRow(
|
|||
const spreadsheetId = getSpreadsheetId(this.getNode(), mode as ResourceLocator, value as string);
|
||||
|
||||
const sheet = new GoogleSheet(spreadsheetId, this);
|
||||
let sheetWithinDocument = this.getNodeParameter('sheetName', undefined, {
|
||||
const sheetWithinDocument = this.getNodeParameter('sheetName', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const { mode: sheetMode } = this.getNodeParameter('sheetName', 0) as {
|
||||
mode: ResourceLocator;
|
||||
};
|
||||
|
||||
if (sheetWithinDocument === 'gid=0') {
|
||||
sheetWithinDocument = '0';
|
||||
}
|
||||
|
||||
const sheetName = await sheet.spreadsheetGetSheetNameById(this.getNode(), sheetWithinDocument);
|
||||
const { title: sheetName } = await sheet.spreadsheetGetSheet(
|
||||
this.getNode(),
|
||||
sheetMode,
|
||||
sheetWithinDocument,
|
||||
);
|
||||
const sheetData = await sheet.getData(`${sheetName}!1:1`, 'FORMATTED_VALUE');
|
||||
|
||||
if (sheetData === undefined) {
|
||||
|
|
|
@ -20,15 +20,16 @@ export async function getMappingColumns(
|
|||
const spreadsheetId = getSpreadsheetId(this.getNode(), mode as ResourceLocator, value as string);
|
||||
|
||||
const sheet = new GoogleSheet(spreadsheetId, this);
|
||||
let sheetWithinDocument = this.getNodeParameter('sheetName', undefined, {
|
||||
const sheetWithinDocument = this.getNodeParameter('sheetName', undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
const { mode: sheetMode } = this.getNodeParameter('sheetName', 0) as { mode: ResourceLocator };
|
||||
|
||||
if (sheetWithinDocument === 'gid=0') {
|
||||
sheetWithinDocument = '0';
|
||||
}
|
||||
|
||||
const sheetName = await sheet.spreadsheetGetSheetNameById(this.getNode(), sheetWithinDocument);
|
||||
const { title: sheetName } = await sheet.spreadsheetGetSheet(
|
||||
this.getNode(),
|
||||
sheetMode,
|
||||
sheetWithinDocument,
|
||||
);
|
||||
const sheetData = await sheet.getData(`${sheetName}!1:1`, 'FORMATTED_VALUE');
|
||||
|
||||
const columns = sheet.testFilter(sheetData || [], 0, 0).filter((col) => col !== '');
|
||||
|
|
Loading…
Reference in a new issue