Compare commits

..

1 Commits

Author SHA1 Message Date
Rıdvan Akca
3c44f55f19 feat(bluesky): add bluesky integration 2024-05-28 10:03:49 +02:00
861 changed files with 22266 additions and 43698 deletions

View File

@@ -5,11 +5,8 @@ BACKEND_PORT=3000
WEB_PORT=3001 WEB_PORT=3001
echo "Configuring backend environment variables..." echo "Configuring backend environment variables..."
cd packages/backend cd packages/backend
rm -rf .env rm -rf .env
echo " echo "
PORT=$BACKEND_PORT PORT=$BACKEND_PORT
WEB_APP_URL=http://localhost:$WEB_PORT WEB_APP_URL=http://localhost:$WEB_PORT
@@ -24,35 +21,24 @@ WEBHOOK_SECRET_KEY=sample_webhook_secret_key
APP_SECRET_KEY=sample_app_secret_key APP_SECRET_KEY=sample_app_secret_key
REDIS_HOST=redis REDIS_HOST=redis
SERVE_WEB_APP_SEPARATELY=true" >> .env SERVE_WEB_APP_SEPARATELY=true" >> .env
echo "Installing backend dependencies..."
yarn
cd $CURRENT_DIR cd $CURRENT_DIR
echo "Configuring web environment variables..." echo "Configuring web environment variables..."
cd packages/web cd packages/web
rm -rf .env rm -rf .env
echo " echo "
PORT=$WEB_PORT PORT=$WEB_PORT
REACT_APP_BACKEND_URL=http://localhost:$BACKEND_PORT REACT_APP_BACKEND_URL=http://localhost:$BACKEND_PORT
" >> .env " >> .env
echo "Installing web dependencies..."
yarn
cd $CURRENT_DIR cd $CURRENT_DIR
echo "Installing and linking dependencies..."
yarn
yarn lerna bootstrap
echo "Migrating database..." echo "Migrating database..."
cd packages/backend cd packages/backend
yarn db:migrate yarn db:migrate
yarn db:seed:user yarn db:seed:user
echo "Done!" echo "Done!"

View File

@@ -1,52 +0,0 @@
name: release-tag
on:
push:
branches:
- 'main'
jobs:
release-image:
runs-on: ubuntu-latest
env:
DOCKER_ORG: groot
DOCKER_LATEST: latest
RUNNER_TOOL_CACHE: /toolcache
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v2
with: # replace it with your local IP
config-inline: |
[registry."git.send.nrw"]
http = true
insecure = true
- name: Login to DockerHub
uses: docker/login-action@v2
with:
registry: git.send.nrw # replace it with your local IP
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Get Meta
id: meta
run: |
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v4
with:
context: ./docker
file: ./docker/Dockerfile.compose
entrypoint: ./docker/compose-entrypoint.sh
platforms: |
linux/amd64
push: true
tags: | # replace it with your local IP and tags
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}

View File

@@ -41,11 +41,8 @@ jobs:
with: with:
node-version: 18 node-version: 18
- name: Install dependencies - name: Install dependencies
run: yarn run: cd packages/backend && yarn
working-directory: packages/backend
- name: Copy .env-example.test file to .env.test - name: Copy .env-example.test file to .env.test
run: cp .env-example.test .env.test run: cd packages/backend && cp .env-example.test .env.test
working-directory: packages/backend
- name: Run tests - name: Run tests
run: yarn test:coverage run: cd packages/backend && yarn test
working-directory: packages/backend

View File

@@ -18,13 +18,11 @@ jobs:
with: with:
node-version: '18' node-version: '18'
cache: 'yarn' cache: 'yarn'
cache-dependency-path: packages/backend/yarn.lock cache-dependency-path: yarn.lock
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner." - run: echo "🖥️ The workflow is now ready to test your code on the runner."
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile
working-directory: packages/backend - run: cd packages/backend && yarn lint
- run: yarn lint
working-directory: packages/backend
- run: echo "🍏 This job's status is ${{ job.status }}." - run: echo "🍏 This job's status is ${{ job.status }}."
start-backend-server: start-backend-server:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -37,13 +35,11 @@ jobs:
with: with:
node-version: '18' node-version: '18'
cache: 'yarn' cache: 'yarn'
cache-dependency-path: packages/backend/yarn.lock cache-dependency-path: yarn.lock
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner." - run: echo "🖥️ The workflow is now ready to test your code on the runner."
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile && yarn lerna bootstrap
working-directory: packages/backend - run: cd packages/backend && yarn start
- run: yarn start
working-directory: packages/backend
env: env:
ENCRYPTION_KEY: sample_encryption_key ENCRYPTION_KEY: sample_encryption_key
WEBHOOK_SECRET_KEY: sample_webhook_secret_key WEBHOOK_SECRET_KEY: sample_webhook_secret_key
@@ -59,13 +55,11 @@ jobs:
with: with:
node-version: '18' node-version: '18'
cache: 'yarn' cache: 'yarn'
cache-dependency-path: packages/backend/yarn.lock cache-dependency-path: yarn.lock
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner." - run: echo "🖥️ The workflow is now ready to test your code on the runner."
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile && yarn lerna bootstrap
working-directory: packages/backend - run: cd packages/backend && yarn start:worker
- run: yarn start:worker
working-directory: packages/backend
env: env:
ENCRYPTION_KEY: sample_encryption_key ENCRYPTION_KEY: sample_encryption_key
WEBHOOK_SECRET_KEY: sample_webhook_secret_key WEBHOOK_SECRET_KEY: sample_webhook_secret_key
@@ -81,13 +75,11 @@ jobs:
with: with:
node-version: '18' node-version: '18'
cache: 'yarn' cache: 'yarn'
cache-dependency-path: packages/web/yarn.lock cache-dependency-path: yarn.lock
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner." - run: echo "🖥️ The workflow is now ready to test your code on the runner."
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile && yarn lerna bootstrap
working-directory: packages/web - run: cd packages/web && yarn build
- run: yarn build
working-directory: packages/web
env: env:
CI: false CI: false
- run: echo "🍏 This job's status is ${{ job.status }}." - run: echo "🍏 This job's status is ${{ job.status }}."

View File

@@ -3,13 +3,12 @@ on:
push: push:
branches: branches:
- main - main
# TODO: Add pull request after optimizing the total excecution time of the test suite. pull_request:
# pull_request: paths:
# paths: - 'packages/backend/**'
# - 'packages/backend/**' - 'packages/e2e-tests/**'
# - 'packages/e2e-tests/**' - 'packages/web/**'
# - 'packages/web/**' - '!packages/backend/src/apps/**'
# - '!packages/backend/src/apps/**'
workflow_dispatch: workflow_dispatch:
env: env:
@@ -59,27 +58,22 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- name: Install web dependencies - name: Install dependencies
run: yarn run: yarn && yarn lerna bootstrap
working-directory: ./packages/web
- name: Install backend dependencies
run: yarn
working-directory: ./packages/backend
- name: Install e2e-tests dependencies
run: yarn
working-directory: ./packages/e2e-tests
- name: Install Playwright Browsers - name: Install Playwright Browsers
run: yarn playwright install --with-deps run: yarn playwright install --with-deps
working-directory: ./packages/e2e-tests
- name: Build Automatisch web - name: Build Automatisch web
run: yarn build
working-directory: ./packages/web working-directory: ./packages/web
run: yarn build
env: env:
# Keep this until we clean up warnings in build processes # Keep this until we clean up warnings in build processes
CI: false CI: false
- name: Migrate database - name: Migrate database
working-directory: ./packages/backend working-directory: ./packages/backend
run: yarn db:migrate run: yarn db:migrate
- name: Seed user
working-directory: ./packages/backend
run: yarn db:seed:user &
- name: Install certutils - name: Install certutils
run: sudo apt install -y libnss3-tools run: sudo apt install -y libnss3-tools
- name: Install mkcert - name: Install mkcert

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ logs
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log*
.pnpm-debug.log* .pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)

View File

@@ -1,7 +1,10 @@
version: '3.9' version: '3.9'
services: services:
main: main:
image: git.send.nrw/groot/automatisch:latest build:
context: ./docker
dockerfile: Dockerfile.compose
entrypoint: /compose-entrypoint.sh
ports: ports:
- '3000:3000' - '3000:3000'
depends_on: depends_on:
@@ -25,7 +28,10 @@ services:
volumes: volumes:
- automatisch_storage:/automatisch/storage - automatisch_storage:/automatisch/storage
worker: worker:
image: git.send.nrw/groot/automatisch:latest build:
context: ./docker
dockerfile: Dockerfile.compose
entrypoint: /compose-entrypoint.sh
depends_on: depends_on:
- main - main
environment: environment:

View File

