Skip to content

Commit

Permalink
Merge pull request activepieces#1605 from Abdallah-Alwarawreh/piece/g…
Browse files Browse the repository at this point in the history
…oogle-sheets
  • Loading branch information
abuaboud authored Jul 7, 2023
2 parents 78afd30 + 97807dd commit eb4862a
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 59 deletions.
2 changes: 1 addition & 1 deletion packages/pieces/google-sheets/package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "@activepieces/piece-google-sheets",
"version": "0.2.21"
"version": "0.2.22"
}
3 changes: 2 additions & 1 deletion packages/pieces/google-sheets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { readNewRows } from './lib/triggers/new-row-added';
import { deleteRowAction } from './lib/actions/delete-row.action';
import { updateRowAction } from './lib/actions/update-row';
import { findRowsAction } from './lib/actions/find-rows';
import { clearSheetAction } from './lib/actions/clear-sheet';

export const googleSheets = createPiece({
logoUrl: 'https://cdn.activepieces.com/pieces/google-sheets.png',
authors: ['abuaboud', 'AbdulTheActivepiecer', 'Shay Punter', 'Abdallah-Alwarawreh'],
actions: [insertRowAction, deleteRowAction, updateRowAction, findRowsAction],
actions: [insertRowAction, deleteRowAction, updateRowAction, findRowsAction, clearSheetAction],
displayName: "Google Sheets",
triggers: [readNewRows],
});
47 changes: 47 additions & 0 deletions packages/pieces/google-sheets/src/lib/actions/clear-sheet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { googleSheetsCommon } from '../common/common';

