Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,46 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
export const deleteRowAction = createAction({
auth: oracleDbAuth,
name: 'delete_row',
displayName: 'Delete Row',
description: 'Delete rows from an Oracle table',
props: {
tableName: oracleDbProps.tableName(),
filter: Property.Object({
displayName: 'Filter (WHERE)',
description: 'Conditions to match rows for deletion',
required: true,
defaultValue: { ID: 101 },
}),
},
async run(context) {
const { tableName, filter } = context.propsValue;
if (
typeof filter !== 'object' ||
filter === null ||
Array.isArray(filter)
) {
throw new Error('Filter must be a valid object');
}
if (Object.keys(filter).length === 0) {
throw new Error(
'Filter cannot be empty. Use Run Custom SQL action to delete all rows.'
);
}
try {
const client = new OracleDbClient(context.auth.props);
return await client.deleteRow(tableName, filter as Record<string, unknown>);
} catch (error) {
throw new Error(
`Failed to delete rows from ${tableName}: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,49 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
export const findRowAction = createAction({
auth: oracleDbAuth,
name: 'find_row',
displayName: 'Find Row',
description: 'Find rows in an Oracle table',
props: {
tableName: oracleDbProps.tableName(),
filter: Property.Object({
displayName: 'Filter (WHERE)',
description: 'Conditions to match rows',
required: true,
defaultValue: { ID: 101 },
}),
},
async run(context) {
const { tableName, filter } = context.propsValue;
if (
typeof filter !== 'object' ||
filter === null ||
Array.isArray(filter)
) {
throw new Error('Filter must be a valid object');
}
if (Object.keys(filter).length === 0) {
throw new Error(
'Filter cannot be empty. Use Run Custom SQL action to fetch all rows.'
);
}
try {
const client = new OracleDbClient(context.auth.props);
return await client.findRow(
tableName,
filter as Record<string, unknown>
);
} catch (error) {
throw new Error(
`Failed to find rows in ${tableName}: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,38 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
export const insertRowAction = createAction({
auth: oracleDbAuth,
name: 'insert_row',
displayName: 'Insert Row',
description: 'Insert a row into an Oracle table',
props: {
tableName: oracleDbProps.tableName(),
row: Property.Object({
displayName: 'Row',
description: 'Column names and values to insert',
required: true,
defaultValue: {
COLUMN_NAME: 'value',
},
}),
},
async run(context) {
const { tableName, row } = context.propsValue;
if (typeof row !== 'object' || row === null || Array.isArray(row)) {
throw new Error("Row must be a valid object with column names as keys");
}
try {
const client = new OracleDbClient(context.auth.props);
return await client.insertRow(tableName, row as Record<string, unknown>);
} catch (error) {
throw new Error(
`Failed to insert row into ${tableName}: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,42 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
export const insertRowsAction = createAction({
auth: oracleDbAuth,
name: 'insert_rows',
displayName: 'Insert Rows',
description: 'Insert multiple rows into an Oracle table',
props: {
tableName: oracleDbProps.tableName(),
rows: Property.Array({
displayName: 'Rows',
description: 'Array of objects with column names and values',
required: true,
defaultValue: [
{ COLUMN_1: 'value_a', COLUMN_2: 1 },
{ COLUMN_1: 'value_b', COLUMN_2: 2 },
],
}),
},
async run(context) {
const { tableName, rows } = context.propsValue;
if (!Array.isArray(rows) || rows.length === 0) {
throw new Error('Rows must be a non-empty array of objects');
}
try {
const client = new OracleDbClient(context.auth.props);
return await client.insertRows(
tableName,
rows as Record<string, unknown>[]
);
} catch (error) {
throw new Error(
`Failed to insert rows into ${tableName}: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,41 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import oracledb from 'oracledb';
export const runCustomSqlAction = createAction({
auth: oracleDbAuth,
name: 'run_custom_sql',
displayName: 'Run Custom SQL',
description: 'Execute custom SQL or PL/SQL in Oracle',
props: {
markdown: Property.MarkDown({
value: `**DO NOT** insert dynamic input directly into the query. Use bind parameters (:param) to prevent **SQL injection**.`,
}),
sql: Property.LongText({
displayName: 'SQL Query',
description: 'SQL or PL/SQL to execute. Use :param for bind parameters.',
required: true,
defaultValue: 'SELECT * FROM employees WHERE department_id = :dept_id',
}),
binds: Property.Object({
displayName: 'Bind Parameters',
description: 'Key-value pairs for bind variables',
required: false,
defaultValue: { dept_id: 90 },
}),
},
async run(context) {
const { sql, binds } = context.propsValue;
try {
const client = new OracleDbClient(context.auth.props);
const bindParams = (binds as oracledb.BindParameters) || {};
return await client.execute(sql, bindParams);
} catch (error) {
throw new Error(
`Failed to execute SQL: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
export const updateRowAction = createAction({
auth: oracleDbAuth,
name: 'update_row',
displayName: 'Update Row',
description: 'Update rows in an Oracle table',
props: {
tableName: oracleDbProps.tableName(),
values: Property.Object({
displayName: 'Values',
description: 'Column names and new values to set',
required: true,
defaultValue: { SALARY: 8000 },
}),
filter: Property.Object({
displayName: 'Filter (WHERE)',
description: 'Conditions to match rows. Empty object updates ALL rows.',
required: true,
defaultValue: { ID: 101 },
}),
},
async run(context) {
const { tableName, values, filter } = context.propsValue;
if (
typeof values !== 'object' ||
values === null ||
Array.isArray(values) ||
Object.keys(values).length === 0
) {
throw new Error('Values must be a non-empty object');
}
if (
typeof filter !== 'object' ||
filter === null ||
Array.isArray(filter)
) {
throw new Error('Filter must be a valid object');
}
try {
const client = new OracleDbClient(context.auth.props);
return await client.updateRow(
tableName,
values as Record<string, unknown>,
filter as Record<string, unknown>
);
} catch (error) {
throw new Error(
`Failed to update rows in ${tableName}: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
},
});

View File

@@ -0,0 +1,110 @@
import {
PieceAuth,
Property,
StaticPropsValue,
} from '@activepieces/pieces-framework';
import oracledb from 'oracledb';
try {
oracledb.initOracleClient();
} catch (e) {
console.log('Oracle client already initialized or failed to initialize.');
}
export const oracleDbAuth = PieceAuth.CustomAuth({
description: `Connect to Oracle Database using either Service Name (host/port/service) or a full connection string.`,
required: true,
props: {
connectionType: Property.StaticDropdown({
displayName: 'Connection Type',
description: 'How you want to connect',
required: true,
options: {
options: [
{ label: 'Service Name', value: 'serviceName' },
{ label: 'Connection String', value: 'connectionString' },
],
},
defaultValue: 'serviceName',
}),
host: Property.ShortText({
displayName: 'Host',
description: 'Database server hostname or IP',
required: false,
}),
port: Property.Number({
displayName: 'Port',
description: 'Database port',
required: false,
defaultValue: 1521,
}),
serviceName: Property.ShortText({
displayName: 'Service Name',
description: 'Oracle service name',
required: false,
}),
connectionString: Property.LongText({
displayName: 'Connection String',
description: 'Full connection string (e.g., host:port/serviceName)',
required: false,
}),
user: Property.ShortText({
displayName: 'Username',
required: true,
}),
password: PieceAuth.SecretText({
displayName: 'Password',
required: true,
}),
},
validate: async ({ auth }) => {
let connection: oracledb.Connection | undefined;
const typedAuth = auth as StaticPropsValue<(typeof oracleDbAuth)['props']>;
try {
let connectString: string | undefined;
if (typedAuth.connectionType === 'serviceName') {
if (!typedAuth.host || !typedAuth.port || !typedAuth.serviceName) {
return {
valid: false,
error: 'Host, Port, and Service Name are required for this connection type.',
};
}
connectString = `${typedAuth.host}:${typedAuth.port}/${typedAuth.serviceName}`;
} else {
if (!typedAuth.connectionString) {
return {
valid: false,
error: 'Connection String is required for this connection type.',
};
}
connectString = typedAuth.connectionString;
}
connection = await oracledb.getConnection({
user: typedAuth.user,
password: typedAuth.password,
connectString: connectString,
});
return { valid: true };
} catch (e) {
return {
valid: false,
error: (e as Error)?.message || 'Unknown connection error.',
};
} finally {
if (connection) {
try {
await connection.close();
} catch (e) {
console.error('Failed to close Oracle DB connection:', e);
}
}
}
},
});
export type OracleDbAuth = StaticPropsValue<typeof oracleDbAuth.props>;

View File

@@ -0,0 +1,389 @@
import { OracleDbAuth } from './types';
import oracledb from 'oracledb';
interface ExecuteManyResult {
rowsAffected?: number;
}
export class OracleDbClient {
private readonly auth: OracleDbAuth;
private connection: oracledb.Connection | undefined;
constructor(auth: OracleDbAuth) {
this.auth = auth;
}
private async connect(): Promise<void> {
const connectString =
this.auth.connectionType === 'serviceName'
? `${this.auth.host}:${this.auth.port}/${this.auth.serviceName}`
: this.auth.connectionString;
this.connection = await oracledb.getConnection({
user: this.auth.user,
password: this.auth.password,
connectString: connectString,
});
}
public async getTables(): Promise<{ label: string; value: string }[]> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const result = await this.connection.execute<{ TABLE_NAME: string }>(
`SELECT table_name FROM user_tables ORDER BY table_name`,
[],
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await this.close();
return (
result.rows?.map((row) => ({
label: row.TABLE_NAME,
value: row.TABLE_NAME,
})) || []
);
}
public async insertRow(
tableName: string,
rowData: Record<string, unknown>
): Promise<{ success: boolean; rowsAffected: number }> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const columns = Object.keys(rowData);
const values = Object.values(rowData);
const placeholders = columns.map((_, i) => `:${i + 1}`).join(', ');
const quotedColumns = columns.map((c) => `"${c}"`).join(', ');
const quotedTableName = `"${tableName}"`;
const sql = `INSERT INTO ${quotedTableName} (${quotedColumns}) VALUES (${placeholders})`;
try {
const result = await this.connection.execute(sql, values, {
autoCommit: true,
});
await this.close();
return {
success: true,
rowsAffected: result.rowsAffected || 0,
};
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async insertRows(
tableName: string,
rowsData: Record<string, unknown>[]
): Promise<{ success: boolean; rowsAffected: number }> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const columns = Object.keys(rowsData[0]);
const quotedColumns = columns.map((c) => `"${c}"`).join(', ');
const quotedTableName = `"${tableName}"`;
const placeholders = columns.map((_, i) => `:${i + 1}`).join(', ');
const sql = `INSERT INTO ${quotedTableName} (${quotedColumns}) VALUES (${placeholders})`;
const bindData = rowsData.map((row) => columns.map((col) => row[col]));
try {
const result = await this.connection.executeMany(sql, bindData, {
autoCommit: true,
});
await this.close();
return {
success: true,
rowsAffected: result.rowsAffected || 0,
};
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async updateRow(
tableName: string,
values: Record<string, unknown>,
filter: Record<string, unknown>
): Promise<{ success: boolean; rowsAffected: number }> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const valueKeys = Object.keys(values);
const filterKeys = Object.keys(filter);
const setClause = valueKeys.map((k) => `"${k}" = :set_${k}`).join(', ');
const whereClause = filterKeys
.map((k) => `"${k}" = :whr_${k}`)
.join(' AND ');
const binds: oracledb.BindParameters = {};
for (const key of valueKeys) {
binds[`set_${key}`] = values[key] as any;
}
for (const key of filterKeys) {
binds[`whr_${key}`] = filter[key] as any;
}
let sql = `UPDATE "${tableName}" SET ${setClause}`;
if (whereClause) {
sql += ` WHERE ${whereClause}`;
}
try {
const result = await this.connection.execute(sql, binds, {
autoCommit: true,
});
await this.close();
return {
success: true,
rowsAffected: result.rowsAffected || 0,
};
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async deleteRow(
tableName: string,
filter: Record<string, unknown>
): Promise<{ success: boolean; rowsAffected: number }> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const filterKeys = Object.keys(filter);
const whereClause = filterKeys
.map((k) => `"${k}" = :whr_${k}`)
.join(' AND ');
const binds: oracledb.BindParameters = {};
for (const key of filterKeys) {
binds[`whr_${key}`] = filter[key] as any;
}
const sql = `DELETE FROM "${tableName}" WHERE ${whereClause}`;
try {
const result = await this.connection.execute(sql, binds, {
autoCommit: true,
});
await this.close();
return {
success: true,
rowsAffected: result.rowsAffected || 0,
};
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async findRow(
tableName: string,
filter: Record<string, unknown>
): Promise<unknown[]> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const filterKeys = Object.keys(filter);
const whereClause = filterKeys
.map((k) => `"${k}" = :whr_${k}`)
.join(' AND ');
const binds: oracledb.BindParameters = {};
for (const key of filterKeys) {
binds[`whr_${key}`] = filter[key] as any;
}
const sql = `SELECT * FROM "${tableName}" WHERE ${whereClause}`;
try {
const result = await this.connection.execute(sql, binds, {
outFormat: oracledb.OUT_FORMAT_OBJECT,
});
await this.close();
return (result.rows as unknown[]) || [];
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async execute(
sql: string,
binds: oracledb.BindParameters
): Promise<{ rows: unknown[]; rowsAffected?: number }> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
try {
const result = await this.connection.execute(sql, binds, {
autoCommit: true,
outFormat: oracledb.OUT_FORMAT_OBJECT,
});
await this.close();
return {
rows: (result.rows as unknown[]) || [],
rowsAffected: result.rowsAffected,
};
} catch (error: any) {
await this.close();
throw this.handleOracleError(error);
}
}
public async getNewRows(
tableName: string,
orderByColumn: string,
lastValue: unknown,
filter: Record<string, unknown>
): Promise<Record<string, unknown>[]> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const filterKeys = Object.keys(filter);
const whereConditions = filterKeys.map((k) => `"${k}" = :whr_${k}`);
whereConditions.push(`"${orderByColumn}" > :lastValue`);
const whereClause = whereConditions.join(' AND ');
const binds: Record<string, any> = { lastValue };
for (const key of filterKeys) {
binds[`whr_${key}`] = filter[key];
}
const sql = `SELECT * FROM "${tableName}" WHERE ${whereClause} ORDER BY "${orderByColumn}" ASC`;
const result = await this.connection.execute(sql, binds, {
outFormat: oracledb.OUT_FORMAT_OBJECT,
});
await this.close();
return result.rows as Record<string, unknown>[];
}
public async getLatestRows(
tableName: string,
orderByColumn: string,
filter: Record<string, unknown>
): Promise<oracledb.Result<unknown>> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const filterKeys = Object.keys(filter);
const whereClause = filterKeys
.map((k) => `"${k}" = :whr_${k}`)
.join(' AND ');
const binds: oracledb.BindParameters = {};
for (const key of filterKeys) {
binds[`whr_${key}`] = filter[key] as any;
}
let sql = `SELECT * FROM "${tableName}"`;
if (whereClause) {
sql += ` WHERE ${whereClause}`;
}
sql += ` ORDER BY "${orderByColumn}" DESC FETCH FIRST 5 ROWS ONLY`;
const result = await this.connection.execute(sql, binds, {
outFormat: oracledb.OUT_FORMAT_OBJECT,
});
await this.close();
return result;
}
public async getColumns(
tableName: string
): Promise<{ label: string; value: string }[]> {
await this.connect();
if (!this.connection) {
throw new Error('Database connection failed and was not established.');
}
const result = await this.connection.execute<{ COLUMN_NAME: string }>(
`SELECT column_name FROM user_tab_columns WHERE table_name = :tableName ORDER BY column_id`,
{ tableName },
{ outFormat: oracledb.OUT_FORMAT_OBJECT }
);
await this.close();
return (
result.rows?.map((row) => ({
label: row.COLUMN_NAME,
value: row.COLUMN_NAME,
})) || []
);
}
public async close(): Promise<void> {
if (this.connection) {
await this.connection.close();
this.connection = undefined;
}
}
private handleOracleError(error: any): Error {
const errorNum = error?.errorNum;
let message = error?.message || 'Unknown Oracle error';
// Common Oracle error codes
if (errorNum === 1) {
message = `Unique constraint violated: ${message}`;
} else if (errorNum === 2290 || errorNum === 2291 || errorNum === 2292) {
message = `Constraint violation: ${message}`;
} else if (errorNum === 1400) {
message = `Required column missing: ${message}`;
} else if (errorNum === 904 || errorNum === 942) {
message = `Invalid column or table: ${message}`;
} else if (errorNum === 1722) {
message = `Invalid number format: ${message}`;
} else if (errorNum === 12899) {
message = `Value too large for column: ${message}`;
}
return new Error(message);
}
}

View File

@@ -0,0 +1,64 @@
import { Property } from '@activepieces/pieces-framework';
import { OracleDbClient } from './client';
import { OracleDbAuth } from './types';
import { oracleDbAuth } from './auth';
export const oracleDbProps = {
tableName: () =>
Property.Dropdown({
auth: oracleDbAuth,
displayName: 'Table Name',
required: true,
refreshers: [],
options: async (propsValue) => {
const auth = propsValue.auth;
if (!auth) {
return {
disabled: true,
placeholder: 'Please authenticate first',
options: [],
};
}
const client = new OracleDbClient(auth.props);
const tables = await client.getTables();
return {
disabled: false,
options: tables.map((table) => ({
label: table.label,
value: table.value,
})),
};
},
}),
orderBy: () =>
Property.Dropdown({
auth: oracleDbAuth,
displayName: 'Order By Column',
description: 'Column that increases over time (ID or timestamp)',
required: true,
refreshers: ['tableName'],
options: async (propsValue) => {
const tableName = propsValue['tableName'] as string | undefined;
const auth = propsValue.auth;
if (!auth || !tableName) {
return {
disabled: true,
placeholder: 'Please select a table first',
options: [],
};
}
const client = new OracleDbClient(auth.props);
const columns = await client.getColumns(tableName);
return {
disabled: false,
options: columns.map((col: { label: string; value: string }) => ({
label: col.label,
value: col.value,
})),
};
},
}),
};

View File

@@ -0,0 +1,4 @@
import { StaticPropsValue } from '@activepieces/pieces-framework';
import { oracleDbAuth } from '../common/auth';
export type OracleDbAuth = StaticPropsValue<(typeof oracleDbAuth)['props']>;

View File

@@ -0,0 +1,130 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
Property,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import {
DedupeStrategy,
Polling,
pollingHelper,
} from '@activepieces/pieces-common';
import crypto from 'crypto';
import dayjs from 'dayjs';
import { oracleDbAuth } from '../common/auth';
import { OracleDbClient } from '../common/client';
import { oracleDbProps } from '../common/props';
import oracledb from 'oracledb';
type OrderDirection = 'ASC' | 'DESC';
const polling: Polling<
AppConnectionValueForAuthProperty<typeof oracleDbAuth>,
{
tableName: string;
orderBy: string;
orderDirection: OrderDirection | undefined;
}
> = {
strategy: DedupeStrategy.LAST_ITEM,
items: async ({ auth, propsValue, lastItemId }) => {
const client = new OracleDbClient(auth.props);
await client['connect']();
if (!client['connection']) {
throw new Error('Database connection failed');
}
const lastItem = lastItemId as string;
const lastOrderKey = lastItem ? lastItem.split('|')[0] : null;
const direction = propsValue.orderDirection || 'DESC';
let sql: string;
const binds: oracledb.BindParameters = {};
if (lastOrderKey === null) {
sql = `SELECT * FROM "${propsValue.tableName}" ORDER BY "${propsValue.orderBy}" ${direction} FETCH FIRST 5 ROWS ONLY`;
} else {
const operator = direction === 'DESC' ? '>=' : '<=';
sql = `SELECT * FROM "${propsValue.tableName}" WHERE "${propsValue.orderBy}" ${operator} :lastKey ORDER BY "${propsValue.orderBy}" ${direction}`;
binds['lastKey'] = lastOrderKey;
}
const result = await client['connection'].execute(sql, binds, {
outFormat: oracledb.OUT_FORMAT_OBJECT,
});
await client.close();
const rows = (result.rows as Record<string, any>[]) || [];
const items = rows.map((row) => {
const rowHash = crypto
.createHash('md5')
.update(JSON.stringify(row))
.digest('hex');
const isTimestamp = dayjs(row[propsValue.orderBy]).isValid();
const orderValue = isTimestamp
? dayjs(row[propsValue.orderBy]).toISOString()
: row[propsValue.orderBy];
return {
id: orderValue + '|' + rowHash,
data: row,
};
});
return items;
},
};
export const newRowTrigger = createTrigger({
auth: oracleDbAuth,
name: 'new_row',
displayName: 'New Row',
description: 'Triggers when a new row is created',
props: {
description: Property.MarkDown({
value: `**NOTE:** Fetches latest rows using the order column (newest first), then keeps polling for new rows.`,
}),
tableName: oracleDbProps.tableName(),
orderBy: oracleDbProps.orderBy(),
orderDirection: Property.StaticDropdown<OrderDirection>({
displayName: 'Order Direction',
description: 'Sort direction to fetch newest rows first',
required: true,
options: {
options: [
{ label: 'Ascending', value: 'ASC' },
{ label: 'Descending', value: 'DESC' },
],
},
defaultValue: 'DESC',
}),
},
type: TriggerStrategy.POLLING,
sampleData: {},
async onEnable(context) {
await pollingHelper.onEnable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth,
});
},
async onDisable(context) {
await pollingHelper.onDisable(polling, {
store: context.store,
propsValue: context.propsValue,
auth: context.auth,
});
},
async run(context) {
return await pollingHelper.poll(polling, context);
},
async test(context) {
return await pollingHelper.test(polling, context);
},
});