@@ -1,22 +1,20 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM node:18-alpine FROM node:18-alpine
ENV PORT=3000 ENV PORT 3000
RUN \ RUN \
apk --no-cache add --virtual build-dependencies python3 build-base git make g++ apk --no-cache add --virtual build-dependencies python3 build-base git
WORKDIR /automatisch WORKDIR /automatisch
# copy the app, note .dockerignore # copy the app, note .dockerignore
COPY . /automatisch COPY . /automatisch
RUN cd packages/web && yarn RUN yarn
RUN cd packages/web && yarn build RUN cd packages/web && yarn build
RUN cd packages/backend && yarn --production
RUN \ RUN \
rm -rf /usr/local/share/.cache/ && \ rm -rf /usr/local/share/.cache/ && \
apk del build-dependencies apk del build-dependencies

13
lerna.json Normal file
View File

@@ -0,0 +1,13 @@
{
"packages": [
"packages/*"
],
"version": "0.10.0",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
"add": {
"exact": true
}
}
}

32
package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "@automatisch/root",
"license": "See LICENSE file",
"private": true,
"scripts": {
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
"start:web": "lerna run --stream --scope=@*/web dev",
"start:backend": "lerna run --stream --scope=@*/backend dev",
"build:docs": "cd ./packages/docs && yarn install && yarn build"
},
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/babel-loader",
"**/webpack",
"**/@automatisch/web",
"**/ajv"
]
},
"devDependencies": {
"eslint": "^8.13.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"lerna": "^4.0.0",
"prettier": "^2.5.1"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -10,7 +10,7 @@ import process from 'process';
async function fetchAdminRole() { async function fetchAdminRole() {
const role = await Role.query() const role = await Role.query()
.where({ .where({
name: 'Admin', key: 'admin',
}) })
.limit(1) .limit(1)
.first(); .first();

View File

@@ -1,6 +1,6 @@
import { knexSnakeCaseMappers } from 'objection'; import { knexSnakeCaseMappers } from 'objection';
import appConfig from './src/config/app.js'; import appConfig from './src/config/app.js';
import path, { join } from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
const fileExtension = 'js'; const fileExtension = 'js';
@@ -20,12 +20,12 @@ const knexConfig = {
searchPath: [appConfig.postgresSchema], searchPath: [appConfig.postgresSchema],
pool: { min: 0, max: 20 }, pool: { min: 0, max: 20 },
migrations: { migrations: {
directory: join(__dirname, '/src/db/migrations'), directory: __dirname + '/src/db/migrations',
extension: fileExtension, extension: fileExtension,
loadExtensions: [`.${fileExtension}`], loadExtensions: [`.${fileExtension}`],
}, },
seeds: { seeds: {
directory: join(__dirname, '/src/db/seeds'), directory: __dirname + '/src/db/seeds',
}, },
...(appConfig.isTest ? knexSnakeCaseMappers() : {}), ...(appConfig.isTest ? knexSnakeCaseMappers() : {}),
}; };

View File

@@ -5,14 +5,12 @@
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.", "description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "nodemon --exec node src/server.js", "dev": "nodemon --watch 'src/**/*.js' --exec 'node' src/server.js",
"worker": "nodemon --exec node src/worker.js", "worker": "nodemon --watch 'src/**/*.js' --exec 'node' src/worker.js",
"start": "node src/server.js", "start": "node src/server.js",
"start:worker": "node src/worker.js", "start:worker": "node src/worker.js",
"pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js", "pretest": "APP_ENV=test node ./test/setup/prepare-test-env.js",
"test": "APP_ENV=test vitest run", "test": "APP_ENV=test vitest run",
"test:watch": "APP_ENV=test vitest watch",
"test:coverage": "yarn test --coverage",
"lint": "eslint .", "lint": "eslint .",
"db:create": "node ./bin/database/create.js", "db:create": "node ./bin/database/create.js",
"db:seed:user": "node ./bin/database/seed-user.js", "db:seed:user": "node ./bin/database/seed-user.js",
@@ -24,7 +22,8 @@
"dependencies": { "dependencies": {
"@bull-board/express": "^3.10.1", "@bull-board/express": "^3.10.1",
"@casl/ability": "^6.5.0", "@casl/ability": "^6.5.0",
"@faker-js/faker": "^9.2.0", "@graphql-tools/graphql-file-loader": "^7.3.4",
"@graphql-tools/load": "^7.5.2",
"@node-saml/passport-saml": "^4.0.4", "@node-saml/passport-saml": "^4.0.4",
"@rudderstack/rudder-sdk-node": "^1.1.2", "@rudderstack/rudder-sdk-node": "^1.1.2",
"@sentry/node": "^7.42.0", "@sentry/node": "^7.42.0",
@@ -38,18 +37,18 @@
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"debug": "~2.6.9", "debug": "~2.6.9",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"eslint": "^8.13.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"express": "~4.18.2", "express": "~4.18.2",
"express-async-errors": "^3.1.1", "express-async-handler": "^1.2.0",
"express-basic-auth": "^1.2.1", "express-basic-auth": "^1.2.1",
"express-graphql": "^0.12.0",
"fast-xml-parser": "^4.0.11", "fast-xml-parser": "^4.0.11",
"graphql-middleware": "^6.1.15",
"graphql-shield": "^7.5.0",
"graphql-tools": "^8.2.0",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"http-errors": "~1.6.3", "http-errors": "~1.6.3",
"http-proxy-agent": "^7.0.0", "http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.1",
"isolated-vm": "^5.0.1",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"knex": "^2.4.0", "knex": "^2.4.0",
"libphonenumber-js": "^1.10.48", "libphonenumber-js": "^1.10.48",
@@ -66,7 +65,6 @@
"pg": "^8.7.1", "pg": "^8.7.1",
"php-serialize": "^4.0.2", "php-serialize": "^4.0.2",
"pluralize": "^8.0.0", "pluralize": "^8.0.0",
"prettier": "^2.5.1",
"raw-body": "^2.5.2", "raw-body": "^2.5.2",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"uuid": "^9.0.1", "uuid": "^9.0.1",
@@ -98,19 +96,12 @@
"url": "https://github.com/automatisch/automatisch/issues" "url": "https://github.com/automatisch/automatisch/issues"
}, },
"devDependencies": { "devDependencies": {
"@vitest/coverage-v8": "^2.1.5",
"node-gyp": "^10.1.0", "node-gyp": "^10.1.0",
"nodemon": "^2.0.13", "nodemon": "^2.0.13",
"supertest": "^6.3.3", "supertest": "^6.3.3",
"vitest": "^2.1.5" "vitest": "^1.1.3"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
},
"nodemonConfig": {
"watch": [
"src/"
],
"ext": "js"
} }
} }

View File

@@ -1,6 +1,5 @@
import createError from 'http-errors'; import createError from 'http-errors';
import express from 'express'; import express from 'express';
import 'express-async-errors';
import cors from 'cors'; import cors from 'cors';
import appConfig from './config/app.js'; import appConfig from './config/app.js';

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: 'https://api.airtable.com', apiBaseUrl: 'https://api.airtable.com',
iconUrl: '{BASE_URL}/apps/airtable/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/airtable/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/airtable/connection', authDocUrl: '{DOCS_URL}/apps/airtable/connection',
primaryColor: '#FFBF00', primaryColor: 'FFBF00',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: 'https://cloud.appwrite.io', apiBaseUrl: 'https://cloud.appwrite.io',
iconUrl: '{BASE_URL}/apps/appwrite/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/appwrite/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/appwrite/connection', authDocUrl: '{DOCS_URL}/apps/appwrite/connection',
primaryColor: '#FD366E', primaryColor: 'FD366E',
supportsConnections: true, supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader], beforeRequest: [setBaseUrl, addAuthHeader],
auth, auth,

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: '', apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/azure-openai/connection', authDocUrl: '{DOCS_URL}/apps/azure-openai/connection',
primaryColor: '#000000', primaryColor: '000000',
supportsConnections: true, supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader], beforeRequest: [setBaseUrl, addAuthHeader],
auth, auth,

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 430 390" fill="#1185fd" aria-hidden="true">
<path d="M180 141.964C163.699 110.262 119.308 51.1817 78.0347 22.044C38.4971 -5.86834 23.414 -1.03207 13.526 3.43594C2.08093 8.60755 0 26.1785 0 36.5164C0 46.8542 5.66748 121.272 9.36416 133.694C21.5786 174.738 65.0603 188.607 105.104 184.156C107.151 183.852 109.227 183.572 111.329 183.312C109.267 183.642 107.19 183.924 105.104 184.156C46.4204 192.847 -5.69621 214.233 62.6582 290.33C137.848 368.18 165.705 273.637 180 225.702C194.295 273.637 210.76 364.771 295.995 290.33C360 225.702 313.58 192.85 254.896 184.158C252.81 183.926 250.733 183.645 248.671 183.315C250.773 183.574 252.849 183.855 254.896 184.158C294.94 188.61 338.421 174.74 350.636 133.697C354.333 121.275 360 46.8568 360 36.519C360 26.1811 357.919 8.61012 346.474 3.43851C336.586 -1.02949 321.503 -5.86576 281.965 22.0466C240.692 51.1843 196.301 110.262 180 141.964Z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 956 B

