Fixed some issues with Excel-Node

This commit is contained in:
Jan Oberhauser 2020-03-28 19:08:39 +01:00
parent 1b3417390b
commit bba6a8494d
8 changed files with 412 additions and 80 deletions

View file

@ -0,0 +1,26 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
const scopes = [
'https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events',
];
export class TestOAuth2Api implements ICredentialType {
name = 'testOAuth2Api';
extends = [
'googleOAuth2Api',
];
displayName = 'Test OAuth2 API';
properties = [
{
displayName: 'Scope',
name: 'scope',
type: 'string' as NodePropertyTypes,
default: '',
placeholder: 'asdf',
},
];
}

View file

@ -0,0 +1,293 @@
// import { google } from 'googleapis';
// import {
// IHookFunctions,
// IWebhookFunctions,
// } from 'n8n-core';
// import {
// IDataObject,
// INodeTypeDescription,
// INodeType,
// IWebhookResponseData,
// } from 'n8n-workflow';
// import { getAuthenticationClient } from './GoogleApi';
// export class GoogleDriveTrigger implements INodeType {
// description: INodeTypeDescription = {
// displayName: 'Google Drive Trigger',
// name: 'googleDriveTrigger',
// icon: 'file:googleDrive.png',
// group: ['trigger'],
// version: 1,
// subtitle: '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
// description: 'Starts the workflow when a file on Google Drive got changed.',
// defaults: {
// name: 'Google Drive Trigger',
// color: '#3f87f2',
// },
// inputs: [],
// outputs: ['main'],
// credentials: [
// {
// name: 'googleApi',
// required: true,
// }
// ],
// webhooks: [
// {
// name: 'default',
// httpMethod: 'POST',
// responseMode: 'onReceived',
// path: 'webhook',
// },
// ],
// properties: [
// {
// displayName: 'Resource Id',
// name: 'resourceId',
// type: 'string',
// default: '',
// required: true,
// placeholder: '',
// description: 'ID of the resource to watch, for example a file ID.',
// },
// ],
// };
// // @ts-ignore (because of request)
// webhookMethods = {
// default: {
// async checkExists(this: IHookFunctions): Promise<boolean> {
// // const webhookData = this.getWorkflowStaticData('node');
// // if (webhookData.webhookId === undefined) {
// // // No webhook id is set so no webhook can exist
// // return false;
// // }
// // // Webhook got created before so check if it still exists
// // const owner = this.getNodeParameter('owner') as string;
// // const repository = this.getNodeParameter('repository') as string;
// // const endpoint = `/repos/${owner}/${repository}/hooks/${webhookData.webhookId}`;
// // try {
// // await githubApiRequest.call(this, 'GET', endpoint, {});
// // } catch (e) {
// // if (e.message.includes('[404]:')) {
// // // Webhook does not exist
// // delete webhookData.webhookId;
// // delete webhookData.webhookEvents;
// // return false;
// // }
// // // Some error occured
// // throw e;
// // }
// // If it did not error then the webhook exists
// // return true;
// return false;
// },
// async create(this: IHookFunctions): Promise<boolean> {
// const webhookUrl = this.getNodeWebhookUrl('default');
// const resourceId = this.getNodeParameter('resourceId') as string;
// const credentials = this.getCredentials('googleApi');
// if (credentials === undefined) {
// throw new Error('No credentials got returned!');
// }
// const scopes = [
// 'https://www.googleapis.com/auth/drive',
// 'https://www.googleapis.com/auth/drive.appdata',
// 'https://www.googleapis.com/auth/drive.photos.readonly',
// ];
// const client = await getAuthenticationClient(credentials.email as string, credentials.privateKey as string, scopes);
// const drive = google.drive({
// version: 'v3',
// auth: client,
// });
// const accessToken = await client.getAccessToken();
// console.log('accessToken: ');
// console.log(accessToken);
// const asdf = await drive.changes.getStartPageToken();
// // console.log('asdf: ');
// // console.log(asdf);
// const response = await drive.changes.watch({
// //
// pageToken: asdf.data.startPageToken,
// requestBody: {
// id: 'asdf-test-2',
// address: webhookUrl,
// resourceId,
// type: 'web_hook',
// // page_token: '',
// }
// });
// console.log('...response...CREATE');
// console.log(JSON.stringify(response, null, 2));
// // const endpoint = `/repos/${owner}/${repository}/hooks`;
// // const body = {
// // name: 'web',
// // config: {
// // url: webhookUrl,
// // content_type: 'json',
// // // secret: '...later...',
// // insecure_ssl: '1', // '0' -> not allow inscure ssl | '1' -> allow insercure SSL
// // },
// // events,
// // active: true,
// // };
// // let responseData;
// // try {
// // responseData = await githubApiRequest.call(this, 'POST', endpoint, body);
// // } catch (e) {
// // if (e.message.includes('[422]:')) {
// // throw new Error('A webhook with the identical URL exists already. Please delete it manually on Github!');
// // }
// // throw e;
// // }
// // if (responseData.id === undefined || responseData.active !== true) {
// // // Required data is missing so was not successful
// // throw new Error('Github webhook creation response did not contain the expected data.');
// // }
// // const webhookData = this.getWorkflowStaticData('node');
// // webhookData.webhookId = responseData.id as string;
// // webhookData.webhookEvents = responseData.events as string[];
// return true;
// },
// async delete(this: IHookFunctions): Promise<boolean> {
// const webhookUrl = this.getNodeWebhookUrl('default');
// const resourceId = this.getNodeParameter('resourceId') as string;
// const credentials = this.getCredentials('googleApi');
// if (credentials === undefined) {
// throw new Error('No credentials got returned!');
// }
// const scopes = [
// 'https://www.googleapis.com/auth/drive',
// 'https://www.googleapis.com/auth/drive.appdata',
// 'https://www.googleapis.com/auth/drive.photos.readonly',
// ];
// const client = await getAuthenticationClient(credentials.email as string, credentials.privateKey as string, scopes);
// const drive = google.drive({
// version: 'v3',
// auth: client,
// });
// // Remove channel
// const response = await drive.channels.stop({
// requestBody: {
// id: 'asdf-test-2',
// address: webhookUrl,
// resourceId,
// type: 'web_hook',
// }
// });
// console.log('...response...DELETE');
// console.log(JSON.stringify(response, null, 2));
// // const webhookData = this.getWorkflowStaticData('node');
// // if (webhookData.webhookId !== undefined) {
// // const owner = this.getNodeParameter('owner') as string;
// // const repository = this.getNodeParameter('repository') as string;
// // const endpoint = `/repos/${owner}/${repository}/hooks/${webhookData.webhookId}`;
// // const body = {};
// // try {
// // await githubApiRequest.call(this, 'DELETE', endpoint, body);
// // } catch (e) {
// // return false;
// // }
// // // Remove from the static workflow data so that it is clear
// // // that no webhooks are registred anymore
// // delete webhookData.webhookId;
// // delete webhookData.webhookEvents;
// // }
// return true;
// },
// },
// };
// async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
// const bodyData = this.getBodyData();
// console.log('');
// console.log('');
// console.log('GOT WEBHOOK CALL');
// console.log(JSON.stringify(bodyData, null, 2));
// // Check if the webhook is only the ping from Github to confirm if it workshook_id
// if (bodyData.hook_id !== undefined && bodyData.action === undefined) {
// // Is only the ping and not an actual webhook call. So return 'OK'
// // but do not start the workflow.
// return {
// webhookResponse: 'OK'
// };
// }
// // Is a regular webhoook call
// // TODO: Add headers & requestPath
// const returnData: IDataObject[] = [];
// returnData.push(
// {
// body: bodyData,
// headers: this.getHeaderData(),
// query: this.getQueryData(),
// }
// );
// return {
// workflowData: [
// this.helpers.returnJsonArray(returnData)
// ],
// };
// }
// }