export const clearSheetAction = createAction({
name: 'clear_sheet',
description: 'Clears all rows on an existing sheet',
displayName: 'Clear Sheet',
props: {
authentication: googleSheetsCommon.authentication,
spreadsheet_id: googleSheetsCommon.spreadsheet_id,
include_team_drives: googleSheetsCommon.include_team_drives,
sheet_id: googleSheetsCommon.sheet_id,
is_first_row_headers: Property.Checkbox({
displayName: 'Is First row Headers?',
description: 'If the first row is headers',
required: true,
defaultValue: true,
}),
},
async run(context) {
const sheetName = await googleSheetsCommon.findSheetName(context.propsValue['authentication']['access_token'],
context.propsValue['spreadsheet_id'],
context.propsValue['sheet_id']);
if (!sheetName) {
throw Error("Sheet not found in spreadsheet");
}

const rowsToDelete: number[] = [];
const values = await googleSheetsCommon.getValues(context.propsValue.spreadsheet_id, context.propsValue['authentication']['access_token'], context.propsValue.sheet_id);
for (const key in values) {
if (key === '0' && context.propsValue.is_first_row_headers) {
continue;
}
rowsToDelete.push(parseInt(key) + 1);
}

for (let i = 0; i < rowsToDelete.length; i++) {
await googleSheetsCommon.clearSheet(context.propsValue.spreadsheet_id,
context.propsValue.sheet_id, context.propsValue['authentication']['access_token'],
context.propsValue.is_first_row_headers ? 1 : 0, rowsToDelete.length)
}

return {
deletedRow: rowsToDelete,
}
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ export const deleteRowAction = createAction({

// Subtract 1 from the row_id to convert it to 0-indexed
const adjustedRowIndex = context.propsValue.row_id - 1;

const response = await googleSheetsCommon.deleteRow(context.propsValue.spreadsheet_id, context.propsValue.sheet_id, adjustedRowIndex,
await googleSheetsCommon.deleteRow(context.propsValue.spreadsheet_id, context.propsValue.sheet_id, adjustedRowIndex,
context.propsValue['authentication']['access_token'])

return {
Expand Down
12 changes: 4 additions & 8 deletions packages/pieces/google-sheets/src/lib/actions/find-rows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ export const findRowsAction = createAction({
spreadsheet_id: googleSheetsCommon.spreadsheet_id,
include_team_drives: googleSheetsCommon.include_team_drives,
sheet_id: googleSheetsCommon.sheet_id,
column_name: Property.ShortText({
displayName: 'Column Name',
description: 'The name of the column to search in, e.g. "A"',
required: true,
}),
column_name: googleSheetsCommon.column_name,
search_value: Property.ShortText({
displayName: 'Search Value',
description: 'The value to search for',
Expand All @@ -29,8 +25,8 @@ export const findRowsAction = createAction({
throw Error("Sheet not found in spreadsheet");
}
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
// find the column index
const column = alphabet.indexOf(context.propsValue.column_name.toLowerCase());

const column = alphabet.indexOf(context.propsValue.column_name?.toLowerCase().toString()[0] ?? 'a');
if (column === -1) {
throw Error("Column not found in sheet");
}else{
Expand All @@ -40,7 +36,7 @@ export const findRowsAction = createAction({
for (const { row, values: innerValues } of values) {
for (const value of innerValues) {
for (const key in value) {
if(value[key].includes(context.propsValue.search_value)){
if(value[key].includes(context.propsValue.search_value) && key.toLowerCase() === alphabet[column]){
matchingRows.push({
[key]: value[key],
});
Expand Down
47 changes: 22 additions & 25 deletions packages/pieces/google-sheets/src/lib/actions/insert-row.action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { Dimension, ValueInputOption } from '../common/common';
import { googleSheetsCommon } from '../common/common';
import { Dimension, googleSheetsCommon, ValueInputOption } from '../common/common';

export const insertRowAction = createAction({
name: 'insert_row',
Expand All @@ -16,35 +15,33 @@ export const insertRowAction = createAction({
description: 'Inserted values that are dates and formulas will be entered strings and have no effect',
required: false,
}),
values: Property.Array({
displayName: 'Values',
description: 'These are the cell values of the row that will be added, beginning with the Value in column A and proceeding with each Value being entered in the next cell.',
is_first_row_headers: Property.Checkbox({
displayName: 'Is First row Headers?',
description: 'If the first row is headers',
required: true,
defaultValue: false,
}),
values: googleSheetsCommon.values,

},
async run(context) {
const values = context.propsValue['values'];
const sheetName = await googleSheetsCommon.findSheetName(context.propsValue['authentication']['access_token'],
context.propsValue['spreadsheet_id'], context.propsValue['sheet_id']);
const sheetName = await googleSheetsCommon.findSheetName(context.propsValue['authentication']['access_token'],
context.propsValue['spreadsheet_id'], context.propsValue['sheet_id']);
if (!sheetName) {
throw Error("Sheet not found in spreadsheet");
}

if (Array.isArray(values)) {
const res = await googleSheetsCommon.appendGoogleSheetValues({
accessToken: context.propsValue['authentication']['access_token'],
majorDimension: Dimension.COLUMNS,
range: sheetName,
spreadSheetId: context.propsValue['spreadsheet_id'],
valueInputOption: context.propsValue['as_string']
? ValueInputOption.RAW
: ValueInputOption.USER_ENTERED,
values: values as string[],
});

return res.body;
} else {
throw Error("Values passed are not an array")
return {}
}
const formattedValues = context.propsValue.is_first_row_headers ? Object.values(values) : values['values'];
const res = await googleSheetsCommon.appendGoogleSheetValues({
accessToken: context.propsValue['authentication']['access_token'],
majorDimension: Dimension.COLUMNS,
range: sheetName,
spreadSheetId: context.propsValue['spreadsheet_id'],
valueInputOption: context.propsValue['as_string']
? ValueInputOption.RAW
: ValueInputOption.USER_ENTERED,
values: formattedValues,
});
return res.body;
},
});
19 changes: 7 additions & 12 deletions packages/pieces/google-sheets/src/lib/actions/update-row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,34 @@ export const updateRowAction = createAction({
description: 'The row number to update',
required: true,
}),
values: Property.Array({
displayName: 'Values',
description: 'These are the cell values of the row that will be updated, begining with column A and continuing with each Value entered into the next column. For example, to update column C, you must enter Values for columns A, B, and C. It is likely that you will update these columns using Values selected from a previous Google Sheets operation so they will remain the same. If they are left blank they will be blanked out when updating. You do not need to enter Values for all of the columns, just those to the left of the Value you wish to update.',
required: true,
}),
values: googleSheetsCommon.values,
},
async run(context) {
const values = context.propsValue['values'];

const sheetName = await googleSheetsCommon.findSheetName(context.propsValue['authentication']['access_token'], context.propsValue['spreadsheet_id'], context.propsValue['sheet_id']);
if (!sheetName) {
throw Error("Sheet not found in spreadsheet");
}
if (Array.isArray(values)) {
const formattedValues = Object.values(context.propsValue['values']);
if (formattedValues.length > 0) {
const res = await googleSheetsCommon.updateGoogleSheetRow({
accessToken: context.propsValue['authentication']['access_token'],
rowIndex: Number(context.propsValue.row_id),
sheetName: sheetName,
spreadSheetId: context.propsValue['spreadsheet_id'],
valueInputOption: ValueInputOption.USER_ENTERED,
values: values as string[],
values: formattedValues,
});


res.body.updatedRange = res.body.updatedRange.replace(sheetName + "!", "");
res.body.updatedRange = res.body.updatedRange.split(":");
const UpdatedRows = [];
const updatedRows = [];

for (let i = 0; i < res.body.updatedRange.length; i++)
UpdatedRows.push({ [res.body.updatedRange[i].charAt(0)]: parseInt(res.body.updatedRange[i].slice(1)) });
updatedRows.push({ [res.body.updatedRange[i].charAt(0)]: parseInt(res.body.updatedRange[i].slice(1)) });


return UpdatedRows;
return updatedRows;
} else {
throw Error("Values passed are not an array")
}
Expand Down
132 changes: 130 additions & 2 deletions packages/pieces/google-sheets/src/lib/common/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,108 @@ export const googleSheetsCommon = {
};
}
}),
values: Property.DynamicProperties({
displayName: 'Values',
description: 'The values to insert',
required: true,
refreshers: ['authentication', 'sheet_id', 'spreadsheet_id', 'is_first_row_headers'],
props: async (context) => {

const authentication = context.authentication as OAuth2PropertyValue;
const spreadsheet_id = context.spreadsheet_id as unknown as string;
const sheet_id = context.sheet_id as unknown as number;
const values = await googleSheetsCommon.getValues(spreadsheet_id, getAccessTokenOrThrow(authentication), sheet_id);

if (!context.is_first_row_headers) {
return {
values: Property.Array({
displayName: 'Values',
required: true,
})
}
}
const firstRow = (values?.[0]?.values ?? [])
const properties: {
[key: string]: any
} = {}
for (const key in firstRow) {
for (const Letter in firstRow[key]) {
properties[Letter] = Property.ShortText({
displayName: firstRow[key][Letter].toString(),
description: firstRow[key][Letter].toString(),
required: true
})
}
}
return properties;
}
}),
column_name: Property.Dropdown<string>({
description: 'Column Name',
displayName: 'The name of the column to search in',
required: true,
refreshers: ['authentication', 'sheet_id', 'spreadsheet_id'],
options: async (context) => {
const authentication = context.authentication as OAuth2PropertyValue;
const spreadsheet_id = context.spreadsheet_id as string;
const sheet_id = context.sheet_id as number;
const accessToken = authentication['access_token'] ?? '';

const sheetName = await googleSheetsCommon.findSheetName(accessToken, spreadsheet_id, sheet_id);

if (!sheetName) {
throw Error("Sheet not found in spreadsheet");
}

const values: {
row: number;
values: {
[x: string]: string[];
}[];
}[] = await googleSheetsCommon.getValues(spreadsheet_id, accessToken, sheet_id);

const ret = [];

const firstRow = values[0].values;

if (firstRow.length === 0) {
let columnSize = 1;

for (const row of values) {
columnSize = Math.max(columnSize, row.values.length);
}

const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

for (let i = 0; i < columnSize; i++) {
ret.push({
label: alphabet[i].toUpperCase(),
value: alphabet[i],
});
}
} else {
for (const key in firstRow) {
for (const letter in firstRow[key]) {
ret.push({
label: firstRow[key][letter].toString(),
value: letter,
});
}
}
}

return {
options: ret,
disabled: false,
};
}
}),
getValues: getValues,
appendGoogleSheetValues: appendGoogleSheetValues,
updateGoogleSheetRow: updateGoogleSheetRow,
findSheetName: findSheetName,
deleteRow: deleteRow,
clearSheet: clearSheet,
}


Expand Down Expand Up @@ -146,12 +243,13 @@ async function updateGoogleSheetRow(params: UpdateGoogleSheetRowParams) {
async function appendGoogleSheetValues(params: AppendGoogleSheetValuesParams) {
const requestBody = {
majorDimension: params.majorDimension,
range: params.range,
range: params.range + "!A:A",
values: params.values.map(val => ({ values: val })),
};

const request: HttpRequest<typeof requestBody> = {
method: HttpMethod.POST,
url: `https://sheets.googleapis.com/v4/spreadsheets/${params.spreadSheetId}/values/${params.range}:append`,
url: `https://sheets.googleapis.com/v4/spreadsheets/${params.spreadSheetId}/values/${params.range}!A:A:append`,
body: requestBody,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
Expand All @@ -168,6 +266,9 @@ async function getValues(spreadsheetId: string, accessToken: string, sheetId: nu
// Define the API endpoint and headers
// Send the API request
const sheetName = await findSheetName(accessToken, spreadsheetId, sheetId);
if(!sheetName){
return [];
}
const request: HttpRequest = {
method: HttpMethod.GET,
url: `${googleSheetsCommon.baseUrl}/${spreadsheetId}/values/${sheetName}`,
Expand Down Expand Up @@ -235,6 +336,33 @@ async function deleteRow(spreadsheetId: string, sheetId: number, rowIndex: numbe
await httpClient.sendRequest(request);
}


async function clearSheet(spreadsheetId: string, sheetId: number, accessToken: string, rowIndex: number, numOfRows: number) {
const request: HttpRequest = {
method: HttpMethod.POST,
url: `${googleSheetsCommon.baseUrl}/${spreadsheetId}/:batchUpdate`,
authentication: {
type: AuthenticationType.BEARER_TOKEN,
token: accessToken,
},
body: {
requests: [
{
deleteDimension: {
range: {
sheetId: sheetId,
dimension: "ROWS",
startIndex: rowIndex,
endIndex: rowIndex + numOfRows + 1,
},
},
},
],
},
};
await httpClient.sendRequest(request);
}

export enum ValueInputOption {
RAW = 'RAW',
USER_ENTERED = 'USER_ENTERED',
Expand Down
Loading

0 comments on commit eb4862a

Please sign in to comment.