View File

@@ -1,33 +1,34 @@
import verifyCredentials from './verify-credentials.js'; import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js'; import isStillVerified from './is-still-verified.js';
import refreshToken from './refresh-token.js';
export default { export default {
fields: [ fields: [
{ {
key: 'screenName', key: 'handle',
label: 'Screen Name', label: 'Your Bluesky Handle',
type: 'string', type: 'string',
required: true, required: true,
readOnly: false, readOnly: false,
value: null, value: null,
placeholder: null, placeholder: null,
description: description: '',
'Screen name of your connection to be used on Automatisch UI.',
clickToCopy: false, clickToCopy: false,
}, },
{ {
key: 'apiKey', key: 'password',
label: 'API Key', label: 'Your Bluesky Password',
type: 'string', type: 'string',
required: true, required: true,
readOnly: false, readOnly: false,
value: null, value: null,
placeholder: null, placeholder: null,
description: 'MailerLite API key of your account.', description: '',
clickToCopy: false, clickToCopy: false,
}, },
], ],
verifyCredentials, verifyCredentials,
isStillVerified, isStillVerified,
refreshToken,
}; };

View File

@@ -2,7 +2,7 @@ import getCurrentUser from '../common/get-current-user.js';
const isStillVerified = async ($) => { const isStillVerified = async ($) => {
const currentUser = await getCurrentUser($); const currentUser = await getCurrentUser($);
return !!currentUser.id; return !!currentUser.did;
}; };
export default isStillVerified; export default isStillVerified;

View File

@@ -0,0 +1,24 @@
const refreshToken = async ($) => {
const { refreshJwt } = $.auth.data;
const { data } = await $.http.post(
'/com.atproto.server.refreshSession',
null,
{
headers: {
Authorization: `Bearer ${refreshJwt}`,
},
additionalProperties: {
skipAddingAuthHeader: true,
},
}
);
await $.auth.set({
accessJwt: data.accessJwt,
refreshJwt: data.refreshJwt,
did: data.did,
});
};
export default refreshToken;

View File

@@ -0,0 +1,20 @@
const verifyCredentials = async ($) => {
const handle = $.auth.data.handle;
const password = $.auth.data.password;
const body = {
identifier: handle,
password,
};
const { data } = await $.http.post('/com.atproto.server.createSession', body);
await $.auth.set({
accessJwt: data.accessJwt,
refreshJwt: data.refreshJwt,
did: data.did,
screenName: data.handle,
});
};
export default verifyCredentials;

View File

@@ -1,9 +1,9 @@
const addAuthHeader = ($, requestConfig) => { const addAuthHeader = ($, requestConfig) => {
if ( if (requestConfig.additionalProperties?.skipAddingAuthHeader)
!requestConfig.additionalProperties?.skipAddingAuthHeader && return requestConfig;
$.auth.data?.accessToken
) { if ($.auth.data?.accessJwt) {
requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessToken}`; requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessJwt}`;
} }
return requestConfig; return requestConfig;

View File

@@ -0,0 +1,15 @@
const getCurrentUser = async ($) => {
const handle = $.auth.data.handle;
const params = {
actor: handle,
};
const { data: currentUser } = await $.http.get('/app.bsky.actor.getProfile', {
params,
});
return currentUser;
};
export default getCurrentUser;

View File

@@ -0,0 +1,16 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
export default defineApp({
name: 'Bluesky',
key: 'bluesky',
iconUrl: '{BASE_URL}/apps/bluesky/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/bluesky/connection',
supportsConnections: true,
baseUrl: 'https://bluesky.app',
apiBaseUrl: 'https://bsky.social/xrpc',
primaryColor: '1185fd',
beforeRequest: [addAuthHeader],
auth,
});

View File

@@ -7,7 +7,7 @@ export default defineAction({
'Creates an attachment of a specified object by given parent ID.', 'Creates an attachment of a specified object by given parent ID.',
arguments: [ arguments: [
{ {
label: 'Template Data', label: 'Templete Data',
key: 'templateData', key: 'templateData',
type: 'string', type: 'string',
required: true, required: true,

View File

@@ -11,7 +11,7 @@ export default defineApp({
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://carbone.io', baseUrl: 'https://carbone.io',
apiBaseUrl: 'https://api.carbone.io', apiBaseUrl: 'https://api.carbone.io',
primaryColor: '#6f42c1', primaryColor: '6f42c1',
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
actions, actions,

View File

@@ -1,72 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create folder',
key: 'createFolder',
description: 'Creates a new folder.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder Name',
key: 'folderName',
type: 'string',
required: true,
description: '',
variables: true,
},
],
async run($) {
const { spaceId, folderName } = $.step.parameters;
const body = {
name: folderName,
};
const { data } = await $.http.post(`/v2/space/${spaceId}/folder`, body);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -1,135 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create list',
key: 'createList',
description: 'Creates a new list.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder',
key: 'folderId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.spaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFolders',
},
{
name: 'parameters.spaceId',
value: '{parameters.spaceId}',
},
],
},
},
{
label: 'List Name',
key: 'listName',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'List Info',
key: 'listInfo',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Priority',
key: 'priority',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Urgent', value: 1 },
{ label: 'High', value: 2 },
{ label: 'Normal', value: 3 },
{ label: 'Low', value: 4 },
],
},
{
label: 'Due Date',
key: 'dueDate',
type: 'string',
required: false,
description: 'format: integer <int64>',
variables: true,
},
],
async run($) {
const { folderId, listName, listInfo, priority, dueDate } =
$.step.parameters;
const body = {
name: listName,
content: listInfo,
};
if (priority) {
body.priority = priority;
}
if (dueDate) {
body.due_date = dueDate;
}
const { data } = await $.http.post(`/v2/folder/${folderId}/list`, body);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -1,294 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create task',
key: 'createTask',
description: 'Creates a new task.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder',
key: 'folderId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.spaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFolders',
},
{
name: 'parameters.spaceId',
value: '{parameters.spaceId}',
},
],
},
},
{
label: 'List',
key: 'listId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.folderId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLists',
},
{
name: 'parameters.folderId',
value: '{parameters.folderId}',
},
],
},
},
{
label: 'Task Name',
key: 'taskName',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Task Description',
key: 'taskDescription',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Markdown Content',
key: 'markdownContent',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'False', value: 'false' },
{ label: 'True', value: 'true' },
],
},
{
label: 'Assignees',
key: 'assigneeIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Assignee',
key: 'assigneeId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.listId'],
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listAssignees',
},
{
name: 'parameters.listId',
value: '{parameters.listId}',
},
],
},
},
],
},
{
label: 'Task Status',
key: 'taskStatus',
type: 'dropdown',
required: false,
dependsOn: ['parameters.listId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listStatuses',
},
{
name: 'parameters.listId',
value: '{parameters.listId}',
},
],
},
},
{
label: 'Tags',
key: 'tagIds',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'tag',
key: 'tagId',
type: 'dropdown',
required: false,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listTags',
},
],
},
},
],
},
{
label: 'Priority',
key: 'priority',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Urgent', value: 1 },
{ label: 'High', value: 2 },
{ label: 'Normal', value: 3 },
{ label: 'Low', value: 4 },
],
},
{
label: 'Due Date',
key: 'dueDate',
type: 'string',
required: false,
description: 'format: integer <int64>',
variables: true,
},
{
label: 'Start Date',
key: 'startDate',
type: 'string',
required: false,
description: 'format: integer <int64>',
variables: true,
},
],
async run($) {
const {
listId,
taskName,
taskDescription,
markdownContent,
assigneeIds,
taskStatus,
tagIds,
priority,
dueDate,
startDate,
} = $.step.parameters;
const tags = tagIds.map((tag) => tag.tagId);
const assignees = assigneeIds.map((assignee) =>
Number(assignee.assigneeId)
);
const body = {
name: taskName,
};
if (assignees.length) {
body.assignees = assignees;
}
if (taskStatus) {
body.status = taskStatus;
}
if (tags.length) {
body.tags = tags;
}
if (priority) {
body.priority = priority;
}
if (dueDate) {
body.due_date = dueDate;
}
if (startDate) {
body.start_date = startDate;
}
if (markdownContent) {
body.markdown_description = taskDescription;
} else {
body.description = taskDescription;
}
const { data } = await $.http.post(`/v2/list/${listId}/task`, body);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -1,82 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Find task by id',
key: 'findTaskById',
description: 'Finds a task using id.',
arguments: [
{
label: 'Task ID',
key: 'taskId',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Use Custom ID',
key: 'useCustomId',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{
label: 'True',
value: true,
},
{
label: 'False',
value: false,
},
],
additionalFields: {
type: 'query',
name: 'getDynamicFields',
arguments: [
{
name: 'key',
value: 'listFieldsWhenUsingCustomId',
},
{
name: 'parameters.useCustomId',
value: '{parameters.useCustomId}',
},
],
},
},
{
label: 'Include Subtasks?',
key: 'includeSubtasks',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{
label: 'True',
value: true,
},
{
label: 'False',
value: false,
},
],
},
],
async run($) {
const { taskId, useCustomId, includeSubtasks } = $.step.parameters;
const params = {
custom_task_ids: useCustomId || false,
include_subtasks: includeSubtasks,
};
const { data } = await $.http.get(`/v2/task/${taskId}`, { params });
$.setActionItem({
raw: data,
});
},
});