View file

@ -153,23 +153,23 @@ export class MicrosoftExcel implements INodeType {
const items = this.getInputData(); const items = this.getInputData();
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
const length = items.length as unknown as number; const length = items.length as unknown as number;
const qs: IDataObject = {}; let qs: IDataObject = {};
const result: IDataObject[] = []; const result: IDataObject[] = [];
const object: IDataObject = {};
let responseData; let responseData;
const resource = this.getNodeParameter('resource', 0) as string; const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string; const operation = this.getNodeParameter('operation', 0) as string;
if (resource === 'table') { if (resource === 'table') {
//https://docs.microsoft.com/en-us/graph/api/table-post-rows?view=graph-rest-1.0&tabs=http //https://docs.microsoft.com/en-us/graph/api/table-post-rows?view=graph-rest-1.0&tabs=http
if (operation === 'addRow') { if (operation === 'addRow') {
// TODO: At some point it should be possible to use item dependent parameters.
// Is however important to then not make one separate request each.
const workbookId = this.getNodeParameter('workbook', 0) as string; const workbookId = this.getNodeParameter('workbook', 0) as string;
const worksheetId = this.getNodeParameter('worksheet', 0) as string; const worksheetId = this.getNodeParameter('worksheet', 0) as string;
const tableId = this.getNodeParameter('table', 0) as string; const tableId = this.getNodeParameter('table', 0) as string;
const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject;
const body: IDataObject = {}; const body: IDataObject = {};
if (Object.keys(items[0].json).length === 0) {
throw new Error('Input cannot be empty');
}
if (additionalFields.index) { if (additionalFields.index) {
body.index = additionalFields.index as number; body.index = additionalFields.index as number;
} }
@ -178,41 +178,35 @@ export class MicrosoftExcel implements INodeType {
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs); responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
const columns = responseData.value.map((column: IDataObject) => (column.name)); const columns = responseData.value.map((column: IDataObject) => (column.name));
const cleanedItems: IDataObject[] = []; const rows: any[][] = []; // tslint:disable-line:no-any
// Delete columns the excel table does not have // Bring the items into the correct format
for (const item of items) { for (const item of items) {
for (const key of Object.keys(item.json)) { const row = [];
if (!columns.includes(key)) {
const property = { ...item.json };
delete property[key];
cleanedItems.push(property);
}
}
}
// Map the keys to the column index
const values: any[][] = [];
let value = [];
for (const item of cleanedItems) {
for (const column of columns) { for (const column of columns) {
value.push(item[column]); row.push(item.json[column]);
} }
values.push(value); rows.push(row);
value = [];
} }
body.values = values; body.values = rows;
const { id } = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/createSession`, { persistChanges: true }); const { id } = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/createSession`, { persistChanges: true });
responseData = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows/add`, body, {}, '', { 'workbook-session-id': id }); responseData = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows/add`, body, {}, '', { 'workbook-session-id': id });
await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/closeSession`, {}, {}, '', { 'workbook-session-id': id }); await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/closeSession`, {}, {}, '', { 'workbook-session-id': id });
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}
} }
//https://docs.microsoft.com/en-us/graph/api/table-list-columns?view=graph-rest-1.0&tabs=http //https://docs.microsoft.com/en-us/graph/api/table-list-columns?view=graph-rest-1.0&tabs=http
if (operation === 'getColumns') { if (operation === 'getColumns') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const workbookId = this.getNodeParameter('workbook', 0) as string; qs = {};
const worksheetId = this.getNodeParameter('worksheet', 0) as string; const workbookId = this.getNodeParameter('workbook', i) as string;
const tableId = this.getNodeParameter('table', 0) as string; const worksheetId = this.getNodeParameter('worksheet', i) as string;
const tableId = this.getNodeParameter('table', i) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const rawData = this.getNodeParameter('rawData', i) as boolean; const rawData = this.getNodeParameter('rawData', i) as boolean;
if (rawData) { if (rawData) {
@ -234,14 +228,21 @@ export class MicrosoftExcel implements INodeType {
const dataProperty = this.getNodeParameter('dataProperty', i) as string; const dataProperty = this.getNodeParameter('dataProperty', i) as string;
responseData = { [dataProperty] : responseData }; responseData = { [dataProperty] : responseData };
} }
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}
} }
} }
//https://docs.microsoft.com/en-us/graph/api/table-list-rows?view=graph-rest-1.0&tabs=http //https://docs.microsoft.com/en-us/graph/api/table-list-rows?view=graph-rest-1.0&tabs=http
if (operation === 'getRows') { if (operation === 'getRows') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const workbookId = this.getNodeParameter('workbook', 0) as string; qs = {};
const worksheetId = this.getNodeParameter('worksheet', 0) as string; const workbookId = this.getNodeParameter('workbook', i) as string;
const tableId = this.getNodeParameter('table', 0) as string; const worksheetId = this.getNodeParameter('worksheet', i) as string;
const tableId = this.getNodeParameter('table', i) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const rawData = this.getNodeParameter('rawData', i) as boolean; const rawData = this.getNodeParameter('rawData', i) as boolean;
if (rawData) { if (rawData) {
@ -253,71 +254,78 @@ export class MicrosoftExcel implements INodeType {
if (returnAll === true) { if (returnAll === true) {
responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, qs); responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, qs);
} else { } else {
qs['$top'] = this.getNodeParameter('limit', i) as number; const rowsQs = { ...qs };
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, qs); rowsQs['$top'] = this.getNodeParameter('limit', i) as number;
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, rowsQs);
responseData = responseData.value; responseData = responseData.value;
} }
if (!rawData) { if (!rawData) {
qs['$select'] = 'name'; const columnsQs = { ...qs };
let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs); columnsQs['$select'] = 'name';
// TODO: That should probably be cached in the future
let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, columnsQs);
//@ts-ignore //@ts-ignore
columns = columns.map(column => column.name); columns = columns.map(column => column.name);
for (let i = 0; i < responseData.length; i++) { for (let i = 0; i < responseData.length; i++) {
const object: IDataObject = {};
for (let y = 0; y < columns.length; y++) { for (let y = 0; y < columns.length; y++) {
object[columns[y]] = responseData[i].values[0][y]; object[columns[y]] = responseData[i].values[0][y];
} }
result.push({ ...object }); returnData.push({ ...object });
} }
responseData = result;
} else { } else {
const dataProperty = this.getNodeParameter('dataProperty', i) as string; const dataProperty = this.getNodeParameter('dataProperty', i) as string;
responseData = { [dataProperty] : responseData }; returnData.push({ [dataProperty]: responseData });
} }
} }
} }
if (operation === 'lookup') { if (operation === 'lookup') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
const workbookId = this.getNodeParameter('workbook', 0) as string; qs = {};
const worksheetId = this.getNodeParameter('worksheet', 0) as string; const workbookId = this.getNodeParameter('workbook', i) as string;
const tableId = this.getNodeParameter('table', 0) as string; const worksheetId = this.getNodeParameter('worksheet', i) as string;
const lookupColumn = this.getNodeParameter('lookupColumn', 0) as string; const tableId = this.getNodeParameter('table', i) as string;
const lookupValue = this.getNodeParameter('lookupValue', 0) as string; const lookupColumn = this.getNodeParameter('lookupColumn', i) as string;
const options = this.getNodeParameter('options', 0) as IDataObject; const lookupValue = this.getNodeParameter('lookupValue', i) as string;
const options = this.getNodeParameter('options', i) as IDataObject;
responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, qs); responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, {});
qs['$select'] = 'name'; qs['$select'] = 'name';
// TODO: That should probably be cached in the future
let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs); let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
columns = columns.map((column: IDataObject) => column.name); columns = columns.map((column: IDataObject) => column.name);
for (let i = 0; i < responseData.length; i++) {
for (let y = 0; y < columns.length; y++) {
object[columns[y]] = responseData[i].values[0][y];
}
result.push({ ...object });
}
responseData = result;
if (!columns.includes(lookupColumn)) { if (!columns.includes(lookupColumn)) {
throw new Error(`Column ${lookupColumn} does not exist on the table selected`); throw new Error(`Column ${lookupColumn} does not exist on the table selected`);
} }
result.length = 0;
for (let i = 0; i < responseData.length; i++) {
const object: IDataObject = {};
for (let y = 0; y < columns.length; y++) {
object[columns[y]] = responseData[i].values[0][y];
}
result.push({ ...object });
}
if (options.returnAllMatches) { if (options.returnAllMatches) {
responseData = result.filter((data: IDataObject) => {
responseData = responseData.filter((data: IDataObject) => {
return (data[lookupColumn]?.toString() === lookupValue ); return (data[lookupColumn]?.toString() === lookupValue );
}); });
returnData.push.apply(returnData, responseData as IDataObject[]);
} else { } else {
responseData = result.find((data: IDataObject) => {
responseData = responseData.find((data: IDataObject) => {
return (data[lookupColumn]?.toString() === lookupValue ); return (data[lookupColumn]?.toString() === lookupValue );
}); });
returnData.push(responseData as IDataObject);
} }
} }
} }
} }
if (resource === 'workbook') { if (resource === 'workbook') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
qs = {};
//https://docs.microsoft.com/en-us/graph/api/worksheetcollection-add?view=graph-rest-1.0&tabs=http //https://docs.microsoft.com/en-us/graph/api/worksheetcollection-add?view=graph-rest-1.0&tabs=http
if (operation === 'addWorksheet') { if (operation === 'addWorksheet') {
const workbookId = this.getNodeParameter('workbook', i) as string; const workbookId = this.getNodeParameter('workbook', i) as string;
@ -344,10 +352,17 @@ export class MicrosoftExcel implements INodeType {
responseData = responseData.value; responseData = responseData.value;
} }
} }
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}
} }
} }
if (resource === 'worksheet') { if (resource === 'worksheet') {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
qs = {};
//https://docs.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0&tabs=http //https://docs.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0&tabs=http
if (operation === 'getAll') { if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
@ -376,7 +391,9 @@ export class MicrosoftExcel implements INodeType {
qs['$select'] = filters.fields; qs['$select'] = filters.fields;
} }
} }
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/range(address='${range}')`, {}, qs); responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/range(address='${range}')`, {}, qs);
if (!rawData) { if (!rawData) {
const keyRow = this.getNodeParameter('keyRow', i) as number; const keyRow = this.getNodeParameter('keyRow', i) as number;
const dataStartRow = this.getNodeParameter('dataStartRow', i) as number; const dataStartRow = this.getNodeParameter('dataStartRow', i) as number;
@ -385,24 +402,20 @@ export class MicrosoftExcel implements INodeType {
} }
const keyValues = responseData.values[keyRow]; const keyValues = responseData.values[keyRow];
for (let i = dataStartRow; i < responseData.values.length; i++) { for (let i = dataStartRow; i < responseData.values.length; i++) {
const object: IDataObject = {};
for (let y = 0; y < keyValues.length; y++) { for (let y = 0; y < keyValues.length; y++) {
object[keyValues[y]] = responseData.values[i][y]; object[keyValues[y]] = responseData.values[i][y];
} }
result.push({ ...object }); returnData.push({ ...object });
} }
responseData = result;
} else { } else {
const dataProperty = this.getNodeParameter('dataProperty', i) as string; const dataProperty = this.getNodeParameter('dataProperty', i) as string;
responseData = { [dataProperty] : responseData }; returnData.push({ [dataProperty]: responseData });
} }
} }
} }
} }
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
} }