View File

@@ -1,6 +0,0 @@
import createFolder from './create-folder/index.js';
import createList from './create-list/index.js';
import createTask from './create-task/index.js';
import findTaskById from './find-task-by-id/index.js';
export default [createFolder, createList, createTask, findTaskById];

View File

@@ -1,27 +0,0 @@
<svg width="185" height="185" viewBox="0 0 185 185" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d)">
<rect x="30" y="20" width="125" height="125" rx="62.5" fill="white"/>
<rect x="30" y="20" width="125" height="125" rx="62.5" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M55.8789 105.714L69.3974 95.3593C76.5762 104.732 84.1998 109.051 92.6948 109.051C101.143 109.051 108.557 104.781 115.414 95.4832L129.119 105.59C119.232 118.996 106.932 126.079 92.6948 126.079C78.5049 126.079 66.0907 119.046 55.8789 105.714Z" fill="url(#paint0_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M92.6491 60.7078L68.5883 81.4406L57.4727 68.5407L92.6969 38.1885L127.647 68.5644L116.477 81.417L92.6491 60.7078Z" fill="url(#paint1_linear)"/>
</g>
<defs>
<filter id="filter0_d" x="0" y="0" width="185" height="185" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="10"/>
<feGaussianBlur stdDeviation="15"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.117647 0 0 0 0 0.211765 0 0 0 0.1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
<linearGradient id="paint0_linear" x1="55.8789" y1="116.251" x2="129.119" y2="116.251" gradientUnits="userSpaceOnUse">
<stop stop-color="#8930FD"/>
<stop offset="1" stop-color="#49CCF9"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="57.4727" y1="67.6025" x2="127.647" y2="67.6025" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF02F0"/>
<stop offset="1" stop-color="#FFC800"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,21 +0,0 @@
import { URLSearchParams } from 'url';
export default async function generateAuthUrl($) {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const state = Math.random().toString();
const searchParams = new URLSearchParams({
client_id: $.auth.data.clientId,
redirect_uri: redirectUri,
state,
});
const url = `https://app.clickup.com/api?${searchParams.toString()}`;
await $.auth.set({
url,
originalState: state,
});
}

View File

@@ -1,46 +0,0 @@
import generateAuthUrl from './generate-auth-url.js';
import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js';
export default {
fields: [
{
key: 'oAuthRedirectUrl',
label: 'OAuth Redirect URL',
type: 'string',
required: true,
readOnly: true,
value: '{WEB_APP_URL}/app/clickup/connections/add',
placeholder: null,
description:
'When asked to input a redirect URL in ClickUp, enter the URL above.',
clickToCopy: true,
},
{
key: 'clientId',
label: 'Client ID',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'clientSecret',
label: 'Client Secret',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
],
generateAuthUrl,
verifyCredentials,
isStillVerified,
};

View File

@@ -1,31 +0,0 @@
import getCurrentUser from '../common/get-current-user.js';
const verifyCredentials = async ($) => {
if ($.auth.data.originalState !== $.auth.data.state) {
throw new Error(`The 'state' parameter does not match.`);
}
const { data } = await $.http.post('/v2/oauth/token', {
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
});
await $.auth.set({
accessToken: data.access_token,
tokenType: data.token_type,
});
const currentUser = await getCurrentUser($);
const screenName = [currentUser.username, currentUser.email]
.filter(Boolean)
.join(' @ ');
await $.auth.set({
clientId: $.auth.data.clientId,
clientSecret: $.auth.data.clientSecret,
screenName,
});
};
export default verifyCredentials;

View File

@@ -1,9 +0,0 @@
const addAuthHeader = ($, requestConfig) => {
if ($.auth.data?.accessToken) {
requestConfig.headers.Authorization = `${$.auth.data.tokenType} ${$.auth.data.accessToken}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -1,6 +0,0 @@
const getCurrentUser = async ($) => {
const { data } = await $.http.get('/v2/user');
return data.user;
};
export default getCurrentUser;

View File

@@ -1,19 +0,0 @@
import listAssignees from './list-assignees/index.js';
import listFolders from './list-folders/index.js';
import listLists from './list-lists/index.js';
import listSpaces from './list-spaces/index.js';
import listStatuses from './list-statuses/index.js';
import listTags from './list-tags/index.js';
import listTasks from './list-tasks/index.js';
import listWorkspaces from './list-workspaces/index.js';
export default [
listAssignees,
listFolders,
listLists,
listSpaces,
listStatuses,
listTags,
listTasks,
listWorkspaces,
];

View File

@@ -1,28 +0,0 @@
export default {
name: 'List assignees',
key: 'listAssignees',
async run($) {
const assignees = {
data: [],
};
const listId = $.step.parameters.listId;
if (!listId) {
return assignees;
}
const { data } = await $.http.get(`/v2/list/${listId}/member`);
if (data.members) {
for (const member of data.members) {
assignees.data.push({
value: member.id,
name: member.username,
});
}
}
return assignees;
},
};

View File

@@ -1,28 +0,0 @@
export default {
name: 'List folders',
key: 'listFolders',
async run($) {
const folders = {
data: [],
};
const spaceId = $.step.parameters.spaceId;
if (!spaceId) {
return folders;
}
const { data } = await $.http.get(`/v2/space/${spaceId}/folder`);
if (data.folders) {
for (const folder of data.folders) {
folders.data.push({
value: folder.id,
name: folder.name,
});
}
}
return folders;
},
};

View File

@@ -1,28 +0,0 @@
export default {
name: 'List lists',
key: 'listLists',
async run($) {
const lists = {
data: [],
};
const folderId = $.step.parameters.folderId;
if (!folderId) {
return lists;
}
const { data } = await $.http.get(`/v2/folder/${folderId}/list`);
if (data.lists) {
for (const list of data.lists) {
lists.data.push({
value: list.id,
name: list.name,
});
}
}
return lists;
},
};

View File

@@ -1,28 +0,0 @@
export default {
name: 'List spaces',
key: 'listSpaces',
async run($) {
const spaces = {
data: [],
};
const workspaceId = $.step.parameters.workspaceId;
if (!workspaceId) {
return spaces;
}
const { data } = await $.http.get(`/v2/team/${workspaceId}/space`);
if (data.spaces) {
for (const space of data.spaces) {
spaces.data.push({
value: space.id,
name: space.name,
});
}
}
return spaces;
},
};

View File

@@ -1,28 +0,0 @@
export default {
name: 'List statuses',
key: 'listStatuses',
async run($) {
const statuses = {
data: [],
};
const listId = $.step.parameters.listId;
if (!listId) {
return statuses;
}
const { data } = await $.http.get(`/v2/list/${listId}`);
if (data.statuses) {
for (const status of data.statuses) {
statuses.data.push({
value: status.status,
name: status.status,
});
}
}
return statuses;
},
};

View File

@@ -1,28 +0,0 @@
export default {
name: 'List tags',
key: 'listTags',
async run($) {
const tags = {
data: [],
};
const spaceId = $.step.parameters.spaceId;
if (!spaceId) {
return spaceId;
}
const { data } = await $.http.get(`v2/space/${spaceId}/tag`);
if (data.tags) {
for (const tag of data.tags) {
tags.data.push({
value: tag.name,
name: tag.name,
});
}
}
return tags;
},
};

View File

@@ -1,41 +0,0 @@
export default {
name: 'List tasks',
key: 'listTasks',
async run($) {
const tasks = {
data: [],
};
const listId = $.step.parameters.listId;
let next = false;
if (!listId) {
return tasks;
}
const params = {
order_by: 'created',
reverse: true,
};
do {
const { data } = await $.http.get(`/v2/list/${listId}/task`, { params });
if (data.last_page) {
next = false;
} else {
next = true;
}
if (data.tasks) {
for (const task of data.tasks) {
tasks.data.push({
value: task.id,
name: task.name,
});
}
}
} while (next);
return tasks;
},
};

View File

@@ -1,23 +0,0 @@
export default {
name: 'List workspaces',
key: 'listWorkspaces',
async run($) {
const workspaces = {
data: [],
};
const { data } = await $.http.get('/v2/team');
if (data.teams) {
for (const workspace of data.teams) {
workspaces.data.push({
value: workspace.id,
name: workspace.name,
});
}
}
return workspaces;
},
};

View File

@@ -1,3 +0,0 @@
import useCustomId from './use-custom-id/index.js';
export default [useCustomId];

View File

@@ -1,29 +0,0 @@
export default {
name: 'List workspaces when using custom id',
key: 'listFieldsWhenUsingCustomId',
async run($) {
if ($.step.parameters.useCustomId) {
return [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
];
}
},
};

View File

@@ -1,24 +0,0 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
import actions from './actions/index.js';
import dynamicFields from './dynamic-fields/index.js';
export default defineApp({
name: 'ClickUp',
key: 'clickup',
baseUrl: 'https://clickup.com',
apiBaseUrl: 'https://api.clickup.com/api',
iconUrl: '{BASE_URL}/apps/clickup/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/clickup/connection',
primaryColor: '#FD71AF',
supportsConnections: true,
beforeRequest: [addAuthHeader],
auth,
triggers,
dynamicData,
actions,
dynamicFields,
});

View File

@@ -1,6 +0,0 @@
import newFolders from './new-folders/index.js';
import newLists from './new-lists/index.js';
import newTasks from './new-tasks/index.js';
import updatedTask from './updated-task/index.js';
export default [newFolders, newLists, newTasks, updatedTask];

View File

@@ -1,105 +0,0 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New folders',
key: 'newFolder',
type: 'webhook',
description: 'Triggers when a new folder is created.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: $.request.body.folder_id,
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const sampleEventData = {
event: 'folderCreated',
folder_id: '90180382912',
webhook_id: Crypto.randomUUID(),
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: '',
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const { workspaceId, spaceId } = $.step.parameters;
const payload = {
name: $.flow.id,
endpoint: $.webhookUrl,
events: ['folderCreated'],
};
if (spaceId) {
payload.space_id = spaceId;
}
const { data } = await $.http.post(
`/v2/team/${workspaceId}/webhook`,
payload
);
await $.flow.setRemoteWebhookId(data.id);
},
async unregisterHook($) {
await $.http.delete(`/v2/webhook/${$.flow.remoteWebhookId}`);
},
});

View File

@@ -1,129 +0,0 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New lists',
key: 'newLists',
type: 'webhook',
description: 'Triggers when a new list is created.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder',
key: 'folderId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.spaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFolders',
},
{
name: 'parameters.spaceId',
value: '{parameters.spaceId}',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: $.request.body.list_id,
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const sampleEventData = {
event: 'listCreated',
list_id: '901800588812',
webhook_id: Crypto.randomUUID(),
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.webhook_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const { workspaceId, spaceId, folderId } = $.step.parameters;
const payload = {
name: $.flow.id,
endpoint: $.webhookUrl,
events: ['listCreated'],
space_id: spaceId,
};
if (folderId) {
payload.folder_id = folderId;
}
const { data } = await $.http.post(
`/v2/team/${workspaceId}/webhook`,
payload
);
await $.flow.setRemoteWebhookId(data.id);
},
async unregisterHook($) {
await $.http.delete(`/v2/webhook/${$.flow.remoteWebhookId}`);
},
});

View File

@@ -1,186 +0,0 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New tasks',
key: 'newTasks',
type: 'webhook',
description: 'Triggers when a new task is created.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder',
key: 'folderId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.spaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFolders',
},
{
name: 'parameters.spaceId',
value: '{parameters.spaceId}',
},
],
},
},
{
label: 'List',
key: 'listId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.folderId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLists',
},
{
name: 'parameters.folderId',
value: '{parameters.folderId}',
},
],
},
},
{
label: 'Task',
key: 'taskId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.listId'],
description:
'Choose an optional task to determine when this flow should be activated. In this scenario, only subtasks will initiate this flow.',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listTasks',
},
{
name: 'parameters.listId',
value: '{parameters.listId}',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: $.request.body.task_id,
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const sampleEventData = {
event: 'taskCreated',
task_id: '86enn7pg7',
webhook_id: Crypto.randomUUID(),
history_items: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.webhook_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const { workspaceId, spaceId, folderId, listId, taskId } =
$.step.parameters;
const payload = {
name: $.flow.id,
endpoint: $.webhookUrl,
events: ['taskCreated'],
space_id: spaceId,
};
if (folderId) {
payload.folder_id = folderId;
}
if (listId) {
payload.list_id = listId;
}
if (taskId) {
payload.task_id = taskId;
}
const { data } = await $.http.post(
`/v2/team/${workspaceId}/webhook`,
payload
);
await $.flow.setRemoteWebhookId(data.id);
},
async unregisterHook($) {
await $.http.delete(`/v2/webhook/${$.flow.remoteWebhookId}`);
},
});

View File

@@ -1,172 +0,0 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'Updated task',
key: 'updatedTask',
type: 'webhook',
description: 'Triggers when a task is updated.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Space',
key: 'spaceId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpaces',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
{
label: 'Folder',
key: 'folderId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.spaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFolders',
},
{
name: 'parameters.spaceId',
value: '{parameters.spaceId}',
},
],
},
},
{
label: 'List',
key: 'listId',
type: 'dropdown',
required: false,
dependsOn: ['parameters.folderId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLists',
},
{
name: 'parameters.folderId',
value: '{parameters.folderId}',
},
],
},
},
{
label: 'What Changed?',
key: 'whatChanged',
type: 'dropdown',
required: false,
variables: true,
options: [
{ label: 'Status', value: 'taskStatusUpdated' },
{ label: 'Assignee Added', value: 'taskAssigneeUpdated' },
{ label: 'Priority', value: 'taskPriorityUpdated' },
{ label: 'Tag Added', value: 'taskTagUpdated' },
],
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const sampleEventData = {
event: 'taskUpdated',
task_id: '86enn7pg7',
webhook_id: Crypto.randomUUID(),
history_items: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.webhook_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const { workspaceId, spaceId, folderId, listId, whatChanged } =
$.step.parameters;
const payload = {
name: $.flow.id,
endpoint: $.webhookUrl,
space_id: spaceId,
};
payload.events = [whatChanged || 'taskUpdated'];
if (folderId) {
payload.folder_id = folderId;
}
if (listId) {
payload.list_id = listId;
}
const { data } = await $.http.post(
`/v2/team/${workspaceId}/webhook`,
payload
);
await $.flow.setRemoteWebhookId(data.id);
},
async unregisterHook($) {
await $.http.delete(`/v2/webhook/${$.flow.remoteWebhookId}`);
},
});

View File

@@ -1,3 +0,0 @@
import runJavascript from './run-javascript/index.js';
export default [runJavascript];

View File

@@ -1,84 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Run Javascript',
key: 'runJavascript',
description:
'Run browser Javascript code. You can not use NodeJS specific features and npm packages.',
arguments: [
{
label: 'Inputs',
key: 'inputs',
type: 'dynamic',
required: false,
description:
'To be able to use data from previous steps, you need to expose them as input entries. You can access these input values in your code by using the `inputs` argument.',
value: [
{
key: '',
value: '',
},
],
fields: [
{
label: 'Key',
key: 'key',
type: 'string',
required: true,
variables: true,
},
{
label: 'Value',
key: 'value',
type: 'string',
required: true,
variables: true,
valueType: 'parse',
},
],
},
{
label: 'Code Snippet',
key: 'codeSnippet',
type: 'code',
required: true,
variables: false,
value:
'const code = async (inputs) => { \n // E.g. if you have an input called username,\n // you can access its value by calling inputs.username\n // Return value will be used as output of this step.\n\n return true;\n};',
},
],
async run($) {
const { inputs = [], codeSnippet } = $.step.parameters;
const objectifiedInput = {};
for (const input of inputs) {
if (input.key) {
objectifiedInput[input.key] = input.value;
}
}
const ivm = (await import('isolated-vm')).default;
const isolate = new ivm.Isolate({ memoryLimit: 128 });
try {
const context = await isolate.createContext();
await context.global.set(
'inputs',
new ivm.ExternalCopy(objectifiedInput).copyInto()
);
const compiledCodeSnippet = await isolate.compileScript(
`${codeSnippet}; code(inputs);`
);
const codeFunction = await compiledCodeSnippet.run(context, {
reference: true,
promise: true,
});
$.setActionItem({ raw: { output: await codeFunction.copy() } });
} finally {
isolate.dispose();
}
},
});

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="800px" height="800px" viewBox="0 0 512 512">
<polyline points="160 368 32 256 160 144" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
<polyline points="352 368 480 256 352 144" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
<line x1="304" y1="96" x2="208" y2="416" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
</svg>

Before

Width:  |  Height:  |  Size: 519 B

View File

@@ -1,14 +0,0 @@
import defineApp from '../../helpers/define-app.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Code',
key: 'code',
baseUrl: '',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/code/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/code/connection',
primaryColor: '#000000',
supportsConnections: false,
actions,
});

View File

@@ -1,64 +0,0 @@
import { createHmac } from 'node:crypto';
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create HMAC',
key: 'createHmac',
description: 'Create a Hash-based Message Authentication Code (HMAC) using the specified algorithm, secret key, and message.',
arguments: [
{
label: 'Algorithm',
key: 'algorithm',
type: 'dropdown',
required: true,
value: 'sha256',
description: 'Specifies the cryptographic hash function to use for HMAC generation.',
options: [
{ label: 'SHA-256', value: 'sha256' },
],
variables: true,
},
{
label: 'Message',
key: 'message',
type: 'string',
required: true,
description: 'The input message to be hashed. This is the value that will be processed to generate the HMAC.',
variables: true,
},
{
label: 'Secret Key',
key: 'secretKey',
type: 'string',
required: true,
description: 'The secret key used to create the HMAC.',
variables: true,
},
{
label: 'Output Encoding',
key: 'outputEncoding',
type: 'dropdown',
required: true,
value: 'hex',
description: 'Specifies the encoding format for the HMAC digest output.',
options: [
{ label: 'base64', value: 'base64' },
{ label: 'base64url', value: 'base64url' },
{ label: 'hex', value: 'hex' },
],
variables: true,
},
],
async run($) {
const hash = createHmac($.step.parameters.algorithm, $.step.parameters.secretKey)
.update($.step.parameters.message)
.digest($.step.parameters.outputEncoding);
$.setActionItem({
raw: {
hash
},
});
},
});

View File

@@ -1,65 +0,0 @@
import crypto from 'node:crypto';
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create Signature',
key: 'createSignature',
description: 'Create a digital signature using the specified algorithm, secret key, and message.',
arguments: [
{
label: 'Algorithm',
key: 'algorithm',
type: 'dropdown',
required: true,
value: 'RSA-SHA256',
description: 'Specifies the cryptographic hash function to use for HMAC generation.',
options: [
{ label: 'RSA-SHA256', value: 'RSA-SHA256' },
],
variables: true,
},
{
label: 'Message',
key: 'message',
type: 'string',
required: true,
description: 'The input message to be signed.',
variables: true,
},
{
label: 'Private Key',
key: 'privateKey',
type: 'string',
required: true,
description: 'The RSA private key in PEM format used for signing.',
variables: true,
},
{
label: 'Output Encoding',
key: 'outputEncoding',
type: 'dropdown',
required: true,
value: 'hex',
description: 'Specifies the encoding format for the digital signature output. This determines how the generated signature will be represented as a string.',
options: [
{ label: 'base64', value: 'base64' },
{ label: 'base64url', value: 'base64url' },
{ label: 'hex', value: 'hex' },
],
variables: true,
},
],
async run($) {
const signer = crypto.createSign($.step.parameters.algorithm);
signer.update($.step.parameters.message);
signer.end();
const signature = signer.sign($.step.parameters.privateKey, $.step.parameters.outputEncoding);
$.setActionItem({
raw: {
signature
},
});
},
});

View File

@@ -1,4 +0,0 @@
import createHmac from './create-hmac/index.js';
import createRsaSha256Signature from './create-rsa-sha256-signature/index.js';
export default [createHmac, createRsaSha256Signature];

View File

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100pt" height="100pt" version="1.1" viewBox="0 0 100 100">
<path d="m66.012 33h-3.0117v-11c0-7.1719-5.8281-13-13-13s-13 5.8281-13 13v11h-3.0117c-2.75 0-4.9883 2.2383-4.9883 4.9883v28.012c0 2.75 2.2383 4.9883 4.9883 4.9883h32.012c2.75 0 4.9883-2.2383 4.9883-4.9883v-28.012c0.011719-2.75-2.2266-4.9883-4.9766-4.9883zm-27.012-11c0-6.0703 4.9297-11 11-11s11 4.9297 11 11v11h-22zm30 44.012c0 1.6484-1.3398 2.9883-2.9883 2.9883h-32.023c-1.6484 0-2.9883-1.3398-2.9883-2.9883v-28.023c0-1.6484 1.3398-2.9883 2.9883-2.9883h32.023c1.6484 0 2.9883 1.3398 2.9883 2.9883zm-18 9.9883v14c0 0.55078-0.44922 1-1 1s-1-0.44922-1-1v-14c0-0.55078 0.44922-1 1-1s1 0.44922 1 1zm20 8c0 0.55078-0.44922 1-1 1h-8c-0.55078 0-1-0.44922-1-1v-8c0-0.55078 0.44922-1 1-1s1 0.44922 1 1v7h7c0.55078 0 1 0.44922 1 1zm-32-8v8c0 0.55078-0.44922 1-1 1h-8c-0.55078 0-1-0.44922-1-1s0.44922-1 1-1h7v-7c0-0.55078 0.44922-1 1-1s1 0.44922 1 1zm-14-26c0 0.55078-0.44922 1-1 1h-14c-0.55078 0-1-0.44922-1-1s0.44922-1 1-1h14c0.55078 0 1 0.44922 1 1zm0-12c0 0.55078-0.44922 1-1 1h-8c-0.55078 0-1-0.44922-1-1v-8c0-0.55078 0.44922-1 1-1s1 0.44922 1 1v7h7c0.55078 0 1 0.44922 1 1zm0 24c0 0.55078-0.44922 1-1 1h-7v7c0 0.55078-0.44922 1-1 1s-1-0.44922-1-1v-8c0-0.55078 0.44922-1 1-1h8c0.55078 0 1 0.44922 1 1zm66-12c0 0.55078-0.44922 1-1 1h-14c-0.55078 0-1-0.44922-1-1s0.44922-1 1-1h14c0.55078 0 1 0.44922 1 1zm-16-12c0-0.55078 0.44922-1 1-1h7v-7c0-0.55078 0.44922-1 1-1s1 0.44922 1 1v8c0 0.55078-0.44922 1-1 1h-8c-0.55078 0-1-0.44922-1-1zm10 24v8c0 0.55078-0.44922 1-1 1s-1-0.44922-1-1v-7h-7c-0.55078 0-1-0.44922-1-1s0.44922-1 1-1h8c0.55078 0 1 0.44922 1 1zm-35-17c-2.7617 0-5 2.2383-5 5 0 2.4102 1.7188 4.4297 4 4.8984v5.1016c0 0.55078 0.44922 1 1 1s1-0.44922 1-1v-5.1016c2.2812-0.46094 4-2.4805 4-4.8984 0-2.7617-2.2383-5-5-5zm0 8c-1.6484 0-3-1.3516-3-3s1.3516-3 3-3 3 1.3516 3 3-1.3516 3-3 3z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,14 +0,0 @@
import defineApp from '../../helpers/define-app.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Cryptography',
key: 'cryptography',
iconUrl: '{BASE_URL}/apps/cryptography/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/cryptography/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',
primaryColor: '#001F52',
actions,
});

View File

@@ -9,6 +9,6 @@ export default defineApp({
supportsConnections: false, supportsConnections: false,
baseUrl: '', baseUrl: '',
apiBaseUrl: '', apiBaseUrl: '',
primaryColor: '#001F52', primaryColor: '001F52',
actions, actions,
}); });

View File

@@ -11,7 +11,7 @@ export default defineApp({
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://deepl.com', baseUrl: 'https://deepl.com',
apiBaseUrl: 'https://api.deepl.com', apiBaseUrl: 'https://api.deepl.com',
primaryColor: '#0d2d45', primaryColor: '0d2d45',
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
actions, actions,

View File

@@ -9,6 +9,6 @@ export default defineApp({
supportsConnections: false, supportsConnections: false,
baseUrl: '', baseUrl: '',
apiBaseUrl: '', apiBaseUrl: '',
primaryColor: '#001F52', primaryColor: '001F52',
actions, actions,
}); });

View File

@@ -14,7 +14,7 @@ export default defineApp({
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://discord.com', baseUrl: 'https://discord.com',
apiBaseUrl: 'https://discord.com/api', apiBaseUrl: 'https://discord.com/api',
primaryColor: '#5865f2', primaryColor: '5865f2',
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
dynamicData, dynamicData,

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: 'https://disqus.com/api', apiBaseUrl: 'https://disqus.com/api',
iconUrl: '{BASE_URL}/apps/disqus/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/disqus/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/disqus/connection', authDocUrl: '{DOCS_URL}/apps/disqus/connection',
primaryColor: '#2E9FFF', primaryColor: '2E9FFF',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -11,7 +11,7 @@ export default defineApp({
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://dropbox.com', baseUrl: 'https://dropbox.com',
apiBaseUrl: 'https://api.dropboxapi.com', apiBaseUrl: 'https://api.dropboxapi.com',
primaryColor: '#0061ff', primaryColor: '0061ff',
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
actions, actions,

View File

@@ -9,6 +9,6 @@ export default defineApp({
supportsConnections: false, supportsConnections: false,
baseUrl: '', baseUrl: '',
apiBaseUrl: '', apiBaseUrl: '',
primaryColor: '#001F52', primaryColor: '001F52',
actions, actions,
}); });

View File

@@ -10,7 +10,7 @@ export default defineApp({
iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/flickr/connection', authDocUrl: '{DOCS_URL}/apps/flickr/connection',
docUrl: 'https://automatisch.io/docs/flickr', docUrl: 'https://automatisch.io/docs/flickr',
primaryColor: '#000000', primaryColor: '000000',
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://www.flickr.com/', baseUrl: 'https://www.flickr.com/',
apiBaseUrl: 'https://www.flickr.com/services', apiBaseUrl: 'https://www.flickr.com/services',

View File

@@ -11,7 +11,7 @@ export default defineApp({
supportsConnections: true, supportsConnections: true,
baseUrl: 'https://flowers-software.com', baseUrl: 'https://flowers-software.com',
apiBaseUrl: 'https://webapp.flowers-software.com/api', apiBaseUrl: 'https://webapp.flowers-software.com/api',
primaryColor: '#02AFC7', primaryColor: '02AFC7',
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
triggers, triggers,

View File

@@ -1,10 +1,8 @@
import defineAction from '../../../../helpers/define-action.js'; import defineAction from '../../../../helpers/define-action.js';
import formatDateTime from './transformers/format-date-time.js'; import formatDateTime from './transformers/format-date-time.js';
import getCurrentTimestamp from './transformers/get-current-timestamp.js';
const transformers = { const transformers = {
formatDateTime, formatDateTime,
getCurrentTimestamp,
}; };
export default defineAction({ export default defineAction({
@@ -18,16 +16,7 @@ export default defineAction({
type: 'dropdown', type: 'dropdown',
required: true, required: true,
variables: true, variables: true,
options: [ options: [{ label: 'Format Date / Time', value: 'formatDateTime' }],
{
label: 'Get current timestamp',
value: 'getCurrentTimestamp',
},
{
label: 'Format Date / Time',
value: 'formatDateTime',
},
],
additionalFields: { additionalFields: {
type: 'query', type: 'query',
name: 'getDynamicFields', name: 'getDynamicFields',

View File

@@ -1,5 +0,0 @@
const getCurrentTimestamp = () => {
return Date.now();
};
export default getCurrentTimestamp;

View File

@@ -14,8 +14,6 @@ import stringToBase64 from './transformers/string-to-base64.js';
import encodeUri from './transformers/encode-uri.js'; import encodeUri from './transformers/encode-uri.js';
import trimWhitespace from './transformers/trim-whitespace.js'; import trimWhitespace from './transformers/trim-whitespace.js';
import useDefaultValue from './transformers/use-default-value.js'; import useDefaultValue from './transformers/use-default-value.js';
import parseStringifiedJson from './transformers/parse-stringified-json.js';
import createUuid from './transformers/create-uuid.js';
const transformers = { const transformers = {
base64ToString, base64ToString,
@@ -32,8 +30,6 @@ const transformers = {
encodeUri, encodeUri,
trimWhitespace, trimWhitespace,
useDefaultValue, useDefaultValue,
parseStringifiedJson,
createUuid,
}; };
export default defineAction({ export default defineAction({
@@ -51,21 +47,19 @@ export default defineAction({
options: [ options: [
{ label: 'Base64 to String', value: 'base64ToString' }, { label: 'Base64 to String', value: 'base64ToString' },
{ label: 'Capitalize', value: 'capitalize' }, { label: 'Capitalize', value: 'capitalize' },
{ label: 'Convert HTML to Markdown', value: 'htmlToMarkdown' },
{ label: 'Convert Markdown to HTML', value: 'markdownToHtml' },
{ label: 'Create UUID', value: 'createUuid' },
{ label: 'Encode URI', value: 'encodeUri' },
{ {
label: 'Encode URI Component', label: 'Encode URI Component',
value: 'encodeUriComponent', value: 'encodeUriComponent',
}, },
{ label: 'Convert HTML to Markdown', value: 'htmlToMarkdown' },
{ label: 'Convert Markdown to HTML', value: 'markdownToHtml' },
{ label: 'Extract Email Address', value: 'extractEmailAddress' }, { label: 'Extract Email Address', value: 'extractEmailAddress' },
{ label: 'Extract Number', value: 'extractNumber' }, { label: 'Extract Number', value: 'extractNumber' },
{ label: 'Lowercase', value: 'lowercase' }, { label: 'Lowercase', value: 'lowercase' },
{ label: 'Parse stringified JSON', value: 'parseStringifiedJson' },
{ label: 'Pluralize', value: 'pluralize' }, { label: 'Pluralize', value: 'pluralize' },
{ label: 'Replace', value: 'replace' }, { label: 'Replace', value: 'replace' },
{ label: 'String to Base64', value: 'stringToBase64' }, { label: 'String to Base64', value: 'stringToBase64' },
{ label: 'Encode URI', value: 'encodeUri' },
{ label: 'Trim Whitespace', value: 'trimWhitespace' }, { label: 'Trim Whitespace', value: 'trimWhitespace' },
{ label: 'Use Default Value', value: 'useDefaultValue' }, { label: 'Use Default Value', value: 'useDefaultValue' },
], ],

View File

@@ -1,7 +0,0 @@
import { v4 as uuidv4 } from 'uuid';
const createUuidV4 = () => {
return uuidv4();
};
export default createUuidV4;

View File

@@ -1,7 +0,0 @@
const parseStringifiedJson = ($) => {
const input = $.step.parameters.input;
return JSON.parse(input);
};
export default parseStringifiedJson;

View File

@@ -1,26 +1,8 @@
const replace = ($) => { const replace = ($) => {
const input = $.step.parameters.input; const input = $.step.parameters.input;
const find = $.step.parameters.find; const find = $.step.parameters.find;
const replace = $.step.parameters.replace; const replace = $.step.parameters.replace;
const useRegex = $.step.parameters.useRegex;
if (useRegex) {
const ignoreCase = $.step.parameters.ignoreCase;
const flags = [ignoreCase && 'i', 'g'].filter(Boolean).join('');
const timeoutId = setTimeout(() => {
$.execution.exit();
}, 100);
const regex = new RegExp(find, flags);
const replacedValue = input.replaceAll(regex, replace);
clearTimeout(timeoutId);
return replacedValue;
}
return input.replaceAll(find, replace); return input.replaceAll(find, replace);
}; };

View File

@@ -1,4 +1,3 @@
import listTransformOptions from './list-transform-options/index.js'; import listTransformOptions from './list-transform-options/index.js';
import listReplaceRegexOptions from './list-replace-regex-options/index.js';
export default [listTransformOptions, listReplaceRegexOptions]; export default [listTransformOptions];

View File

@@ -1,23 +0,0 @@
export default {
name: 'List replace regex options',
key: 'listReplaceRegexOptions',
async run($) {
if (!$.step.parameters.useRegex) return [];
return [
{
label: 'Ignore case',
key: 'ignoreCase',
type: 'dropdown',
required: true,
description: 'Ignore case sensitivity.',
variables: true,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
},
];
},
};

View File

@@ -12,7 +12,6 @@ import stringToBase64 from './text/string-to-base64.js';
import encodeUri from './text/encode-uri.js'; import encodeUri from './text/encode-uri.js';
import trimWhitespace from './text/trim-whitespace.js'; import trimWhitespace from './text/trim-whitespace.js';
import useDefaultValue from './text/use-default-value.js'; import useDefaultValue from './text/use-default-value.js';
import parseStringifiedJson from './text/parse-stringified-json.js';
import performMathOperation from './numbers/perform-math-operation.js'; import performMathOperation from './numbers/perform-math-operation.js';
import randomNumber from './numbers/random-number.js'; import randomNumber from './numbers/random-number.js';
import formatNumber from './numbers/format-number.js'; import formatNumber from './numbers/format-number.js';
@@ -39,7 +38,6 @@ const options = {
formatNumber, formatNumber,
formatPhoneNumber, formatPhoneNumber,
formatDateTime, formatDateTime,
parseStringifiedJson,
}; };
export default { export default {

View File

@@ -1,12 +0,0 @@
const useDefaultValue = [
{
label: 'Input',
key: 'input',
type: 'string',
required: true,
description: 'Stringified JSON you want to parse.',
variables: true,
},
];
export default useDefaultValue;

View File

@@ -23,33 +23,6 @@ const replace = [
description: 'Text that will replace the found text.', description: 'Text that will replace the found text.',
variables: true, variables: true,
}, },
{
label: 'Use Regular Expression',
key: 'useRegex',
type: 'dropdown',
required: true,
description: 'Use regex to search values.',
variables: true,
value: false,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
additionalFields: {
type: 'query',
name: 'getDynamicFields',
arguments: [
{
name: 'key',
value: 'listReplaceRegexOptions',
},
{
name: 'parameters.useRegex',
value: '{parameters.useRegex}',
},
],
},
},
]; ];
export default replace; export default replace;

View File

@@ -10,7 +10,7 @@ export default defineApp({
supportsConnections: false, supportsConnections: false,
baseUrl: '', baseUrl: '',
apiBaseUrl: '', apiBaseUrl: '',
primaryColor: '#001F52', primaryColor: '001F52',
actions, actions,
dynamicFields, dynamicFields,
}); });

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: '', apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/ghost/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/ghost/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/ghost/connection', authDocUrl: '{DOCS_URL}/apps/ghost/connection',
primaryColor: '#15171A', primaryColor: '15171A',
supportsConnections: true, supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader], beforeRequest: [setBaseUrl, addAuthHeader],
auth, auth,

View File

@@ -10,7 +10,7 @@ export default defineAction({
label: 'Repo', label: 'Repo',
key: 'repo', key: 'repo',
type: 'dropdown', type: 'dropdown',
required: true, required: false,
variables: true, variables: true,
source: { source: {
type: 'query', type: 'query',

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: 'https://api.github.com', apiBaseUrl: 'https://api.github.com',
iconUrl: '{BASE_URL}/apps/github/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/github/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/github/connection', authDocUrl: '{DOCS_URL}/apps/github/connection',
primaryColor: '#000000', primaryColor: '000000',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: 'https://gitlab.com', apiBaseUrl: 'https://gitlab.com',
iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/gitlab/connection', authDocUrl: '{DOCS_URL}/apps/gitlab/connection',
primaryColor: '#FC6D26', primaryColor: 'FC6D26',
supportsConnections: true, supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader], beforeRequest: [setBaseUrl, addAuthHeader],
auth, auth,

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: 'https://www.googleapis.com/calendar', apiBaseUrl: 'https://www.googleapis.com/calendar',
iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/google-calendar/connection', authDocUrl: '{DOCS_URL}/apps/google-calendar/connection',
primaryColor: '#448AFF', primaryColor: '448AFF',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: 'https://www.googleapis.com/drive', apiBaseUrl: 'https://www.googleapis.com/drive',
iconUrl: '{BASE_URL}/apps/google-drive/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/google-drive/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/google-drive/connection', authDocUrl: '{DOCS_URL}/apps/google-drive/connection',
primaryColor: '#1FA463', primaryColor: '1FA463',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: 'https://forms.googleapis.com', apiBaseUrl: 'https://forms.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/google-forms/connection', authDocUrl: '{DOCS_URL}/apps/google-forms/connection',
primaryColor: '#673AB7', primaryColor: '673AB7',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -1,175 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Find worksheet',
key: 'findWorksheet',
description:
'Finds a worksheet by title. Optionally, create a worksheet if none are found.',
arguments: [
{
label: 'Drive',
key: 'driveId',
type: 'dropdown',
required: false,
description:
'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listDrives',
},
],
},
},
{
label: 'Spreadsheet',
key: 'spreadsheetId',
type: 'dropdown',
required: true,
dependsOn: ['parameters.driveId'],
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSpreadsheets',
},
{
name: 'parameters.driveId',
value: '{parameters.driveId}',
},
],
},
},
{
label: 'Title',
key: 'title',
type: 'string',
required: true,
description:
'The worksheet title needs to match exactly, and the search is case-sensitive.',
variables: true,
},
{
label: 'Create worksheet if none are found.',
key: 'createWorksheet',
type: 'dropdown',
required: false,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
additionalFields: {
type: 'query',
name: 'getDynamicFields',
arguments: [
{
name: 'key',
value: 'listCreateWorksheetFields',
},
{
name: 'parameters.createWorksheet',
value: '{parameters.createWorksheet}',
},
],
},
},
],
async run($) {
const createWorksheet = $.step.parameters.createWorksheet;
async function findWorksheet() {
const {
data: { sheets },
} = await $.http.get(`/v4/spreadsheets/${$.step.parameters.spreadsheetId}`);
const selectedSheet = sheets.find(
(sheet) => sheet.properties.title === $.step.parameters.title
);
return selectedSheet;
}
const selectedSheet = await findWorksheet();
if (selectedSheet) {
$.setActionItem({
raw: selectedSheet,
});
return;
}
if (createWorksheet) {
const headers = $.step.parameters.headers;
const headerValues = headers.map((entry) => entry.header);
const body = {
requests: [
{
addSheet: {
properties: {
title: $.step.parameters.title,
},
},
},
],
};
const { data } = await $.http.post(
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}:batchUpdate`,
body
);
if (headerValues.length) {
const body = {
requests: [
{
updateCells: {
rows: [
{
values: headerValues.map((header) => ({
userEnteredValue: { stringValue: header },
})),
},
],
fields: '*',
start: {
sheetId:
data.replies[data.replies.length - 1].addSheet.properties
.sheetId,
rowIndex: 0,
columnIndex: 0,
},
},
},
],
};
await $.http.post(
`/v4/spreadsheets/${$.step.parameters.spreadsheetId}:batchUpdate`,
body
);
const createdSheet = await findWorksheet();
$.setActionItem({
raw: createdSheet,
});
return;
}
}
$.setActionItem({
raw: null,
});
},
});

View File

@@ -1,11 +1,5 @@
import createSpreadsheet from './create-spreadsheet/index.js'; import createSpreadsheet from './create-spreadsheet/index.js';
import createSpreadsheetRow from './create-spreadsheet-row/index.js'; import createSpreadsheetRow from './create-spreadsheet-row/index.js';
import createWorksheet from './create-worksheet/index.js'; import createWorksheet from './create-worksheet/index.js';
import findWorksheet from './find-worksheet/index.js';
export default [ export default [createSpreadsheet, createSpreadsheetRow, createWorksheet];
createSpreadsheet,
createSpreadsheetRow,
createWorksheet,
findWorksheet,
];

View File

@@ -1,4 +1,3 @@
import listSheetHeaders from './list-sheet-headers/index.js'; import listSheetHeaders from './list-sheet-headers/index.js';
import listCreateWorksheetFields from './list-create-worksheet-fields/index.js';
export default [listSheetHeaders, listCreateWorksheetFields]; export default [listSheetHeaders];

View File

@@ -1,26 +0,0 @@
export default {
name: 'List create worksheet fields',
key: 'listCreateWorksheetFields',
async run($) {
if ($.step.parameters.createWorksheet) {
return [
{
label: 'Headers',
key: 'headers',
type: 'dynamic',
required: false,
fields: [
{
label: 'Header',
key: 'header',
type: 'string',
required: true,
variables: true,
},
],
},
];
}
},
};