View file

@ -1,4 +1,4 @@
import { INodeProperties } from "n8n-workflow"; import { INodeProperties } from 'n8n-workflow';
export const tableOperations = [ export const tableOperations = [
{ {

View file

@ -1,4 +1,4 @@
import { INodeProperties } from "n8n-workflow"; import { INodeProperties } from 'n8n-workflow';
export const workbookOperations = [ export const workbookOperations = [
{ {

View file

@ -1,4 +1,4 @@
import { INodeProperties } from "n8n-workflow"; import { INodeProperties } from 'n8n-workflow';
export const worksheetOperations = [ export const worksheetOperations = [
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -56,8 +56,8 @@
"dist/credentials/MailgunApi.credentials.js", "dist/credentials/MailgunApi.credentials.js",
"dist/credentials/MandrillApi.credentials.js", "dist/credentials/MandrillApi.credentials.js",
"dist/credentials/MattermostApi.credentials.js", "dist/credentials/MattermostApi.credentials.js",
"dist/credentials/MicrosoftOAuth2Api.credentials.js",
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js", "dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
"dist/credentials/MicrosoftOAuth2Api.credentials.js",
"dist/credentials/MongoDb.credentials.js", "dist/credentials/MongoDb.credentials.js",
"dist/credentials/MySql.credentials.js", "dist/credentials/MySql.credentials.js",
"dist/credentials/NextCloudApi.credentials.js", "dist/credentials/NextCloudApi.credentials.js",