View File

@@ -13,7 +13,7 @@ export default defineApp({
apiBaseUrl: 'https://sheets.googleapis.com', apiBaseUrl: 'https://sheets.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-sheets/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/google-sheets/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/google-sheets/connection', authDocUrl: '{DOCS_URL}/apps/google-sheets/connection',
primaryColor: '#0F9D58', primaryColor: '0F9D58',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -12,7 +12,7 @@ export default defineApp({
apiBaseUrl: 'https://tasks.googleapis.com', apiBaseUrl: 'https://tasks.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-tasks/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/google-tasks/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/google-tasks/connection', authDocUrl: '{DOCS_URL}/apps/google-tasks/connection',
primaryColor: '#0066DA', primaryColor: '0066DA',
supportsConnections: true, supportsConnections: true,
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,

View File

@@ -11,7 +11,7 @@ export default defineApp({
apiBaseUrl: 'https://app.tryhelix.ai', apiBaseUrl: 'https://app.tryhelix.ai',
iconUrl: '{BASE_URL}/apps/helix/assets/favicon.svg', iconUrl: '{BASE_URL}/apps/helix/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/helix/connection', authDocUrl: '{DOCS_URL}/apps/helix/connection',
primaryColor: '#000000', primaryColor: '000000',
supportsConnections: true, supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader], beforeRequest: [setBaseUrl, addAuthHeader],
auth, auth,

View File

@@ -145,13 +145,6 @@ export default defineAction({
responseData = Buffer.from(responseData).toString('base64'); responseData = Buffer.from(responseData).toString('base64');
} }
$.setActionItem({ $.setActionItem({ raw: { data: responseData } });
raw: {
data: responseData,
headers: response.headers,
status: response.status,
statusText: response.statusText
}
});
}, },
}); });

Some files were not shown because too many files have changed in this diff Show More