Compare commits
1 Commits
feature/ac
...
feature/do
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6421ec60b7 |
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(find:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(cat:*)",
|
||||
"WebSearch"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
# Test coverage reports (generated)
|
||||
frontend/coverage/
|
||||
|
||||
# IDE files
|
||||
.idea/misc.xml
|
||||
*.imlAGENCY_COST_ESTIMATE.md
|
||||
450
CLAUDE.md
450
CLAUDE.md
@@ -21,169 +21,6 @@
|
||||
|
||||
Note: `lvh.me` resolves to `127.0.0.1` - required for subdomain cookies to work.
|
||||
|
||||
## CRITICAL: Test-Driven Development (TDD) Required
|
||||
|
||||
**All code changes MUST follow TDD.** This is non-negotiable.
|
||||
|
||||
### TDD Workflow
|
||||
|
||||
1. **Write tests FIRST** before writing any implementation code
|
||||
2. **Run tests** to verify they fail (red)
|
||||
3. **Write minimal code** to make tests pass (green)
|
||||
4. **Refactor** while keeping tests green
|
||||
5. **Repeat** for each new feature or bug fix
|
||||
|
||||
### Coverage Requirements
|
||||
|
||||
| Target | Minimum | Goal |
|
||||
|--------|---------|------|
|
||||
| Backend (Django) | **80%** | 100% |
|
||||
| Frontend (React) | **80%** | 100% |
|
||||
|
||||
### Running Tests with Coverage
|
||||
|
||||
**Backend (Django):**
|
||||
```bash
|
||||
cd /home/poduck/Desktop/smoothschedule2/smoothschedule
|
||||
|
||||
# Run all tests with coverage
|
||||
docker compose -f docker-compose.local.yml exec django pytest --cov --cov-report=term-missing
|
||||
|
||||
# Run tests for a specific app
|
||||
docker compose -f docker-compose.local.yml exec django pytest smoothschedule/scheduling/schedule/tests/ --cov=smoothschedule/scheduling/schedule
|
||||
|
||||
# Run a single test file
|
||||
docker compose -f docker-compose.local.yml exec django pytest smoothschedule/path/to/test_file.py -v
|
||||
|
||||
# Run tests matching a pattern
|
||||
docker compose -f docker-compose.local.yml exec django pytest -k "test_create_resource" -v
|
||||
```
|
||||
|
||||
**Frontend (React):**
|
||||
```bash
|
||||
cd /home/poduck/Desktop/smoothschedule2/frontend
|
||||
|
||||
# Run all tests with coverage
|
||||
npm test -- --coverage
|
||||
|
||||
# Run tests in watch mode during development
|
||||
npm test
|
||||
|
||||
# Run a single test file
|
||||
npm test -- src/hooks/__tests__/useResources.test.ts
|
||||
|
||||
# Run tests matching a pattern
|
||||
npm test -- -t "should create resource"
|
||||
```
|
||||
|
||||
### Test File Organization
|
||||
|
||||
**Backend:**
|
||||
```
|
||||
smoothschedule/smoothschedule/{domain}/{app}/
|
||||
├── models.py
|
||||
├── views.py
|
||||
├── serializers.py
|
||||
└── tests/
|
||||
├── __init__.py
|
||||
├── test_models.py # Model unit tests
|
||||
├── test_serializers.py # Serializer tests
|
||||
├── test_views.py # API endpoint tests
|
||||
└── factories.py # Test factories (optional)
|
||||
```
|
||||
|
||||
**Frontend:**
|
||||
```
|
||||
frontend/src/
|
||||
├── hooks/
|
||||
│ ├── useResources.ts
|
||||
│ └── __tests__/
|
||||
│ └── useResources.test.ts
|
||||
├── components/
|
||||
│ ├── MyComponent.tsx
|
||||
│ └── __tests__/
|
||||
│ └── MyComponent.test.tsx
|
||||
└── pages/
|
||||
├── MyPage.tsx
|
||||
└── __tests__/
|
||||
└── MyPage.test.tsx
|
||||
```
|
||||
|
||||
### What to Test
|
||||
|
||||
**Backend:**
|
||||
- Model methods and properties
|
||||
- Model validation (clean methods)
|
||||
- Serializer validation
|
||||
- API endpoints (all HTTP methods)
|
||||
- Permission classes
|
||||
- Custom querysets and managers
|
||||
- Signals
|
||||
- Celery tasks
|
||||
- Utility functions
|
||||
|
||||
**Frontend:**
|
||||
- Custom hooks (state changes, API calls)
|
||||
- Component rendering
|
||||
- User interactions (clicks, form submissions)
|
||||
- Conditional rendering
|
||||
- Error states
|
||||
- Loading states
|
||||
- API client functions
|
||||
|
||||
### TDD Example - Adding a New Feature
|
||||
|
||||
**Step 1: Write the test first**
|
||||
```python
|
||||
# Backend: test_views.py
|
||||
def test_create_resource_with_schedule(self, api_client, tenant):
|
||||
"""New feature: resources can have a default schedule."""
|
||||
data = {
|
||||
"name": "Test Resource",
|
||||
"type": "STAFF",
|
||||
"default_schedule": {
|
||||
"monday": {"start": "09:00", "end": "17:00"},
|
||||
"tuesday": {"start": "09:00", "end": "17:00"},
|
||||
}
|
||||
}
|
||||
response = api_client.post("/api/resources/", data, format="json")
|
||||
assert response.status_code == 201
|
||||
assert response.data["default_schedule"]["monday"]["start"] == "09:00"
|
||||
```
|
||||
|
||||
```typescript
|
||||
// Frontend: useResources.test.ts
|
||||
it('should create resource with schedule', async () => {
|
||||
const { result } = renderHook(() => useCreateResource());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.mutateAsync({
|
||||
name: 'Test Resource',
|
||||
type: 'STAFF',
|
||||
defaultSchedule: { monday: { start: '09:00', end: '17:00' } }
|
||||
});
|
||||
});
|
||||
|
||||
expect(mockApiClient.post).toHaveBeenCalledWith('/resources/', expect.objectContaining({
|
||||
default_schedule: expect.any(Object)
|
||||
}));
|
||||
});
|
||||
```
|
||||
|
||||
**Step 2: Run tests - they should FAIL**
|
||||
|
||||
**Step 3: Write minimal implementation to make tests pass**
|
||||
|
||||
**Step 4: Refactor if needed while keeping tests green**
|
||||
|
||||
### Pre-Commit Checklist
|
||||
|
||||
Before committing ANY code:
|
||||
1. [ ] Tests written BEFORE implementation
|
||||
2. [ ] All tests pass
|
||||
3. [ ] Coverage meets minimum threshold (80%)
|
||||
4. [ ] No skipped or disabled tests without justification
|
||||
|
||||
## CRITICAL: Backend Runs in Docker
|
||||
|
||||
**NEVER run Django commands directly.** Always use Docker Compose:
|
||||
@@ -224,293 +61,14 @@ docker compose -f docker-compose.local.yml exec django python manage.py <command
|
||||
| `frontend/src/api/client.ts` | Axios API client |
|
||||
| `frontend/src/types.ts` | TypeScript interfaces |
|
||||
| `frontend/src/i18n/locales/en.json` | Translations |
|
||||
| `frontend/src/utils/dateUtils.ts` | Date formatting utilities |
|
||||
|
||||
## Timezone Architecture (CRITICAL)
|
||||
## Key Django Apps
|
||||
|
||||
All date/time handling follows this architecture to ensure consistency across timezones.
|
||||
|
||||
### Core Principles
|
||||
|
||||
1. **Database**: All times stored in UTC
|
||||
2. **API Communication**: Always use UTC (both directions)
|
||||
3. **API Responses**: Include `business_timezone` field
|
||||
4. **Frontend Display**: Convert UTC based on `business_timezone`
|
||||
- If `business_timezone` is set → display in that timezone
|
||||
- If `business_timezone` is null/blank → display in user's local timezone
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
FRONTEND (User in Eastern Time selects "Dec 8, 2:00 PM")
|
||||
↓
|
||||
Convert to UTC: "2024-12-08T19:00:00Z"
|
||||
↓
|
||||
Send to API (always UTC)
|
||||
↓
|
||||
DATABASE (stores UTC)
|
||||
↓
|
||||
API RESPONSE:
|
||||
{
|
||||
"start_time": "2024-12-08T19:00:00Z", // Always UTC
|
||||
"business_timezone": "America/Denver" // IANA timezone (or null for local)
|
||||
}
|
||||
↓
|
||||
FRONTEND CONVERTS:
|
||||
- If business_timezone set: UTC → Mountain Time → "Dec 8, 12:00 PM MST"
|
||||
- If business_timezone null: UTC → User local → "Dec 8, 2:00 PM EST"
|
||||
```
|
||||
|
||||
### Frontend Helper Functions
|
||||
|
||||
Located in `frontend/src/utils/dateUtils.ts`:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
toUTC,
|
||||
fromUTC,
|
||||
formatForDisplay,
|
||||
formatDateForDisplay,
|
||||
getDisplayTimezone,
|
||||
} from '../utils/dateUtils';
|
||||
|
||||
// SENDING TO API - Always convert to UTC
|
||||
const apiPayload = {
|
||||
start_time: toUTC(selectedDateTime), // "2024-12-08T19:00:00Z"
|
||||
};
|
||||
|
||||
// RECEIVING FROM API - Convert for display
|
||||
const displayTime = formatForDisplay(
|
||||
response.start_time, // UTC from API
|
||||
response.business_timezone // "America/Denver" or null
|
||||
);
|
||||
// Result: "Dec 8, 2024 12:00 PM" (in business or local timezone)
|
||||
|
||||
// DATE-ONLY fields (time blocks)
|
||||
const displayDate = formatDateForDisplay(
|
||||
response.start_date,
|
||||
response.business_timezone
|
||||
);
|
||||
```
|
||||
|
||||
### API Response Requirements
|
||||
|
||||
All endpoints returning date/time data MUST include:
|
||||
|
||||
```python
|
||||
# In serializers or views
|
||||
{
|
||||
"start_time": "2024-12-08T19:00:00Z",
|
||||
"business_timezone": business.timezone, # "America/Denver" or None
|
||||
}
|
||||
```
|
||||
|
||||
### Backend Serializer Mixin
|
||||
|
||||
Use `TimezoneSerializerMixin` from `core/mixins.py` to automatically add the timezone field:
|
||||
|
||||
```python
|
||||
from core.mixins import TimezoneSerializerMixin
|
||||
|
||||
class EventSerializer(TimezoneSerializerMixin, serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = [
|
||||
'id', 'start_time', 'end_time',
|
||||
# ... other fields ...
|
||||
'business_timezone', # Provided by mixin
|
||||
]
|
||||
read_only_fields = ['business_timezone']
|
||||
```
|
||||
|
||||
The mixin automatically retrieves the timezone from the tenant context.
|
||||
- Returns the IANA timezone string if set (e.g., "America/Denver")
|
||||
- Returns `null` if not set (frontend uses user's local timezone)
|
||||
|
||||
### Common Mistakes to Avoid
|
||||
|
||||
```typescript
|
||||
// BAD - Uses browser local time, not UTC
|
||||
date.toISOString().split('T')[0]
|
||||
|
||||
// BAD - Doesn't respect business timezone setting
|
||||
new Date(utcString).toLocaleString()
|
||||
|
||||
// GOOD - Use helper functions
|
||||
toUTC(date) // For API requests
|
||||
formatForDisplay(utcString, businessTimezone) // For displaying
|
||||
```
|
||||
|
||||
## Django App Organization (Domain-Based)
|
||||
|
||||
Apps are organized into domain packages under `smoothschedule/smoothschedule/`:
|
||||
|
||||
### Identity Domain
|
||||
| App | Location | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `core` | `identity/core/` | Tenant, Domain, PermissionGrant, middleware, mixins |
|
||||
| `users` | `identity/users/` | User model, authentication, MFA |
|
||||
|
||||
### Scheduling Domain
|
||||
| App | Location | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `schedule` | `scheduling/schedule/` | Resources, Events, Services, Participants |
|
||||
| `contracts` | `scheduling/contracts/` | Contract/e-signature system |
|
||||
| `analytics` | `scheduling/analytics/` | Business analytics and reporting |
|
||||
|
||||
### Communication Domain
|
||||
| App | Location | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `notifications` | `communication/notifications/` | Notification system |
|
||||
| `credits` | `communication/credits/` | SMS/calling credits |
|
||||
| `mobile` | `communication/mobile/` | Field employee mobile app |
|
||||
| `messaging` | `communication/messaging/` | Email templates and messaging |
|
||||
|
||||
### Commerce Domain
|
||||
| App | Location | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `payments` | `commerce/payments/` | Stripe Connect payments bridge |
|
||||
| `tickets` | `commerce/tickets/` | Support ticket system |
|
||||
|
||||
### Platform Domain
|
||||
| App | Location | Purpose |
|
||||
|-----|----------|---------|
|
||||
| `admin` | `platform/admin/` | Platform administration, subscriptions |
|
||||
| `api` | `platform/api/` | Public API v1 for third-party integrations |
|
||||
|
||||
## Core Mixins & Base Classes
|
||||
|
||||
Located in `smoothschedule/smoothschedule/identity/core/mixins.py`. Use these to avoid code duplication.
|
||||
|
||||
### Permission Classes
|
||||
|
||||
```python
|
||||
from smoothschedule.identity.core.mixins import DenyStaffWritePermission, DenyStaffAllAccessPermission, DenyStaffListPermission
|
||||
|
||||
class MyViewSet(ModelViewSet):
|
||||
# Block write operations for staff (GET allowed)
|
||||
permission_classes = [IsAuthenticated, DenyStaffWritePermission]
|
||||
|
||||
# Block ALL operations for staff
|
||||
permission_classes = [IsAuthenticated, DenyStaffAllAccessPermission]
|
||||
|
||||
# Block list/create/update/delete but allow retrieve
|
||||
permission_classes = [IsAuthenticated, DenyStaffListPermission]
|
||||
```
|
||||
|
||||
#### Per-User Permission Overrides
|
||||
|
||||
Staff permissions can be overridden on a per-user basis using the `user.permissions` JSONField.
|
||||
Permission keys are auto-derived from the view's basename or model name:
|
||||
|
||||
| Permission Class | Auto-derived Key | Example |
|
||||
|-----------------|------------------|---------|
|
||||
| `DenyStaffWritePermission` | `can_write_{basename}` | `can_write_resources` |
|
||||
| `DenyStaffAllAccessPermission` | `can_access_{basename}` | `can_access_services` |
|
||||
| `DenyStaffListPermission` | `can_list_{basename}` or `can_access_{basename}` | `can_list_customers` |
|
||||
|
||||
**Current ViewSet permission keys:**
|
||||
|
||||
| ViewSet | Permission Class | Override Key |
|
||||
|---------|-----------------|--------------|
|
||||
| `ResourceViewSet` | `DenyStaffAllAccessPermission` | `can_access_resources` |
|
||||
| `ServiceViewSet` | `DenyStaffAllAccessPermission` | `can_access_services` |
|
||||
| `CustomerViewSet` | `DenyStaffListPermission` | `can_list_customers` or `can_access_customers` |
|
||||
| `ScheduledTaskViewSet` | `DenyStaffAllAccessPermission` | `can_access_scheduled-tasks` |
|
||||
|
||||
**Granting a specific staff member access:**
|
||||
```bash
|
||||
# Open Django shell
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py shell
|
||||
```
|
||||
|
||||
```python
|
||||
from smoothschedule.identity.users.models import User
|
||||
|
||||
# Find the staff member
|
||||
staff = User.objects.get(email='john@example.com')
|
||||
|
||||
# Grant read access to resources
|
||||
staff.permissions['can_access_resources'] = True
|
||||
staff.save()
|
||||
|
||||
# Or grant list access to customers (but not full CRUD)
|
||||
staff.permissions['can_list_customers'] = True
|
||||
staff.save()
|
||||
```
|
||||
|
||||
**Custom permission keys (optional):**
|
||||
```python
|
||||
class ResourceViewSet(ModelViewSet):
|
||||
permission_classes = [IsAuthenticated, DenyStaffAllAccessPermission]
|
||||
# Override the auto-derived key
|
||||
staff_access_permission_key = 'can_manage_equipment'
|
||||
```
|
||||
|
||||
Then grant via: `staff.permissions['can_manage_equipment'] = True`
|
||||
|
||||
### QuerySet Mixins
|
||||
|
||||
```python
|
||||
from smoothschedule.identity.core.mixins import TenantFilteredQuerySetMixin, UserTenantFilteredMixin
|
||||
|
||||
# For tenant-scoped models (automatic django-tenants filtering)
|
||||
class ResourceViewSet(TenantFilteredQuerySetMixin, ModelViewSet):
|
||||
queryset = Resource.objects.all()
|
||||
deny_staff_queryset = True # Optional: also filter staff at queryset level
|
||||
|
||||
def filter_queryset_for_tenant(self, queryset):
|
||||
# Override for custom filtering
|
||||
return queryset.filter(is_active=True)
|
||||
|
||||
# For User model (shared schema, needs explicit tenant filter)
|
||||
class CustomerViewSet(UserTenantFilteredMixin, ModelViewSet):
|
||||
queryset = User.objects.filter(role=User.Role.CUSTOMER)
|
||||
```
|
||||
|
||||
### Feature Permission Mixins
|
||||
|
||||
```python
|
||||
from smoothschedule.identity.core.mixins import PluginFeatureRequiredMixin, TaskFeatureRequiredMixin
|
||||
|
||||
# Checks can_use_plugins feature on list/retrieve/create
|
||||
class PluginViewSet(PluginFeatureRequiredMixin, ModelViewSet):
|
||||
pass
|
||||
|
||||
# Checks both can_use_plugins AND can_use_tasks
|
||||
class ScheduledTaskViewSet(TaskFeatureRequiredMixin, TenantFilteredQuerySetMixin, ModelViewSet):
|
||||
pass
|
||||
```
|
||||
|
||||
### Base API Views (for non-ViewSet views)
|
||||
|
||||
```python
|
||||
from rest_framework.views import APIView
|
||||
from smoothschedule.identity.core.mixins import TenantAPIView, TenantRequiredAPIView
|
||||
|
||||
# Optional tenant - use self.get_tenant()
|
||||
class MyView(TenantAPIView, APIView):
|
||||
def get(self, request):
|
||||
tenant = self.get_tenant() # May be None
|
||||
return self.success_response({'data': 'value'})
|
||||
# or: return self.error_response('Something went wrong', status_code=400)
|
||||
|
||||
# Required tenant - self.tenant always available
|
||||
class MyTenantView(TenantRequiredAPIView, APIView):
|
||||
def get(self, request):
|
||||
# self.tenant is guaranteed to exist (returns 400 if missing)
|
||||
return Response({'name': self.tenant.name})
|
||||
```
|
||||
|
||||
### Helper Methods Available
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `self.get_tenant()` | Get tenant from request (may be None) |
|
||||
| `self.get_tenant_or_error()` | Returns (tenant, error_response) tuple |
|
||||
| `self.error_response(msg, status_code)` | Standard error response |
|
||||
| `self.success_response(data, status_code)` | Standard success response |
|
||||
| `self.check_feature(key, name)` | Check feature permission, returns error or None |
|
||||
| `schedule` | `smoothschedule/smoothschedule/schedule/` | Resources, Events, Services |
|
||||
| `users` | `smoothschedule/smoothschedule/users/` | Authentication, User model |
|
||||
| `tenants` | `smoothschedule/smoothschedule/tenants/` | Multi-tenancy (Business model) |
|
||||
|
||||
## Common Tasks
|
||||
|
||||
|
||||
56
ESTIMATE.md
56
ESTIMATE.md
@@ -1,56 +0,0 @@
|
||||
### **Project Estimate: SmoothSchedule Platform Development**
|
||||
|
||||
**Date:** December 16, 2025
|
||||
**Prepared For:** Internal & External Stakeholders
|
||||
**Prepared By:** Gemini AI Software Engineering Agent
|
||||
|
||||
---
|
||||
|
||||
#### **1. Executive Summary**
|
||||
|
||||
This document provides a high-level cost and timeline estimate for the from-scratch development of the SmoothSchedule platform. Our analysis of the existing codebase reveals that SmoothSchedule is not merely a scheduling application, but a sophisticated, multi-tenant Software-as-a-Service (SaaS) platform with enterprise-grade features for e-commerce, extensive customization, and developer-level extensibility.
|
||||
|
||||
The architecture includes several high-complexity components, most notably a **sandboxed custom scripting engine** for user-defined automations and a **full data-isolation sandbox mode** for testing. These features place the project in a category of complexity comparable to building a platform-as-a-service (PaaS).
|
||||
|
||||
* **Total Estimated Project Cost:** **$3,500,000 - $5,500,000 USD**
|
||||
* **Estimated Timeline:** **18 - 24 months**
|
||||
|
||||
---
|
||||
|
||||
#### **2. Project Scope & Complexity Analysis**
|
||||
|
||||
This estimate is based on the implementation of the following key features and architectural pillars identified in the codebase:
|
||||
|
||||
* **Multi-Tenant SaaS Architecture:** The system is designed to serve multiple businesses (tenants) from a single infrastructure, with complete data separation.
|
||||
* **Custom Python Scripting Engine:** The platform's most complex feature is its ability to safely execute custom, user-written Python code in a sandboxed environment. This allows for limitless business automation, similar to Zapier or Salesforce Apex, and requires significant investment in security and resource management.
|
||||
* **Full Data-Isolation Sandbox Mode:** A complete "Test Mode" for each tenant, which uses a separate, isolated database schema. This allows users to safely test workflows and automations without affecting their live business data—a feature typical of mature, enterprise-grade platforms.
|
||||
* **Extensible Automation & Plugin Framework:** A comprehensive system for creating, installing, and managing "plugins" (automations). These can be triggered by schedules (e.g., cron jobs) or application events (e.g., when an appointment is completed), and are managed via a built-in marketplace.
|
||||
* **Visual Page Builder:** A drag-and-drop interface (identified as using `@measured/puck`) that allows tenants to build their own public-facing websites and booking pages.
|
||||
* **Advanced E-commerce Platform:** Integration with Stripe Connect, enabling tenants to bill their own customers, not just for the platform to bill its tenants. This requires complex logic for managed accounts, payment flows, and fee processing.
|
||||
* **Real-time Capabilities & Asynchronous Tasks:** The platform uses WebSockets (`django-channels`) for live updates and a Celery-based queue for handling background jobs like sending emails, generating reports, and running automations.
|
||||
* **Mobile Application:** A companion field application for iOS and Android that integrates with the full feature set of the backend.
|
||||
|
||||
---
|
||||
|
||||
#### **3. Cost Estimate Breakdown**
|
||||
|
||||
This estimate assumes a US-based software development agency model, including project management, design, development, and quality assurance.
|
||||
|
||||
| Category | Description | Estimated Cost Range |
|
||||
| :---------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------ |
|
||||
| **Backend Development** | (Python/Django) Includes multi-tenancy, database architecture, REST APIs, and the highly complex scripting engine & sandbox mode. | $1,500,000 - $2,200,000 |
|
||||
| **Frontend Development** | (React/TypeScript) Includes the primary web application, visual page builder, custom dashboards, and UIs for the automation/scripting engine. | $700,000 - $1,100,000 |
|
||||
| **Mobile App Development** | (iOS/Android) Native or cross-platform development of the companion field application. | $350,000 - $550,000 |
|
||||
| **UI/UX Design** | Wireframing, prototyping, and high-fidelity design for the web and mobile applications, ensuring a polished and intuitive user experience. | $250,000 - $400,000 |
|
||||
| **Project Management & QA** | Management oversight, sprint planning, manual and automated testing, and release coordination across all development tracks. | $550,000 - $900,000 |
|
||||
| **Third-Party Security Audit** | Essential for a platform that executes custom code. Includes penetration testing and code review by an external security firm. | $100,000 - $350,000 |
|
||||
| **Total Estimated Cost** | | **$3,500,000 - $5,500,000** |
|
||||
|
||||
---
|
||||
|
||||
#### **4. Assumptions & Disclaimer**
|
||||
|
||||
* This estimate is based on a feature set inferred from a comprehensive analysis of the provided codebase.
|
||||
* The costs are calculated using a blended agency rate typical for senior-level engineering talent in the United States. Rates and timelines may vary based on team location and composition.
|
||||
* This document is a high-level estimate intended for budgetary and planning purposes only. It is **not** a fixed-price quote. A formal proposal would require a detailed discovery and specification phase.
|
||||
* This estimate covers initial development and deployment. It does **not** include ongoing operational costs such as hosting, third-party service fees (e.g., Stripe, Twilio), marketing, or post-launch maintenance.
|
||||
@@ -1,383 +0,0 @@
|
||||
# Django App Reorganization Plan - Option C (Domain-Based)
|
||||
|
||||
## Overview
|
||||
|
||||
Reorganize Django apps from their current scattered locations into a clean domain-based structure within `smoothschedule/smoothschedule/`.
|
||||
|
||||
**Branch:** `refactor/organize-django-apps`
|
||||
**Risk Level:** Medium-High (migration history must be preserved)
|
||||
**Estimated Parallel Agents:** 6-8
|
||||
|
||||
---
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Current App Locations (Inconsistent)
|
||||
|
||||
| App | Current Location | Registered As |
|
||||
|-----|-----------------|---------------|
|
||||
| core | `smoothschedule/core/` | `"core"` |
|
||||
| schedule | `smoothschedule/schedule/` | `"schedule"` |
|
||||
| payments | `smoothschedule/payments/` | `"payments"` |
|
||||
| platform_admin | `smoothschedule/platform_admin/` | `"platform_admin.apps.PlatformAdminConfig"` |
|
||||
| analytics | `smoothschedule/analytics/` | `"analytics"` |
|
||||
| notifications | `smoothschedule/notifications/` | `"notifications"` |
|
||||
| tickets | `smoothschedule/tickets/` | `"tickets"` |
|
||||
| contracts | `smoothschedule/contracts/` | **NOT REGISTERED** |
|
||||
| communication | `smoothschedule/communication/` | **NOT REGISTERED** |
|
||||
| users | `smoothschedule/smoothschedule/users/` | `"smoothschedule.users"` |
|
||||
| comms_credits | `smoothschedule/smoothschedule/comms_credits/` | `"smoothschedule.comms_credits"` |
|
||||
| field_mobile | `smoothschedule/smoothschedule/field_mobile/` | `"smoothschedule.field_mobile"` |
|
||||
| public_api | `smoothschedule/smoothschedule/public_api/` | `"smoothschedule.public_api"` |
|
||||
|
||||
### Migration Counts by App
|
||||
|
||||
| App | Migrations | Complexity |
|
||||
|-----|------------|------------|
|
||||
| core | 22 | High (Tenant model) |
|
||||
| schedule | 30 | High (main business logic) |
|
||||
| payments | 1 | Low |
|
||||
| platform_admin | 12 | Medium |
|
||||
| users | 10 | Medium |
|
||||
| tickets | 13 | Medium |
|
||||
| contracts | 1 | Low |
|
||||
| notifications | 1 | Low |
|
||||
| comms_credits | 2 | Low |
|
||||
| field_mobile | 1 | Low |
|
||||
| public_api | 3 | Low |
|
||||
| analytics | 0 | None |
|
||||
| communication | 1 | Low |
|
||||
|
||||
---
|
||||
|
||||
## Target Structure (Option C - Domain-Based)
|
||||
|
||||
```
|
||||
smoothschedule/smoothschedule/
|
||||
├── __init__.py
|
||||
│
|
||||
├── identity/ # User & Tenant Management
|
||||
│ ├── __init__.py
|
||||
│ ├── core/ # Multi-tenancy, permissions, OAuth
|
||||
│ │ └── (moved from smoothschedule/core/)
|
||||
│ └── users/ # User model, auth, invitations
|
||||
│ └── (keep at current location, just move parent)
|
||||
│
|
||||
├── scheduling/ # Core Business Logic
|
||||
│ ├── __init__.py
|
||||
│ ├── schedule/ # Resources, Events, Services, Plugins
|
||||
│ │ └── (moved from smoothschedule/schedule/)
|
||||
│ ├── contracts/ # E-signatures, legal documents
|
||||
│ │ └── (moved from smoothschedule/contracts/)
|
||||
│ └── analytics/ # Reporting, dashboards
|
||||
│ └── (moved from smoothschedule/analytics/)
|
||||
│
|
||||
├── communication/ # Messaging & Notifications
|
||||
│ ├── __init__.py
|
||||
│ ├── notifications/ # In-app notifications
|
||||
│ │ └── (moved from smoothschedule/notifications/)
|
||||
│ ├── credits/ # SMS/voice credits (renamed from comms_credits)
|
||||
│ │ └── (moved from smoothschedule/smoothschedule/comms_credits/)
|
||||
│ ├── mobile/ # Field employee app (renamed from field_mobile)
|
||||
│ │ └── (moved from smoothschedule/smoothschedule/field_mobile/)
|
||||
│ └── messaging/ # Twilio conversations (renamed from communication)
|
||||
│ └── (moved from smoothschedule/communication/)
|
||||
│
|
||||
├── commerce/ # Payments & Support
|
||||
│ ├── __init__.py
|
||||
│ ├── payments/ # Stripe Connect, transactions
|
||||
│ │ └── (moved from smoothschedule/payments/)
|
||||
│ └── tickets/ # Support tickets, email integration
|
||||
│ └── (moved from smoothschedule/tickets/)
|
||||
│
|
||||
└── platform/ # Platform Administration
|
||||
├── __init__.py
|
||||
├── admin/ # Platform settings, subscriptions (renamed)
|
||||
│ └── (moved from smoothschedule/platform_admin/)
|
||||
└── api/ # Public API v1 (renamed from public_api)
|
||||
└── (moved from smoothschedule/smoothschedule/public_api/)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Critical Constraints
|
||||
|
||||
### 1. Migration History Preservation
|
||||
|
||||
Django migrations contain the app label in their `dependencies` and `app_label` references. We MUST:
|
||||
|
||||
- **Keep `app_label` unchanged** in each app's `Meta` class
|
||||
- Update `AppConfig.name` to the new dotted path
|
||||
- Django will use the `app_label` (not the path) for migration tracking
|
||||
|
||||
### 2. Foreign Key String References
|
||||
|
||||
Models use string references like `'users.User'` and `'core.Tenant'`. These reference `app_label`, not the module path, so they remain valid.
|
||||
|
||||
### 3. Import Path Updates
|
||||
|
||||
All imports across the codebase must be updated:
|
||||
- `from core.models import Tenant` → `from smoothschedule.identity.core.models import Tenant`
|
||||
- `from schedule.models import Event` → `from smoothschedule.scheduling.schedule.models import Event`
|
||||
|
||||
### 4. URL Configuration
|
||||
|
||||
`config/urls.py` imports views directly - all import paths must be updated.
|
||||
|
||||
### 5. Settings Files
|
||||
|
||||
- `config/settings/base.py` - `LOCAL_APPS`
|
||||
- `config/settings/multitenancy.py` - `SHARED_APPS`, `TENANT_APPS`
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Preparation (Serial)
|
||||
|
||||
**Agent 1: Setup & Verification**
|
||||
1. Create all domain package directories with `__init__.py` files
|
||||
2. Verify Docker is running and database is accessible
|
||||
3. Run existing tests to establish baseline
|
||||
4. Create backup of current migration state
|
||||
|
||||
```bash
|
||||
# Create domain packages
|
||||
mkdir -p smoothschedule/smoothschedule/identity
|
||||
mkdir -p smoothschedule/smoothschedule/scheduling
|
||||
mkdir -p smoothschedule/smoothschedule/communication
|
||||
mkdir -p smoothschedule/smoothschedule/commerce
|
||||
mkdir -p smoothschedule/smoothschedule/platform
|
||||
|
||||
# Create __init__.py files
|
||||
touch smoothschedule/smoothschedule/identity/__init__.py
|
||||
touch smoothschedule/smoothschedule/scheduling/__init__.py
|
||||
touch smoothschedule/smoothschedule/communication/__init__.py
|
||||
touch smoothschedule/smoothschedule/commerce/__init__.py
|
||||
touch smoothschedule/smoothschedule/platform/__init__.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Move Apps (Parallel - 5 Agents)
|
||||
|
||||
Each agent handles one domain. For each app move:
|
||||
|
||||
1. **Move directory** to new location
|
||||
2. **Update `apps.py`** - change `name` to new dotted path, keep `label` same
|
||||
3. **Update internal imports** within the app
|
||||
4. **Add explicit `app_label`** to all model Meta classes (if not present)
|
||||
|
||||
#### Agent 2: Identity Domain
|
||||
Move and update:
|
||||
- `smoothschedule/core/` → `smoothschedule/smoothschedule/identity/core/`
|
||||
- `smoothschedule/smoothschedule/users/` → `smoothschedule/smoothschedule/identity/users/`
|
||||
|
||||
**apps.py changes:**
|
||||
```python
|
||||
# identity/core/apps.py
|
||||
class CoreConfig(AppConfig):
|
||||
name = "smoothschedule.identity.core" # NEW
|
||||
label = "core" # KEEP SAME
|
||||
verbose_name = "Core"
|
||||
|
||||
# identity/users/apps.py
|
||||
class UsersConfig(AppConfig):
|
||||
name = "smoothschedule.identity.users" # NEW
|
||||
label = "users" # KEEP SAME
|
||||
```
|
||||
|
||||
#### Agent 3: Scheduling Domain
|
||||
Move and update:
|
||||
- `smoothschedule/schedule/` → `smoothschedule/smoothschedule/scheduling/schedule/`
|
||||
- `smoothschedule/contracts/` → `smoothschedule/smoothschedule/scheduling/contracts/`
|
||||
- `smoothschedule/analytics/` → `smoothschedule/smoothschedule/scheduling/analytics/`
|
||||
|
||||
#### Agent 4: Communication Domain
|
||||
Move and update:
|
||||
- `smoothschedule/notifications/` → `smoothschedule/smoothschedule/communication/notifications/`
|
||||
- `smoothschedule/smoothschedule/comms_credits/` → `smoothschedule/smoothschedule/communication/credits/`
|
||||
- `smoothschedule/smoothschedule/field_mobile/` → `smoothschedule/smoothschedule/communication/mobile/`
|
||||
- `smoothschedule/communication/` → `smoothschedule/smoothschedule/communication/messaging/`
|
||||
|
||||
**Note:** Rename apps for clarity:
|
||||
- `comms_credits` label stays same, path changes
|
||||
- `field_mobile` label stays same, path changes
|
||||
- `communication` label stays same, path changes
|
||||
|
||||
#### Agent 5: Commerce Domain
|
||||
Move and update:
|
||||
- `smoothschedule/payments/` → `smoothschedule/smoothschedule/commerce/payments/`
|
||||
- `smoothschedule/tickets/` → `smoothschedule/smoothschedule/commerce/tickets/`
|
||||
|
||||
#### Agent 6: Platform Domain
|
||||
Move and update:
|
||||
- `smoothschedule/platform_admin/` → `smoothschedule/smoothschedule/platform/admin/`
|
||||
- `smoothschedule/smoothschedule/public_api/` → `smoothschedule/smoothschedule/platform/api/`
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Update Settings (Serial)
|
||||
|
||||
**Agent 7: Settings Configuration**
|
||||
|
||||
Update `config/settings/base.py`:
|
||||
```python
|
||||
LOCAL_APPS = [
|
||||
# Identity
|
||||
"smoothschedule.identity.users",
|
||||
"smoothschedule.identity.core",
|
||||
|
||||
# Scheduling
|
||||
"smoothschedule.scheduling.schedule",
|
||||
"smoothschedule.scheduling.contracts",
|
||||
"smoothschedule.scheduling.analytics",
|
||||
|
||||
# Communication
|
||||
"smoothschedule.communication.notifications",
|
||||
"smoothschedule.communication.credits",
|
||||
"smoothschedule.communication.mobile",
|
||||
"smoothschedule.communication.messaging",
|
||||
|
||||
# Commerce
|
||||
"smoothschedule.commerce.payments",
|
||||
"smoothschedule.commerce.tickets",
|
||||
|
||||
# Platform
|
||||
"smoothschedule.platform.admin",
|
||||
"smoothschedule.platform.api",
|
||||
]
|
||||
```
|
||||
|
||||
Update `config/settings/multitenancy.py`:
|
||||
```python
|
||||
SHARED_APPS = [
|
||||
'django_tenants',
|
||||
'smoothschedule.identity.core',
|
||||
'smoothschedule.platform.admin',
|
||||
# ... rest of shared apps with new paths
|
||||
]
|
||||
|
||||
TENANT_APPS = [
|
||||
'django.contrib.contenttypes',
|
||||
'smoothschedule.scheduling.schedule',
|
||||
'smoothschedule.commerce.payments',
|
||||
'smoothschedule.scheduling.contracts',
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Update All Import Paths (Parallel - Multiple Agents)
|
||||
|
||||
**This is the largest task.** Each agent handles specific import patterns:
|
||||
|
||||
#### Agent 8: Core Imports
|
||||
Find and replace across entire codebase:
|
||||
- `from core.models import` → `from smoothschedule.identity.core.models import`
|
||||
- `from core.` → `from smoothschedule.identity.core.`
|
||||
- `import core` → `import smoothschedule.identity.core as core`
|
||||
|
||||
#### Agent 9: Schedule Imports
|
||||
- `from schedule.models import` → `from smoothschedule.scheduling.schedule.models import`
|
||||
- `from schedule.` → `from smoothschedule.scheduling.schedule.`
|
||||
|
||||
#### Agent 10: Users/Auth Imports
|
||||
- `from smoothschedule.users.` → `from smoothschedule.identity.users.`
|
||||
- `from users.` → `from smoothschedule.identity.users.`
|
||||
|
||||
#### Agent 11: Other App Imports
|
||||
Handle remaining apps:
|
||||
- payments, tickets, notifications, contracts, analytics
|
||||
- platform_admin, public_api, comms_credits, field_mobile, communication
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: URL Configuration Updates (Serial)
|
||||
|
||||
**Agent 12: URL Updates**
|
||||
|
||||
Update `config/urls.py` with new import paths:
|
||||
```python
|
||||
# Old
|
||||
from schedule.views import ResourceViewSet, EventViewSet
|
||||
from core.api_views import business_current
|
||||
|
||||
# New
|
||||
from smoothschedule.scheduling.schedule.views import ResourceViewSet, EventViewSet
|
||||
from smoothschedule.identity.core.api_views import business_current
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: Cleanup & Verification (Serial)
|
||||
|
||||
**Agent 13: Cleanup**
|
||||
1. Remove old empty directories at top level
|
||||
2. Remove deprecated `smoothschedule/smoothschedule/schedule/` directory
|
||||
3. Update `CLAUDE.md` documentation
|
||||
4. Update any remaining references
|
||||
|
||||
**Agent 14: Verification**
|
||||
1. Run `docker compose exec django python manage.py check`
|
||||
2. Run `docker compose exec django python manage.py makemigrations --check`
|
||||
3. Run `docker compose exec django python manage.py migrate --check`
|
||||
4. Run test suite
|
||||
5. Manual smoke test of key endpoints
|
||||
|
||||
---
|
||||
|
||||
## App Label Mapping Reference
|
||||
|
||||
| Old Import Path | New Import Path | app_label (unchanged) |
|
||||
|----------------|-----------------|----------------------|
|
||||
| `core` | `smoothschedule.identity.core` | `core` |
|
||||
| `smoothschedule.users` | `smoothschedule.identity.users` | `users` |
|
||||
| `schedule` | `smoothschedule.scheduling.schedule` | `schedule` |
|
||||
| `contracts` | `smoothschedule.scheduling.contracts` | `contracts` |
|
||||
| `analytics` | `smoothschedule.scheduling.analytics` | `analytics` |
|
||||
| `notifications` | `smoothschedule.communication.notifications` | `notifications` |
|
||||
| `smoothschedule.comms_credits` | `smoothschedule.communication.credits` | `comms_credits` |
|
||||
| `smoothschedule.field_mobile` | `smoothschedule.communication.mobile` | `field_mobile` |
|
||||
| `communication` | `smoothschedule.communication.messaging` | `communication` |
|
||||
| `payments` | `smoothschedule.commerce.payments` | `payments` |
|
||||
| `tickets` | `smoothschedule.commerce.tickets` | `tickets` |
|
||||
| `platform_admin` | `smoothschedule.platform.admin` | `platform_admin` |
|
||||
| `smoothschedule.public_api` | `smoothschedule.platform.api` | `public_api` |
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If issues are encountered:
|
||||
|
||||
1. **Git Reset:** `git checkout main` and delete branch
|
||||
2. **Database:** No migration changes, database remains intact
|
||||
3. **Docker:** Rebuild containers if needed
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] All apps moved to domain-based structure
|
||||
- [ ] `python manage.py check` passes
|
||||
- [ ] `python manage.py makemigrations --check` shows no changes
|
||||
- [ ] All existing tests pass
|
||||
- [ ] Frontend can communicate with API
|
||||
- [ ] Mobile app can communicate with API
|
||||
- [ ] CLAUDE.md updated with new structure
|
||||
|
||||
---
|
||||
|
||||
## Execution Order
|
||||
|
||||
```
|
||||
Phase 1 (Serial): Agent 1 - Setup
|
||||
Phase 2 (Parallel): Agents 2-6 - Move apps by domain
|
||||
Phase 3 (Serial): Agent 7 - Update settings
|
||||
Phase 4 (Parallel): Agents 8-11 - Update imports
|
||||
Phase 5 (Serial): Agent 12 - URL updates
|
||||
Phase 6 (Serial): Agents 13-14 - Cleanup & verify
|
||||
```
|
||||
|
||||
**Total Agents:** 14 (8 can run in parallel at peak)
|
||||
621
README.md
621
README.md
@@ -1,470 +1,257 @@
|
||||
# SmoothSchedule - Multi-Tenant Scheduling Platform
|
||||
|
||||
A production-ready multi-tenant SaaS platform for resource scheduling, appointments, and business management.
|
||||
A production-ready multi-tenant SaaS platform for resource scheduling and orchestration.
|
||||
|
||||
## Features
|
||||
## 🎯 Features
|
||||
|
||||
- **Multi-Tenancy**: PostgreSQL schema-per-tenant using django-tenants
|
||||
- **8-Tier Role Hierarchy**: SUPERUSER, PLATFORM_MANAGER, PLATFORM_SALES, PLATFORM_SUPPORT, TENANT_OWNER, TENANT_MANAGER, TENANT_STAFF, CUSTOMER
|
||||
- **Modern Stack**: Django 5.2 + React 19 + TypeScript + Vite
|
||||
- **Real-time Updates**: Django Channels + WebSockets
|
||||
- **Background Tasks**: Celery + Redis
|
||||
- **Auto SSL**: Let's Encrypt certificates via Traefik
|
||||
- **Cloud Storage**: DigitalOcean Spaces (S3-compatible)
|
||||
- **Docker Ready**: Complete Docker Compose setup for dev and production
|
||||
- ✅ **Multi-Tenancy**: PostgreSQL schema-per-tenant using django-tenants
|
||||
- ✅ **8-Tier Role Hierarchy**: From SUPERUSER to CUSTOMER with strict permissions
|
||||
- ✅ **Modern Stack**: Django 5.2 + React 18 + Vite
|
||||
- ✅ **Docker Ready**: Complete production & development Docker Compose setup
|
||||
- ✅ **Cloud Storage**: DigitalOcean Spaces (S3-compatible) for static/media files
|
||||
- ✅ **Auto SSL**: Let's Encrypt certificates via Traefik reverse proxy
|
||||
- ✅ **Task Queue**: Celery + Redis for background jobs
|
||||
- ✅ **Real-time**: Django Channels + WebSockets support
|
||||
- ✅ **Production Ready**: Fully configured for deployment
|
||||
|
||||
## Project Structure
|
||||
## 📚 Documentation
|
||||
|
||||
```
|
||||
smoothschedule2/
|
||||
├── frontend/ # React + Vite + TypeScript
|
||||
│ ├── src/
|
||||
│ │ ├── api/ # API client and hooks
|
||||
│ │ ├── components/ # Reusable UI components
|
||||
│ │ ├── hooks/ # React Query hooks
|
||||
│ │ ├── pages/ # Page components
|
||||
│ │ └── types.ts # TypeScript interfaces
|
||||
│ ├── nginx.conf # Production nginx config
|
||||
│ └── Dockerfile.prod # Production frontend container
|
||||
│
|
||||
├── smoothschedule/ # Django backend
|
||||
│ ├── config/ # Django settings
|
||||
│ │ └── settings/
|
||||
│ │ ├── base.py # Base settings
|
||||
│ │ ├── local.py # Local development
|
||||
│ │ └── production.py # Production settings
|
||||
│ ├── smoothschedule/ # Django apps (domain-based)
|
||||
│ │ ├── identity/ # Users, tenants, authentication
|
||||
│ │ │ ├── core/ # Tenant, Domain, middleware
|
||||
│ │ │ └── users/ # User model, MFA, auth
|
||||
│ │ ├── scheduling/ # Core scheduling
|
||||
│ │ │ ├── schedule/ # Resources, Events, Services
|
||||
│ │ │ ├── contracts/ # E-signatures
|
||||
│ │ │ └── analytics/ # Business analytics
|
||||
│ │ ├── communication/ # Notifications, SMS, mobile
|
||||
│ │ ├── commerce/ # Payments, tickets
|
||||
│ │ └── platform/ # Admin, public API
|
||||
│ ├── docker-compose.local.yml
|
||||
│ └── docker-compose.production.yml
|
||||
│
|
||||
├── deploy.sh # Automated deployment script
|
||||
└── CLAUDE.md # Development guide
|
||||
```
|
||||
- **[PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md)** - **Manual step-by-step production deployment** (start here for fresh deployments)
|
||||
- **[QUICK-REFERENCE.md](QUICK-REFERENCE.md)** - Common commands and quick start
|
||||
- **[PRODUCTION-READY.md](PRODUCTION-READY.md)** - Production deployment status
|
||||
- **[DEPLOYMENT.md](DEPLOYMENT.md)** - Comprehensive deployment guide
|
||||
- **[CLAUDE.md](CLAUDE.md)** - Development guide and architecture
|
||||
|
||||
---
|
||||
## 🚀 Quick Start
|
||||
|
||||
## Local Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Docker** and **Docker Compose** (for backend)
|
||||
- **Node.js 22+** and **npm** (for frontend)
|
||||
- **Git**
|
||||
|
||||
### Step 1: Clone the Repository
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-repo/smoothschedule.git
|
||||
# Start backend (Django in Docker)
|
||||
cd smoothschedule
|
||||
```
|
||||
|
||||
### Step 2: Start the Backend (Django in Docker)
|
||||
|
||||
```bash
|
||||
cd smoothschedule
|
||||
|
||||
# Start all backend services
|
||||
docker compose -f docker-compose.local.yml up -d
|
||||
|
||||
# Wait for services to initialize (first time takes longer)
|
||||
sleep 30
|
||||
|
||||
# Run database migrations
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py migrate
|
||||
|
||||
# Create a superuser (optional)
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py createsuperuser
|
||||
```
|
||||
|
||||
### Step 3: Start the Frontend (React with Vite)
|
||||
|
||||
```bash
|
||||
# Start frontend (React with Vite)
|
||||
cd ../frontend
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
|
||||
# Access the app
|
||||
# Frontend: http://platform.lvh.me:5173
|
||||
# Backend API: http://lvh.me:8000/api
|
||||
```
|
||||
|
||||
### Step 4: Access the Application
|
||||
See [CLAUDE.md](CLAUDE.md) for detailed development instructions.
|
||||
|
||||
The application uses `lvh.me` (resolves to 127.0.0.1) for subdomain-based multi-tenancy:
|
||||
### Production Deployment
|
||||
|
||||
| URL | Purpose |
|
||||
|-----|---------|
|
||||
| http://platform.lvh.me:5173 | Platform admin dashboard |
|
||||
| http://demo.lvh.me:5173 | Demo tenant (if created) |
|
||||
| http://lvh.me:8000/api/ | Backend API |
|
||||
| http://lvh.me:8000/admin/ | Django admin |
|
||||
For **fresh deployments or complete reset**, follow [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) for manual step-by-step instructions.
|
||||
|
||||
**Why `lvh.me`?** Browsers don't allow cookies with `domain=.localhost`, but `lvh.me` resolves to 127.0.0.1 and allows proper cookie sharing across subdomains.
|
||||
|
||||
### Local Development Commands
|
||||
For **routine updates**, use the automated script:
|
||||
|
||||
```bash
|
||||
# Backend commands (always use docker compose)
|
||||
cd smoothschedule
|
||||
|
||||
# View logs
|
||||
docker compose -f docker-compose.local.yml logs -f django
|
||||
|
||||
# Run migrations
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py migrate
|
||||
|
||||
# Django shell
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py shell
|
||||
|
||||
# Run tests
|
||||
docker compose -f docker-compose.local.yml exec django pytest
|
||||
|
||||
# Stop all services
|
||||
docker compose -f docker-compose.local.yml down
|
||||
|
||||
# Frontend commands
|
||||
cd frontend
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
|
||||
# Type checking
|
||||
npm run typecheck
|
||||
|
||||
# Lint
|
||||
npm run lint
|
||||
# Deploy to production server (code changes only)
|
||||
./deploy.sh poduck@smoothschedule.com
|
||||
```
|
||||
|
||||
### Creating a Test Tenant
|
||||
See [PRODUCTION-READY.md](PRODUCTION-READY.md) for deployment checklist and [DEPLOYMENT.md](DEPLOYMENT.md) for detailed steps.
|
||||
|
||||
```bash
|
||||
cd smoothschedule
|
||||
docker compose -f docker-compose.local.yml exec django python manage.py shell
|
||||
```
|
||||
|
||||
```python
|
||||
from smoothschedule.identity.core.models import Tenant, Domain
|
||||
|
||||
# Create tenant
|
||||
tenant = Tenant.objects.create(
|
||||
name="Demo Business",
|
||||
schema_name="demo",
|
||||
)
|
||||
|
||||
# Create domain
|
||||
Domain.objects.create(
|
||||
domain="demo.lvh.me",
|
||||
tenant=tenant,
|
||||
is_primary=True,
|
||||
)
|
||||
|
||||
print(f"Created tenant: {tenant.name}")
|
||||
print(f"Access at: http://demo.lvh.me:5173")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Ubuntu/Debian server with Docker and Docker Compose
|
||||
- Domain name with DNS configured:
|
||||
- `A` record: `yourdomain.com` → Server IP
|
||||
- `A` record: `*.yourdomain.com` → Server IP (wildcard)
|
||||
- SSH access to the server
|
||||
|
||||
### Quick Deploy (Existing Server)
|
||||
|
||||
For routine updates to an existing production server:
|
||||
|
||||
```bash
|
||||
# From your local machine
|
||||
./deploy.sh user@yourdomain.com
|
||||
|
||||
# Or deploy specific services
|
||||
./deploy.sh user@yourdomain.com nginx
|
||||
./deploy.sh user@yourdomain.com django
|
||||
```
|
||||
|
||||
### Fresh Server Deployment
|
||||
|
||||
#### Step 1: Server Setup
|
||||
|
||||
SSH into your server and install Docker:
|
||||
|
||||
```bash
|
||||
ssh user@yourdomain.com
|
||||
|
||||
# Install Docker
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# Logout and login for group changes
|
||||
exit
|
||||
ssh user@yourdomain.com
|
||||
```
|
||||
|
||||
#### Step 2: Clone Repository
|
||||
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/your-repo/smoothschedule.git smoothschedule
|
||||
cd smoothschedule
|
||||
```
|
||||
|
||||
#### Step 3: Configure Environment Variables
|
||||
|
||||
Create production environment files:
|
||||
|
||||
```bash
|
||||
mkdir -p smoothschedule/.envs/.production
|
||||
|
||||
# Django configuration
|
||||
cat > smoothschedule/.envs/.production/.django << 'EOF'
|
||||
DJANGO_SECRET_KEY=your-random-secret-key-here
|
||||
DJANGO_DEBUG=False
|
||||
DJANGO_ALLOWED_HOSTS=yourdomain.com,*.yourdomain.com
|
||||
|
||||
DJANGO_ADMIN_URL=your-secret-admin-path/
|
||||
FRONTEND_URL=https://platform.yourdomain.com
|
||||
PLATFORM_BASE_URL=https://platform.yourdomain.com
|
||||
|
||||
REDIS_URL=redis://redis:6379/0
|
||||
CELERY_BROKER_URL=redis://redis:6379/0
|
||||
|
||||
# DigitalOcean Spaces (or S3)
|
||||
DJANGO_AWS_ACCESS_KEY_ID=your-access-key
|
||||
DJANGO_AWS_SECRET_ACCESS_KEY=your-secret-key
|
||||
DJANGO_AWS_STORAGE_BUCKET_NAME=your-bucket
|
||||
DJANGO_AWS_S3_ENDPOINT_URL=https://nyc3.digitaloceanspaces.com
|
||||
DJANGO_AWS_S3_REGION_NAME=nyc3
|
||||
|
||||
# SSL
|
||||
DJANGO_SECURE_SSL_REDIRECT=True
|
||||
DJANGO_SESSION_COOKIE_SECURE=True
|
||||
DJANGO_CSRF_COOKIE_SECURE=True
|
||||
|
||||
# Cloudflare (for wildcard SSL)
|
||||
CF_DNS_API_TOKEN=your-cloudflare-api-token
|
||||
EOF
|
||||
|
||||
# PostgreSQL configuration
|
||||
cat > smoothschedule/.envs/.production/.postgres << 'EOF'
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=smoothschedule
|
||||
POSTGRES_USER=smoothschedule_user
|
||||
POSTGRES_PASSWORD=your-secure-database-password
|
||||
EOF
|
||||
```
|
||||
|
||||
#### Step 4: Build and Start
|
||||
|
||||
```bash
|
||||
cd ~/smoothschedule/smoothschedule
|
||||
|
||||
# Build all images
|
||||
docker compose -f docker-compose.production.yml build
|
||||
|
||||
# Start services
|
||||
docker compose -f docker-compose.production.yml up -d
|
||||
|
||||
# Wait for startup
|
||||
sleep 30
|
||||
|
||||
# Run migrations
|
||||
docker compose -f docker-compose.production.yml exec django python manage.py migrate
|
||||
|
||||
# Collect static files
|
||||
docker compose -f docker-compose.production.yml exec django python manage.py collectstatic --noinput
|
||||
|
||||
# Create superuser
|
||||
docker compose -f docker-compose.production.yml exec django python manage.py createsuperuser
|
||||
```
|
||||
|
||||
#### Step 5: Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check all containers are running
|
||||
docker compose -f docker-compose.production.yml ps
|
||||
|
||||
# View logs
|
||||
docker compose -f docker-compose.production.yml logs -f
|
||||
|
||||
# Test endpoints
|
||||
curl https://yourdomain.com/api/health/
|
||||
```
|
||||
|
||||
### Production URLs
|
||||
|
||||
| URL | Purpose |
|
||||
|-----|---------|
|
||||
| https://yourdomain.com | Marketing site |
|
||||
| https://platform.yourdomain.com | Platform admin |
|
||||
| https://*.yourdomain.com | Tenant subdomains |
|
||||
| https://api.yourdomain.com | API (if configured) |
|
||||
| https://yourdomain.com:5555 | Flower (Celery monitoring) |
|
||||
|
||||
### Production Management Commands
|
||||
|
||||
```bash
|
||||
ssh user@yourdomain.com
|
||||
cd ~/smoothschedule/smoothschedule
|
||||
|
||||
# View logs
|
||||
docker compose -f docker-compose.production.yml logs -f django
|
||||
|
||||
# Restart services
|
||||
docker compose -f docker-compose.production.yml restart
|
||||
|
||||
# Run migrations
|
||||
docker compose -f docker-compose.production.yml exec django python manage.py migrate
|
||||
|
||||
# Django shell
|
||||
docker compose -f docker-compose.production.yml exec django python manage.py shell
|
||||
|
||||
# Database backup
|
||||
docker compose -f docker-compose.production.yml exec postgres pg_dump -U smoothschedule_user smoothschedule > backup.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Multi-Tenancy Model
|
||||
|
||||
```
|
||||
PostgreSQL Database
|
||||
├── public (shared schema)
|
||||
│ ├── Tenants
|
||||
│ ├── Domains
|
||||
│ ├── Users
|
||||
│ └── PermissionGrants
|
||||
├── demo (tenant schema)
|
||||
│ ├── Resources
|
||||
│ ├── Events
|
||||
│ ├── Services
|
||||
│ └── Customers
|
||||
└── acme (tenant schema)
|
||||
├── Resources
|
||||
├── Events
|
||||
└── ...
|
||||
┌─────────────────────────────────────────┐
|
||||
│ PostgreSQL Database │
|
||||
├─────────────────────────────────────────┤
|
||||
│ public (shared schema) │
|
||||
│ ├─ Tenants │
|
||||
│ ├─ Domains │
|
||||
│ ├─ Users │
|
||||
│ └─ PermissionGrants │
|
||||
├─────────────────────────────────────────┤
|
||||
│ tenant_demo (schema for Demo Company) │
|
||||
│ ├─ Appointments │
|
||||
│ ├─ Resources │
|
||||
│ └─ Customers │
|
||||
├─────────────────────────────────────────┤
|
||||
│ tenant_acme (schema for Acme Corp) │
|
||||
│ ├─ Appointments │
|
||||
│ ├─ Resources │
|
||||
│ └─ Customers │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Role Hierarchy
|
||||
|
||||
| Role | Level | Access |
|
||||
|------|-------|--------|
|
||||
| SUPERUSER | Platform | All tenants (god mode) |
|
||||
| PLATFORM_MANAGER | Platform | All tenants |
|
||||
| PLATFORM_SALES | Platform | Demo accounts only |
|
||||
| PLATFORM_SUPPORT | Platform | Can masquerade as tenant users |
|
||||
| TENANT_OWNER | Tenant | Full tenant access |
|
||||
| TENANT_MANAGER | Tenant | Most tenant features |
|
||||
| TENANT_STAFF | Tenant | Limited tenant access |
|
||||
| CUSTOMER | Tenant | Own data only |
|
||||
| Role | Level | Access Scope |
|
||||
|---------------------|----------|---------------------------|
|
||||
| SUPERUSER | Platform | All tenants (god mode) |
|
||||
| PLATFORM_MANAGER | Platform | All tenants |
|
||||
| PLATFORM_SALES | Platform | Demo accounts only |
|
||||
| PLATFORM_SUPPORT | Platform | Tenant users |
|
||||
| TENANT_OWNER | Tenant | Own tenant (full access) |
|
||||
| TENANT_MANAGER | Tenant | Own tenant |
|
||||
| TENANT_STAFF | Tenant | Own tenant (limited) |
|
||||
| CUSTOMER | Tenant | Own data only |
|
||||
|
||||
### Request Flow
|
||||
### Masquerading Matrix
|
||||
|
||||
| Hijacker Role | Can Masquerade As |
|
||||
|--------------------|----------------------------------|
|
||||
| SUPERUSER | Anyone |
|
||||
| PLATFORM_SUPPORT | Tenant users |
|
||||
| PLATFORM_SALES | Demo accounts (`is_temporary=True`) |
|
||||
| TENANT_OWNER | Staff in same tenant |
|
||||
| Others | No one |
|
||||
|
||||
**Security Rules:**
|
||||
- Cannot hijack yourself
|
||||
- Cannot hijack SUPERUSERs (except by other SUPERUSERs)
|
||||
- Maximum depth: 1 (no hijack chains)
|
||||
- All attempts logged to `logs/masquerade.log`
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
Browser → Traefik (SSL) → nginx (frontend) or django (API)
|
||||
↓
|
||||
React SPA
|
||||
↓
|
||||
/api/* → django:5000
|
||||
/ws/* → django:5000 (WebSocket)
|
||||
smoothschedule/
|
||||
├── config/
|
||||
│ └── settings.py # Multi-tenancy & security config
|
||||
├── core/
|
||||
│ ├── models.py # Tenant, Domain, PermissionGrant
|
||||
│ ├── permissions.py # Hijack permission matrix
|
||||
│ ├── middleware.py # Masquerade audit logging
|
||||
│ └── admin.py # Django admin for core models
|
||||
├── users/
|
||||
│ ├── models.py # Custom User with 8-tier roles
|
||||
│ └── admin.py # User admin with hijack button
|
||||
├── logs/
|
||||
│ ├── security.log # General security events
|
||||
│ └── masquerade.log # Hijack activity (JSON)
|
||||
└── setup_project.sh # Automated setup script
|
||||
```
|
||||
|
||||
---
|
||||
## 🔐 Security Features
|
||||
|
||||
## Configuration Files
|
||||
### Audit Logging
|
||||
|
||||
### Backend
|
||||
All masquerade activity is logged in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2024-01-15T10:30:00Z",
|
||||
"action": "HIJACK_START",
|
||||
"hijacker_email": "support@smoothschedule.com",
|
||||
"hijacked_email": "customer@demo.com",
|
||||
"ip_address": "192.168.1.1",
|
||||
"session_key": "abc123..."
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Grants (30-Minute Window)
|
||||
|
||||
Time-limited elevated permissions:
|
||||
|
||||
```python
|
||||
from core.models import PermissionGrant
|
||||
|
||||
grant = PermissionGrant.create_grant(
|
||||
grantor=admin_user,
|
||||
grantee=support_user,
|
||||
action="view_billing",
|
||||
reason="Customer requested billing support",
|
||||
duration_minutes=30,
|
||||
)
|
||||
|
||||
# Check if active
|
||||
if grant.is_active():
|
||||
# Perform privileged action
|
||||
pass
|
||||
```
|
||||
|
||||
## 🧪 Testing Masquerading
|
||||
|
||||
1. Access Django Admin: `http://localhost:8000/admin/`
|
||||
2. Create test users with different roles
|
||||
3. Click "Hijack" button next to a user
|
||||
4. Verify audit logs: `docker-compose exec django cat logs/masquerade.log`
|
||||
|
||||
## 📊 Admin Interface
|
||||
|
||||
- **Tenant Management**: View tenants, domains, subscription tiers
|
||||
- **User Management**: Color-coded roles, masquerade buttons
|
||||
- **Permission Grants**: Active/expired/revoked status, bulk revoke
|
||||
- **Domain Verification**: AWS Route53 integration status
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Adding Tenant Apps
|
||||
|
||||
Edit `config/settings.py`:
|
||||
|
||||
```python
|
||||
TENANT_APPS = [
|
||||
'django.contrib.contenttypes',
|
||||
'appointments', # Your app
|
||||
'resources', # Your app
|
||||
'billing', # Your app
|
||||
]
|
||||
```
|
||||
|
||||
### Custom Domain Setup
|
||||
|
||||
```python
|
||||
domain = Domain.objects.create(
|
||||
domain="app.customdomain.com",
|
||||
tenant=tenant,
|
||||
is_custom_domain=True,
|
||||
route53_zone_id="Z1234567890ABC",
|
||||
)
|
||||
```
|
||||
|
||||
Then configure Route53 CNAME: `app.customdomain.com` → `smoothschedule.yourhost.com`
|
||||
|
||||
## 📖 Key Files Reference
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `smoothschedule/docker-compose.local.yml` | Local Docker services |
|
||||
| `smoothschedule/docker-compose.production.yml` | Production Docker services |
|
||||
| `smoothschedule/.envs/.local/` | Local environment variables |
|
||||
| `smoothschedule/.envs/.production/` | Production environment variables |
|
||||
| `smoothschedule/config/settings/` | Django settings |
|
||||
| `smoothschedule/compose/production/traefik/traefik.yml` | Traefik routing config |
|
||||
| `setup_project.sh` | Automated project initialization |
|
||||
| `config/settings.py` | Multi-tenancy, middleware, security config |
|
||||
| `core/models.py` | Tenant, Domain, PermissionGrant models |
|
||||
| `core/permissions.py` | Masquerading permission matrix |
|
||||
| `core/middleware.py` | Audit logging for masquerading |
|
||||
| `users/models.py` | Custom User with 8-tier roles |
|
||||
|
||||
### Frontend
|
||||
## 📝 Important Notes
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `frontend/.env.development` | Local environment variables |
|
||||
| `frontend/.env.production` | Production environment variables |
|
||||
| `frontend/nginx.conf` | Production nginx config |
|
||||
| `frontend/vite.config.ts` | Vite bundler config |
|
||||
- **Django Admin**: The ONLY HTML interface (everything else is API)
|
||||
- **Middleware Order**: `TenantMainMiddleware` must be first, `MasqueradeAuditMiddleware` after `HijackUserMiddleware`
|
||||
- **Tenant Isolation**: Each tenant's data is in a separate PostgreSQL schema
|
||||
- **Production**: Update `SECRET_KEY`, database credentials, and AWS keys via environment variables
|
||||
|
||||
---
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
## Troubleshooting
|
||||
**Cannot create tenant users:**
|
||||
- Error: "Users with role TENANT_STAFF must be assigned to a tenant"
|
||||
- Solution: Set `user.tenant = tenant_instance` before saving
|
||||
|
||||
### Backend won't start
|
||||
**Hijack button doesn't appear:**
|
||||
- Check `HIJACK_AUTHORIZATION_CHECK` in settings
|
||||
- Verify `HijackUserAdminMixin` in `users/admin.py`
|
||||
- Ensure user has permission per matrix rules
|
||||
|
||||
```bash
|
||||
# Check Docker logs
|
||||
docker compose -f docker-compose.local.yml logs django
|
||||
**Migrations fail:**
|
||||
- Run shared migrations first: `migrate_schemas --shared`
|
||||
- Then run tenant migrations: `migrate_schemas`
|
||||
|
||||
# Common issues:
|
||||
# - Database not ready: wait longer, then restart django
|
||||
# - Missing migrations: run migrate command
|
||||
# - Port conflict: check if 8000 is in use
|
||||
```
|
||||
|
||||
### Frontend can't connect to API
|
||||
|
||||
```bash
|
||||
# Verify backend is running
|
||||
curl http://lvh.me:8000/api/
|
||||
|
||||
# Check CORS settings in Django
|
||||
# Ensure CORS_ALLOWED_ORIGINS includes http://platform.lvh.me:5173
|
||||
```
|
||||
|
||||
### WebSockets disconnecting
|
||||
|
||||
```bash
|
||||
# Check nginx has /ws/ proxy configured
|
||||
# Verify django is running ASGI (Daphne)
|
||||
# Check production traefik/nginx logs
|
||||
```
|
||||
|
||||
### Multi-tenant issues
|
||||
|
||||
```bash
|
||||
# Check tenant exists
|
||||
docker compose exec django python manage.py shell
|
||||
>>> from smoothschedule.identity.core.models import Tenant, Domain
|
||||
>>> Tenant.objects.all()
|
||||
>>> Domain.objects.all()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Documentation
|
||||
|
||||
- **[CLAUDE.md](CLAUDE.md)** - Development guide, coding standards, architecture details
|
||||
- **[DEPLOYMENT.md](DEPLOYMENT.md)** - Comprehensive deployment guide
|
||||
- **[PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md)** - Step-by-step manual deployment
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
## 📄 License
|
||||
|
||||
MIT
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
This is a production skeleton. Extend `TENANT_APPS` with your business logic.
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ for multi-tenant SaaS perfection**
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
@activepieces:registry=https://registry.npmjs.org/
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
legacy-peer-deps=true
|
||||
save-exact=true
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "nx-cloud-client-bundle",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"author": "Victor Savkin",
|
||||
"license": "proprietary",
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "^1.30.1",
|
||||
"@opentelemetry/core": "^1.30.1",
|
||||
"@opentelemetry/resources": "^1.30.1",
|
||||
"@opentelemetry/sdk-trace-base": "^1.30.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0",
|
||||
"axios": "1.1.3",
|
||||
"enquirer": "2.4.1",
|
||||
"dotenv": "~10.0.0",
|
||||
"node-machine-id": "^1.1.12",
|
||||
"tar": "6.1.11",
|
||||
"strip-json-comments": "^5.0.1",
|
||||
"chalk": "4.1.2",
|
||||
"yargs-parser": "21.1.1",
|
||||
"fs-extra": "^11.1.0",
|
||||
"open": "~8.4.0",
|
||||
"html-entities": "^2.6.0",
|
||||
"ini": "4.1.3",
|
||||
"yaml": "2.6.1",
|
||||
"semver": "7.5.4"
|
||||
}
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Nx Cloud login</title>
|
||||
<style>
|
||||
*,
|
||||
:before,
|
||||
:after {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
tab-size: 4;
|
||||
font-family:
|
||||
ui-sans-serif,
|
||||
system-ui,
|
||||
sans-serif,
|
||||
'Apple Color Emoji',
|
||||
'Segoe UI Emoji',
|
||||
Segoe UI Symbol,
|
||||
'Noto Color Emoji';
|
||||
font-feature-settings: normal;
|
||||
font-variation-settings: normal;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
line-height: inherit;
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
/*border-bottom-width: 1px;*/
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.mb-2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.mt-20 {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.h-14 {
|
||||
height: 3.5rem;
|
||||
}
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
.min-h-full {
|
||||
min-height: 100%;
|
||||
}
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
.w-auto {
|
||||
width: auto;
|
||||
}
|
||||
.max-w-7xl {
|
||||
max-width: 80rem;
|
||||
}
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
.items-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
.gap-8 {
|
||||
gap: 2rem;
|
||||
}
|
||||
.border-b {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.border-t {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
.border-slate-100 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(241 245 249 / var(--tw-border-opacity));
|
||||
}
|
||||
.border-slate-200 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
}
|
||||
.bg-white {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
.p-8 {
|
||||
padding: 2rem;
|
||||
}
|
||||
.px-4 {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.px-40 {
|
||||
padding-left: 10rem;
|
||||
padding-right: 10rem;
|
||||
}
|
||||
.py-10 {
|
||||
padding-top: 2.5rem;
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
.text-wrap {
|
||||
max-width: 100%;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.leading-7 {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
.text-slate-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(148 163 184 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-slate-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-slate-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(15 23 42 / var(--tw-text-opacity));
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
.opacity-50 {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.opacity-25 {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.transition {
|
||||
transition-property: color, background-color, border-color,
|
||||
text-decoration-color, fill, stroke, opacity, box-shadow, transform,
|
||||
filter, backdrop-filter;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 0.15s;
|
||||
}
|
||||
body {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
.hover\:opacity-100:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
@media (min-width: 640px) {
|
||||
.sm\:-my-px {
|
||||
margin-top: -1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
.sm\:ml-6 {
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
.sm\:flex {
|
||||
display: flex;
|
||||
}
|
||||
.sm\:truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sm\:px-6 {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
.sm\:text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
.sm\:tracking-tight {
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.md\:grid {
|
||||
display: grid;
|
||||
}
|
||||
.md\:grid-cols-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
.md\:gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
.md\:p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:flex {
|
||||
display: flex;
|
||||
}
|
||||
.lg\:px-8 {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="min-h-full">
|
||||
<nav class="border-b border-slate-200 bg-white">
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-14 justify-between">
|
||||
<div class="flex">
|
||||
<div class="flex flex-shrink-0 items-center">
|
||||
<a href="{{ nxCloudUrl }}">
|
||||
<svg
|
||||
id="nx-cloud-header-logo"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="currentColor"
|
||||
fill="transparent"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 3.75V6.5c-3.036 0-5.5 2.464-5.5 5.5s-2.464 5.5-5.5 5.5-5.5 2.464-5.5 5.5H3.75C2.232 23 1 21.768 1 20.25V3.75C1 2.232 2.232 1 3.75 1h16.5C21.768 1 23 2.232 23 3.75Z"
|
||||
id="nx-cloud-header-logo-stroke-1"
|
||||
></path>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 6v14.1667C23 21.7307 21.7307 23 20.1667 23H6c0-3.128 2.53867-5.6667 5.6667-5.6667 3.128 0 5.6666-2.5386 5.6666-5.6666C17.3333 8.53867 19.872 6 23 6Z"
|
||||
id="nx-cloud-header-logo-stroke-2"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="hidden sm:-my-px sm:ml-6 sm:flex sm:space-x-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="py-10">
|
||||
<div
|
||||
class="mx-auto flex max-w-7xl flex-col items-start justify-center gap-2 px-40"
|
||||
>
|
||||
<h1
|
||||
class="text-2xl leading-7 font-bold text-slate-900 sm:truncate sm:text-3xl sm:tracking-tight"
|
||||
>
|
||||
Your workspace is connected to Nx Cloud
|
||||
</h1>
|
||||
<div>
|
||||
<p class="mb-2">You may now close this window.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
class="mt-20 flex border-t border-slate-100 dark:border-slate-800"
|
||||
>
|
||||
<nav
|
||||
role="menu"
|
||||
aria-labelledby="bottom-navigation"
|
||||
class="mx-auto flex w-auto max-w-7xl items-center px-4 text-slate-400 dark:text-slate-600"
|
||||
>
|
||||
<div class="flex items-center gap-4 p-8 opacity-50">
|
||||
<a title="Nx Cloud" href="{{ nxCloudUrl }}">
|
||||
<svg
|
||||
id="nx-cloud-header-logo"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="currentColor"
|
||||
fill="transparent"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-5 w-5"
|
||||
>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 3.75V6.5c-3.036 0-5.5 2.464-5.5 5.5s-2.464 5.5-5.5 5.5-5.5 2.464-5.5 5.5H3.75C2.232 23 1 21.768 1 20.25V3.75C1 2.232 2.232 1 3.75 1h16.5C21.768 1 23 2.232 23 3.75Z"
|
||||
id="nx-cloud-header-logo-stroke-1"
|
||||
></path>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 6v14.1667C23 21.7307 21.7307 23 20.1667 23H6c0-3.128 2.53867-5.6667 5.6667-5.6667 3.128 0 5.6666-2.5386 5.6666-5.6666C17.3333 8.53867 19.872 6 23 6Z"
|
||||
id="nx-cloud-header-logo-stroke-2"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<p class="text-xs transition">© 2024 - Nx Cloud</p>
|
||||
</div>
|
||||
<section
|
||||
class="hidden gap-8 p-8 text-xs opacity-25 transition hover:opacity-100 md:grid md:grid-cols-4 md:gap-4 md:p-2 lg:flex"
|
||||
>
|
||||
<a href="https://nx.app/terms" title="Terms of Service"
|
||||
>Terms of Service</a
|
||||
><a href="https://nx.app/privacy" title="Privacy Policy"
|
||||
>Privacy Policy</a
|
||||
><a
|
||||
href="https://status.nx.app"
|
||||
title="Status"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>Status</a
|
||||
><a
|
||||
href="https://nx.dev/ci/intro/ci-with-nx?utm_source=nx.app"
|
||||
title="Docs"
|
||||
>Docs</a
|
||||
><a href="mailto:cloud-support@nrwl.io" title="Contact Nx Cloud"
|
||||
>Contact Nx Cloud</a
|
||||
><a href="https://nx.dev/pricing?utm_source=nx.app" title="Pricing"
|
||||
>Pricing</a
|
||||
><a href="https://nx.dev/company?utm_source=nx.app" title="Company"
|
||||
>Company</a
|
||||
><a
|
||||
href="https://twitter.com/nxdevtools"
|
||||
title="@NxDevTools"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>@NxDevTools</a
|
||||
>
|
||||
</section>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,432 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Nx Cloud login</title>
|
||||
<style>
|
||||
*,
|
||||
:before,
|
||||
:after {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
tab-size: 4;
|
||||
font-family:
|
||||
ui-sans-serif,
|
||||
system-ui,
|
||||
sans-serif,
|
||||
'Apple Color Emoji',
|
||||
'Segoe UI Emoji',
|
||||
Segoe UI Symbol,
|
||||
'Noto Color Emoji';
|
||||
font-feature-settings: normal;
|
||||
font-variation-settings: normal;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
line-height: inherit;
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
box-sizing: border-box;
|
||||
border-width: 0;
|
||||
border-style: solid;
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
/*border-bottom-width: 1px;*/
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.mb-2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.mt-20 {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.h-14 {
|
||||
height: 3.5rem;
|
||||
}
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
.min-h-full {
|
||||
min-height: 100%;
|
||||
}
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
.w-auto {
|
||||
width: auto;
|
||||
}
|
||||
.max-w-7xl {
|
||||
max-width: 80rem;
|
||||
}
|
||||
.flex-shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
.items-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
.gap-8 {
|
||||
gap: 2rem;
|
||||
}
|
||||
.border-b {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.border-t {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
.border-slate-100 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(241 245 249 / var(--tw-border-opacity));
|
||||
}
|
||||
.border-slate-200 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(226 232 240 / var(--tw-border-opacity));
|
||||
}
|
||||
.bg-white {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
.p-8 {
|
||||
padding: 2rem;
|
||||
}
|
||||
.px-4 {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.px-40 {
|
||||
padding-left: 10rem;
|
||||
padding-right: 10rem;
|
||||
}
|
||||
.py-10 {
|
||||
padding-top: 2.5rem;
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.text-xs {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.leading-7 {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
.text-slate-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(148 163 184 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-slate-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(51 65 85 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-slate-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(15 23 42 / var(--tw-text-opacity));
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
.opacity-50 {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.opacity-25 {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.transition {
|
||||
transition-property: color, background-color, border-color,
|
||||
text-decoration-color, fill, stroke, opacity, box-shadow, transform,
|
||||
filter, backdrop-filter;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 0.15s;
|
||||
}
|
||||
body {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
.hover\:opacity-100:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
@media (min-width: 640px) {
|
||||
.sm\:-my-px {
|
||||
margin-top: -1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
.sm\:ml-6 {
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
.sm\:flex {
|
||||
display: flex;
|
||||
}
|
||||
.sm\:truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sm\:px-6 {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
.sm\:text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
.sm\:tracking-tight {
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.md\:grid {
|
||||
display: grid;
|
||||
}
|
||||
.md\:grid-cols-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
.md\:gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
.md\:p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:flex {
|
||||
display: flex;
|
||||
}
|
||||
.lg\:px-8 {
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function startCountdown() {
|
||||
let countdownElement = document.getElementById('countdown');
|
||||
let countdown = 5;
|
||||
|
||||
let interval = setInterval(function () {
|
||||
countdownElement.innerHTML = countdown;
|
||||
countdown--;
|
||||
|
||||
if (countdown < 0) {
|
||||
clearInterval(interval);
|
||||
window.location.href = '{{ redirectUrl }}'; // Replace with your redirect URL
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="startCountdown()">
|
||||
<div class="min-h-full">
|
||||
<nav class="border-b border-slate-200 bg-white">
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex h-14 justify-between">
|
||||
<div class="flex">
|
||||
<div class="flex flex-shrink-0 items-center">
|
||||
<a href="{{ nxCloudUrl }}">
|
||||
<svg
|
||||
id="nx-cloud-header-logo"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="currentColor"
|
||||
fill="transparent"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 3.75V6.5c-3.036 0-5.5 2.464-5.5 5.5s-2.464 5.5-5.5 5.5-5.5 2.464-5.5 5.5H3.75C2.232 23 1 21.768 1 20.25V3.75C1 2.232 2.232 1 3.75 1h16.5C21.768 1 23 2.232 23 3.75Z"
|
||||
id="nx-cloud-header-logo-stroke-1"
|
||||
></path>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 6v14.1667C23 21.7307 21.7307 23 20.1667 23H6c0-3.128 2.53867-5.6667 5.6667-5.6667 3.128 0 5.6666-2.5386 5.6666-5.6666C17.3333 8.53867 19.872 6 23 6Z"
|
||||
id="nx-cloud-header-logo-stroke-2"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="hidden sm:-my-px sm:ml-6 sm:flex sm:space-x-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="py-10">
|
||||
<div
|
||||
class="mx-auto flex max-w-7xl flex-col items-start justify-center gap-2 px-40"
|
||||
>
|
||||
<h1
|
||||
class="text-2xl leading-7 font-bold text-slate-900 sm:truncate sm:text-3xl sm:tracking-tight"
|
||||
>
|
||||
Nx Cloud Login
|
||||
</h1>
|
||||
<div>
|
||||
<p class="mb-2">
|
||||
You will be redirected to
|
||||
<a class="font-semibold underline" href="{{ redirectUrl }}"
|
||||
>Nx Cloud</a
|
||||
>
|
||||
in <span id="countdown">5</span> seconds.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
class="mt-20 flex border-t border-slate-100 dark:border-slate-800"
|
||||
>
|
||||
<nav
|
||||
role="menu"
|
||||
aria-labelledby="bottom-navigation"
|
||||
class="mx-auto flex w-auto max-w-7xl items-center px-4 text-slate-400 dark:text-slate-600"
|
||||
>
|
||||
<div class="flex items-center gap-4 p-8 opacity-50">
|
||||
<a title="Nx Cloud" href="{{ nxCloudUrl }}">
|
||||
<svg
|
||||
id="nx-cloud-header-logo"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke="currentColor"
|
||||
fill="transparent"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-5 w-5"
|
||||
>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 3.75V6.5c-3.036 0-5.5 2.464-5.5 5.5s-2.464 5.5-5.5 5.5-5.5 2.464-5.5 5.5H3.75C2.232 23 1 21.768 1 20.25V3.75C1 2.232 2.232 1 3.75 1h16.5C21.768 1 23 2.232 23 3.75Z"
|
||||
id="nx-cloud-header-logo-stroke-1"
|
||||
></path>
|
||||
<path
|
||||
stroke-width="2"
|
||||
d="M23 6v14.1667C23 21.7307 21.7307 23 20.1667 23H6c0-3.128 2.53867-5.6667 5.6667-5.6667 3.128 0 5.6666-2.5386 5.6666-5.6666C17.3333 8.53867 19.872 6 23 6Z"
|
||||
id="nx-cloud-header-logo-stroke-2"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<p class="text-xs transition">© 2024 - Nx Cloud</p>
|
||||
</div>
|
||||
<section
|
||||
class="hidden gap-8 p-8 text-xs opacity-25 transition hover:opacity-100 md:grid md:grid-cols-4 md:gap-4 md:p-2 lg:flex"
|
||||
>
|
||||
<a href="https://nx.app/terms" title="Terms of Service"
|
||||
>Terms of Service</a
|
||||
><a href="https://nx.app/privacy" title="Privacy Policy"
|
||||
>Privacy Policy</a
|
||||
><a
|
||||
href="https://status.nx.app"
|
||||
title="Status"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>Status</a
|
||||
><a
|
||||
href="https://nx.dev/ci/intro/ci-with-nx?utm_source=nx.app"
|
||||
title="Docs"
|
||||
>Docs</a
|
||||
><a href="mailto:cloud-support@nrwl.io" title="Contact Nx Cloud"
|
||||
>Contact Nx Cloud</a
|
||||
><a href="https://nx.dev/pricing?utm_source=nx.app" title="Pricing"
|
||||
>Pricing</a
|
||||
><a href="https://nx.dev/company?utm_source=nx.app" title="Company"
|
||||
>Company</a
|
||||
><a
|
||||
href="https://twitter.com/nxdevtools"
|
||||
title="@NxDevTools"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>@NxDevTools</a
|
||||
>
|
||||
</section>
|
||||
</nav>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
1766103708902
|
||||
@@ -1,13 +0,0 @@
|
||||
<!-- omit in toc -->
|
||||
# Contributing to Activepieces
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
All types of contributions are encouraged and valued. See the [Contributing Guide](https://www.activepieces.com/docs/developers/building-pieces/start-building) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
> - Refer this project in your project's readme
|
||||
> - Mention the project at local meetups and tell your friends/colleagues
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
FROM node:20.19-bullseye-slim AS base
|
||||
|
||||
# Set environment variables early for better layer caching
|
||||
ENV LANG=en_US.UTF-8 \
|
||||
LANGUAGE=en_US:en \
|
||||
LC_ALL=en_US.UTF-8 \
|
||||
NX_DAEMON=false \
|
||||
NX_NO_CLOUD=true
|
||||
|
||||
# Install all system dependencies in a single layer with cache mounts
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openssh-client \
|
||||
python3 \
|
||||
g++ \
|
||||
build-essential \
|
||||
git \
|
||||
poppler-utils \
|
||||
poppler-data \
|
||||
procps \
|
||||
locales \
|
||||
locales-all \
|
||||
unzip \
|
||||
curl \
|
||||
ca-certificates \
|
||||
libcap-dev && \
|
||||
yarn config set python /usr/bin/python3
|
||||
|
||||
RUN export ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then \
|
||||
curl -fSL https://github.com/oven-sh/bun/releases/download/bun-v1.3.1/bun-linux-x64-baseline.zip -o bun.zip; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then \
|
||||
curl -fSL https://github.com/oven-sh/bun/releases/download/bun-v1.3.1/bun-linux-aarch64.zip -o bun.zip; \
|
||||
fi
|
||||
|
||||
RUN unzip bun.zip \
|
||||
&& mv bun-*/bun /usr/local/bin/bun \
|
||||
&& chmod +x /usr/local/bin/bun \
|
||||
&& rm -rf bun.zip bun-*
|
||||
|
||||
RUN bun --version
|
||||
|
||||
# Install global npm packages in a single layer
|
||||
RUN --mount=type=cache,target=/root/.npm \
|
||||
npm install -g --no-fund --no-audit \
|
||||
node-gyp \
|
||||
npm@9.9.3 \
|
||||
pm2@6.0.10 \
|
||||
typescript@4.9.4
|
||||
|
||||
# Install isolated-vm globally (needed for sandboxes)
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
cd /usr/src && bun install isolated-vm@5.0.1
|
||||
|
||||
### STAGE 1: Build ###
|
||||
FROM base AS build
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy only dependency files first for better layer caching
|
||||
COPY .npmrc package.json bun.lock ./
|
||||
|
||||
# Install all dependencies with frozen lockfile
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile
|
||||
|
||||
# Copy source code after dependency installation
|
||||
COPY . .
|
||||
|
||||
# Build all projects including the SmoothSchedule piece
|
||||
RUN npx nx run-many --target=build --projects=react-ui,server-api,pieces-smoothschedule --configuration production --parallel=2 --skip-nx-cache
|
||||
|
||||
# Install production dependencies only for the backend API
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
cd dist/packages/server/api && \
|
||||
bun install --production --frozen-lockfile
|
||||
|
||||
# Install dependencies for the SmoothSchedule piece
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
cd dist/packages/pieces/community/smoothschedule && \
|
||||
bun install --production
|
||||
|
||||
### STAGE 2: Run ###
|
||||
FROM base AS run
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install Nginx and gettext in a single layer with cache mount
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends nginx gettext
|
||||
|
||||
# Copy static configuration files first (better layer caching)
|
||||
COPY nginx.react.conf /etc/nginx/nginx.conf
|
||||
COPY --from=build /usr/src/app/packages/server/api/src/assets/default.cf /usr/local/etc/isolate
|
||||
COPY docker-entrypoint.sh .
|
||||
|
||||
# Create all necessary directories in one layer
|
||||
RUN mkdir -p \
|
||||
/usr/src/app/dist/packages/server \
|
||||
/usr/src/app/dist/packages/engine \
|
||||
/usr/src/app/dist/packages/shared \
|
||||
/usr/src/app/dist/packages/pieces && \
|
||||
chmod +x docker-entrypoint.sh
|
||||
|
||||
# Copy built artifacts from build stage
|
||||
COPY --from=build /usr/src/app/LICENSE .
|
||||
COPY --from=build /usr/src/app/dist/packages/engine/ ./dist/packages/engine/
|
||||
COPY --from=build /usr/src/app/dist/packages/server/ ./dist/packages/server/
|
||||
COPY --from=build /usr/src/app/dist/packages/shared/ ./dist/packages/shared/
|
||||
COPY --from=build /usr/src/app/dist/packages/pieces/ ./dist/packages/pieces/
|
||||
COPY --from=build /usr/src/app/packages ./packages
|
||||
|
||||
# Copy frontend files to Nginx document root
|
||||
COPY --from=build /usr/src/app/dist/packages/react-ui /usr/share/nginx/html/
|
||||
|
||||
LABEL service=activepieces
|
||||
|
||||
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||
EXPOSE 80
|
||||
@@ -1,25 +0,0 @@
|
||||
Copyright (c) 2020-2024 Activepieces Inc.
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
* All content that resides under the "packages/ee/" and "packages/server/api/src/app/ee" directory of this repository, if that directory exists, is licensed under the license defined in packages/ee/LICENSE
|
||||
* All third party components incorporated into the Activepieces Inc Software are licensed under the original license provided by the owner of the applicable component.
|
||||
* Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,464 +0,0 @@
|
||||
|
||||
<h1 align="center">
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://activepieces.com"
|
||||
>
|
||||
<img
|
||||
align="center"
|
||||
alt="Activepieces"
|
||||
src="https://github.com/activepieces/activepieces/assets/1812998/76c97441-c285-4480-bc75-30a0c73ed340"
|
||||
style="width:100%;"
|
||||
/>
|
||||
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="/LICENSE" target="_blank"><img src='https://img.shields.io/badge/license-MIT-green?style=for-the-badge' /></a> <img src='https://img.shields.io/github/commit-activity/w/activepieces/activepieces/main?style=for-the-badge' /> <a href='https://discord.gg/2jUXBKDdP8'><img src='https://img.shields.io/discord/966798490984382485?style=for-the-badge' /></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
An open source replacement for Zapier
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a
|
||||
href="https://www.activepieces.com/docs"
|
||||
target="_blank"
|
||||
><b>Documentation</b></a> 🌪️
|
||||
<a
|
||||
href="https://www.activepieces.com/docs/developers/building-pieces/overview"
|
||||
target="_blank"
|
||||
><b>Create a Piece</b></a> 🖉
|
||||
<a
|
||||
href="https://www.activepieces.com/docs/install/overview"
|
||||
target="_blank"
|
||||
><b>Deploy</b></a> 🔥
|
||||
<a
|
||||
href="https://discord.gg/yvxF5k5AUb"
|
||||
target="_blank"
|
||||
>
|
||||
<b>Join Discord</b>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# 🤯 Welcome to Activepieces
|
||||
|
||||
All-in-one AI automation designed to be **extensible** through a **type-safe** pieces framework written in **TypeScript**.
|
||||
When you contribute pieces to Activepieces they become automatically available as MCP servers that you can use with LLMs through Claude Desktop, Cursor or Windsurf!
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 🔥 Why Activepieces is Different:
|
||||
|
||||
- **💖 Loved by Everyone**: Intuitive interface and great experience for both technical and non-technical users with a quick learning curve.
|
||||
|
||||
<img src="/docs/resources/templates.gif">
|
||||
|
||||
- **🌐 Open Ecosystem:** All pieces are open source and available on npmjs.com, **60% of the pieces are contributed by the community**.
|
||||
|
||||
- **🛠️ Largest open source MCP toolkit**: All our pieces (280+) are available as MCP that you can use with LLMs on Claude Desktop, Cursor or Windsurf.
|
||||
|
||||
- **🛠️ Pieces are written in Typescript**: Pieces are npm packages in TypeScript, offering full customization with the best developer experience, including **hot reloading** for **local** piece development on your machine. 😎
|
||||
|
||||
<img src="/docs/resources/create-action.png" alt="">
|
||||
|
||||
- **🤖 AI-First**: Native AI pieces let you experiment with various providers, or create your own agents using our AI SDK to help you build flows inside the builder.
|
||||
|
||||
- **🏢 Enterprise-Ready**: Developers set up the tools, and anyone in the organization can use the no-code builder. Full customization from branding to control.
|
||||
|
||||
- **🔒 Secure by Design**: Self-hosted and network-gapped for maximum security and control over your data.
|
||||
|
||||
- **🧠 Human in the Loop**: Delay execution for a period of time or require approval. These are just pieces built on top of the piece framework, and you can build many pieces like that. 🎨
|
||||
|
||||
- **💻 Human Input Interfaces**: Built-in support for human input triggers like "Chat Interface" 💬 and "Form Interface" 📝
|
||||
|
||||
|
||||
|
||||
## 🛠️ Builder Features:
|
||||
|
||||
- [x] Loops
|
||||
- [x] Branches
|
||||
- [x] Auto Retries
|
||||
- [x] HTTP
|
||||
- [x] Code with **NPM**
|
||||
- [x] ASK AI in Code Piece (Non technical user can clean data without knowing to code)
|
||||
- [x] Flows are fully versioned.
|
||||
- [x] Languages Translations
|
||||
- [x] Customizable Templates
|
||||
- [X] 200+ Pieces, check https://www.activepieces.com/pieces
|
||||
|
||||
**We release updates frequently. Check the product changelog for the latest features.**
|
||||
|
||||
|
||||
## 🔌 Create Your Own Piece
|
||||
|
||||
Activepieces supports integrations with Google Sheets, OpenAI, Discord, RSS, and over 200 other services. [Check out the full list of supported integrations](https://www.activepieces.com/pieces), which is constantly expanding thanks to our community's contributions.
|
||||
|
||||
As an **open ecosystem**, all integration source code is accessible in our repository. These integrations are versioned and [published](https://www.npmjs.com/search?q=%40activepieces) directly to npmjs.com upon contribution.
|
||||
|
||||
You can easily create your own integration using our TypeScript framework. For detailed instructions, please refer to our [Contributor's Guide](https://www.activepieces.com/docs/developers/building-pieces/overview).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
# License
|
||||
|
||||
Activepieces' Community Edition is released as open source under the [MIT license](https://github.com/activepieces/activepieces/blob/main/LICENSE) and enterprise features are released under [Commercial License](https://github.com/activepieces/activepieces/blob/main/packages/ee/LICENSE)
|
||||
|
||||
|
||||
Read more about the feature comparison here https://www.activepieces.com/docs/about/editions
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
# 💭 Join Our Community
|
||||
|
||||
<a href="https://discord.gg/2jUXBKDdP8" target="_blank">
|
||||
<img src="https://discordapp.com/api/guilds/966798490984382485/widget.png?style=banner3" alt="">
|
||||
</a>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# 🌐 Contributions
|
||||
|
||||
We welcome contributions big or small and in different directions. The best way to do this is to check this [document](https://www.activepieces.com/docs/developers/building-pieces/create-action) and we are always up to talk on [our Discord Server](https://discord.gg/2jUXBKDdP8).
|
||||
|
||||
## 📚 Translations
|
||||
|
||||
Not into coding but still interested in contributing? Come join our [Discord](https://discord.gg/2jUXBKDdP8) and visit https://www.activepieces.com/docs/about/i18n for more information.
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16093902-626364-update.json)
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16093902-626364-update.json)
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16093902-626364-update.json)
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16093902-626364-update.json)
|
||||
|
||||
|
||||
].data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-16093902-626364-update.json)
|
||||
|
||||
|
||||
## 🦫 Contributors
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ShahedAlMashni"><img src="https://avatars.githubusercontent.com/u/41443850?v=4?s=100" width="100px;" alt="ShahedAlMashni"/><br /><sub><b>ShahedAlMashni</b></sub></a><br /><a href="#plugin-ShahedAlMashni" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AbdulTheActivePiecer"><img src="https://avatars.githubusercontent.com/u/106555838?v=4?s=100" width="100px;" alt="AbdulTheActivePiecer"/><br /><sub><b>AbdulTheActivePiecer</b></sub></a><br /><a href="#maintenance-AbdulTheActivePiecer" title="Maintenance">🚧</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/khaledmashaly"><img src="https://avatars.githubusercontent.com/u/61781545?v=4?s=100" width="100px;" alt="Khaled Mashaly"/><br /><sub><b>Khaled Mashaly</b></sub></a><br /><a href="#maintenance-khaledmashaly" title="Maintenance">🚧</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abuaboud"><img src="https://avatars.githubusercontent.com/u/1812998?v=4?s=100" width="100px;" alt="Mohammed Abu Aboud"/><br /><sub><b>Mohammed Abu Aboud</b></sub></a><br /><a href="#maintenance-abuaboud" title="Maintenance">🚧</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://aboudzein.github.io"><img src="https://avatars.githubusercontent.com/u/12976630?v=4?s=100" width="100px;" alt="Abdulrahman Zeineddin"/><br /><sub><b>Abdulrahman Zeineddin</b></sub></a><br /><a href="#plugin-aboudzein" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/creed983"><img src="https://avatars.githubusercontent.com/u/62152944?v=4?s=100" width="100px;" alt="ahmad jaber"/><br /><sub><b>ahmad jaber</b></sub></a><br /><a href="#plugin-creed983" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashrafsamhouri"><img src="https://avatars.githubusercontent.com/u/97393596?v=4?s=100" width="100px;" alt="ashrafsamhouri"/><br /><sub><b>ashrafsamhouri</b></sub></a><br /><a href="#plugin-ashrafsamhouri" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://steercampaign.com"><img src="https://avatars.githubusercontent.com/u/12627658?v=4?s=100" width="100px;" alt="Mohammad Abu Musa"/><br /><sub><b>Mohammad Abu Musa</b></sub></a><br /><a href="#projectManagement-mabumusa1" title="Project Management">📆</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kanarelo"><img src="https://avatars.githubusercontent.com/u/393261?v=4?s=100" width="100px;" alt="Mukewa Wekalao"/><br /><sub><b>Mukewa Wekalao</b></sub></a><br /><a href="#plugin-kanarelo" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://osamahaikal.me/"><img src="https://avatars.githubusercontent.com/u/72370395?v=4?s=100" width="100px;" alt="Osama Abdallah Essa Haikal"/><br /><sub><b>Osama Abdallah Essa Haikal</b></sub></a><br /><a href="#plugin-OsamaHaikal" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/M-Arman"><img src="https://avatars.githubusercontent.com/u/54455592?v=4?s=100" width="100px;" alt="Arman"/><br /><sub><b>Arman</b></sub></a><br /><a href="#security-M-Arman" title="Security">🛡️</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oskarkraemer"><img src="https://avatars.githubusercontent.com/u/42745862?v=4?s=100" width="100px;" alt="Oskar Krämer"/><br /><sub><b>Oskar Krämer</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=oskarkraemer" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://thibpat.com"><img src="https://avatars.githubusercontent.com/u/494686?v=4?s=100" width="100px;" alt="Thibaut Patel"/><br /><sub><b>Thibaut Patel</b></sub></a><br /><a href="#ideas-tpatel" title="Ideas, Planning, & Feedback">🤔</a> <a href="#plugin-tpatel" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Applesaucesomer"><img src="https://avatars.githubusercontent.com/u/18318905?v=4?s=100" width="100px;" alt="Applesaucesomer"/><br /><sub><b>Applesaucesomer</b></sub></a><br /><a href="#ideas-Applesaucesomer" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/crazyTweek"><img src="https://avatars.githubusercontent.com/u/6828237?v=4?s=100" width="100px;" alt="crazyTweek"/><br /><sub><b>crazyTweek</b></sub></a><br /><a href="#ideas-crazyTweek" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://linkedin.com/in/muhammad-tabaza"><img src="https://avatars.githubusercontent.com/u/23503983?v=4?s=100" width="100px;" alt="Muhammad Tabaza"/><br /><sub><b>Muhammad Tabaza</b></sub></a><br /><a href="#plugin-m-tabaza" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://shaypunter.co.uk"><img src="https://avatars.githubusercontent.com/u/18310437?v=4?s=100" width="100px;" alt="Shay Punter"/><br /><sub><b>Shay Punter</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=ShayPunter" title="Documentation">📖</a> <a href="#plugin-ShayPunter" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abaza738"><img src="https://avatars.githubusercontent.com/u/50132270?v=4?s=100" width="100px;" alt="abaza738"/><br /><sub><b>abaza738</b></sub></a><br /><a href="#plugin-abaza738" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jonaboe"><img src="https://avatars.githubusercontent.com/u/51358680?v=4?s=100" width="100px;" alt="Jona Boeddinghaus"/><br /><sub><b>Jona Boeddinghaus</b></sub></a><br /><a href="#plugin-jonaboe" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fomojola"><img src="https://avatars.githubusercontent.com/u/264253?v=4?s=100" width="100px;" alt="fomojola"/><br /><sub><b>fomojola</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=fomojola" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/astorozhevsky"><img src="https://avatars.githubusercontent.com/u/11055414?v=4?s=100" width="100px;" alt="Alexander Storozhevsky"/><br /><sub><b>Alexander Storozhevsky</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=astorozhevsky" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/J0LGER"><img src="https://avatars.githubusercontent.com/u/54769522?v=4?s=100" width="100px;" alt="J0LGER"/><br /><sub><b>J0LGER</b></sub></a><br /><a href="#security-J0LGER" title="Security">🛡️</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/veverkap"><img src="https://avatars.githubusercontent.com/u/22348?v=4?s=100" width="100px;" alt="Patrick Veverka"/><br /><sub><b>Patrick Veverka</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Aveverkap" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://berksmbl.com"><img src="https://avatars.githubusercontent.com/u/10000339?v=4?s=100" width="100px;" alt="Berk Sümbül"/><br /><sub><b>Berk Sümbül</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=berksmbl" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Willianwg"><img src="https://avatars.githubusercontent.com/u/51550522?v=4?s=100" width="100px;" alt="Willian Guedes"/><br /><sub><b>Willian Guedes</b></sub></a><br /><a href="#plugin-Willianwg" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abdullahranginwala"><img src="https://avatars.githubusercontent.com/u/19731056?v=4?s=100" width="100px;" alt="Abdullah Ranginwala"/><br /><sub><b>Abdullah Ranginwala</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=abdullahranginwala" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dentych"><img src="https://avatars.githubusercontent.com/u/2256372?v=4?s=100" width="100px;" alt="Dennis Tychsen"/><br /><sub><b>Dennis Tychsen</b></sub></a><br /><a href="#plugin-dentych" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MyWay"><img src="https://avatars.githubusercontent.com/u/1765284?v=4?s=100" width="100px;" alt="MyWay"/><br /><sub><b>MyWay</b></sub></a><br /><a href="#plugin-MyWay" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bibhuty-did-this"><img src="https://avatars.githubusercontent.com/u/28416188?v=4?s=100" width="100px;" alt="Bibhuti Bhusan Panda"/><br /><sub><b>Bibhuti Bhusan Panda</b></sub></a><br /><a href="#plugin-bibhuty-did-this" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tarunsamanta2k20"><img src="https://avatars.githubusercontent.com/u/55488549?v=4?s=100" width="100px;" alt="Tarun Samanta"/><br /><sub><b>Tarun Samanta</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Atarunsamanta2k20" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/herman-kudria-10868b207/"><img src="https://avatars.githubusercontent.com/u/9007211?v=4?s=100" width="100px;" alt="Herman Kudria"/><br /><sub><b>Herman Kudria</b></sub></a><br /><a href="#plugin-HKudria" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://nulldev.imagefoo.com/"><img src="https://avatars.githubusercontent.com/u/66683380?v=4?s=100" width="100px;" alt="[NULL] Dev"/><br /><sub><b>[NULL] Dev</b></sub></a><br /><a href="#plugin-Abdallah-Alwarawreh" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JanHolger"><img src="https://avatars.githubusercontent.com/u/25184957?v=4?s=100" width="100px;" alt="Jan Bebendorf"/><br /><sub><b>Jan Bebendorf</b></sub></a><br /><a href="#plugin-JanHolger" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.nileshtrivedi.com"><img src="https://avatars.githubusercontent.com/u/19304?v=4?s=100" width="100px;" alt="Nilesh"/><br /><sub><b>Nilesh</b></sub></a><br /><a href="#plugin-nileshtrivedi" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://certopus.com"><img src="https://avatars.githubusercontent.com/u/40790016?v=4?s=100" width="100px;" alt="Vraj Gohil"/><br /><sub><b>Vraj Gohil</b></sub></a><br /><a href="#plugin-VrajGohil" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BastienMe"><img src="https://avatars.githubusercontent.com/u/71411115?v=4?s=100" width="100px;" alt="BastienMe"/><br /><sub><b>BastienMe</b></sub></a><br /><a href="#plugin-BastienMe" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://blog.fosketts.net"><img src="https://avatars.githubusercontent.com/u/8627862?v=4?s=100" width="100px;" alt="Stephen Foskett"/><br /><sub><b>Stephen Foskett</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=SFoskett" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://ganapati.fr"><img src="https://avatars.githubusercontent.com/u/15729117?v=4?s=100" width="100px;" alt="Nathan"/><br /><sub><b>Nathan</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=asuri0n" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.n-soft.pl"><img src="https://avatars.githubusercontent.com/u/4056319?v=4?s=100" width="100px;" alt="Marcin Natanek"/><br /><sub><b>Marcin Natanek</b></sub></a><br /><a href="#plugin-mnatanek" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://all-tech-plus.com"><img src="https://avatars.githubusercontent.com/u/23551912?v=4?s=100" width="100px;" alt="Mark van Bellen"/><br /><sub><b>Mark van Bellen</b></sub></a><br /><a href="#plugin-buttonsbond" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://guzguz.fr"><img src="https://avatars.githubusercontent.com/u/13715916?v=4?s=100" width="100px;" alt="Olivier Guzzi"/><br /><sub><b>Olivier Guzzi</b></sub></a><br /><a href="#plugin-olivierguzzi" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ozak93"><img src="https://avatars.githubusercontent.com/u/31257994?v=4?s=100" width="100px;" alt="Osama Zakarneh"/><br /><sub><b>Osama Zakarneh</b></sub></a><br /><a href="#plugin-Ozak93" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/phestvik"><img src="https://avatars.githubusercontent.com/u/88210985?v=4?s=100" width="100px;" alt="phestvik"/><br /><sub><b>phestvik</b></sub></a><br /><a href="#ideas-phestvik" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://website-portfolio-bucket.s3-website-ap-northeast-1.amazonaws.com/"><img src="https://avatars.githubusercontent.com/u/113296626?v=4?s=100" width="100px;" alt="Rajdeep Pal"/><br /><sub><b>Rajdeep Pal</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=Rajdeep1311" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.tepote.com"><img src="https://avatars.githubusercontent.com/u/40870?v=4?s=100" width="100px;" alt="Camilo Usuga"/><br /><sub><b>Camilo Usuga</b></sub></a><br /><a href="#plugin-camilou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kishanprmr"><img src="https://avatars.githubusercontent.com/u/135701940?v=4?s=100" width="100px;" alt="Kishan Parmar"/><br /><sub><b>Kishan Parmar</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=kishanprmr" title="Documentation">📖</a> <a href="#plugin-kishanprmr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BBND"><img src="https://avatars.githubusercontent.com/u/42919338?v=4?s=100" width="100px;" alt="BBND"/><br /><sub><b>BBND</b></sub></a><br /><a href="#plugin-BBND" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haseebrehmanpc"><img src="https://avatars.githubusercontent.com/u/37938986?v=4?s=100" width="100px;" alt="Haseeb Rehman"/><br /><sub><b>Haseeb Rehman</b></sub></a><br /><a href="#plugin-haseebrehmanpc" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/ritagorokhod/"><img src="https://avatars.githubusercontent.com/u/60586879?v=4?s=100" width="100px;" alt="Rita Gorokhod"/><br /><sub><b>Rita Gorokhod</b></sub></a><br /><a href="#plugin-rita-gorokhod" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/facferreira"><img src="https://avatars.githubusercontent.com/u/487349?v=4?s=100" width="100px;" alt="Fábio Ferreira"/><br /><sub><b>Fábio Ferreira</b></sub></a><br /><a href="#plugin-facferreira" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://buffetitservices.ch"><img src="https://avatars.githubusercontent.com/u/73933252?v=4?s=100" width="100px;" alt="Florin Buffet"/><br /><sub><b>Florin Buffet</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=FlorinBuffet" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Owlcept"><img src="https://avatars.githubusercontent.com/u/67299472?v=4?s=100" width="100px;" alt="Drew Lewis"/><br /><sub><b>Drew Lewis</b></sub></a><br /><a href="#plugin-Owlcept" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bendersej.com"><img src="https://avatars.githubusercontent.com/u/10613140?v=4?s=100" width="100px;" alt="Benjamin André-Micolon"/><br /><sub><b>Benjamin André-Micolon</b></sub></a><br /><a href="#plugin-bendersej" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DGurskij"><img src="https://avatars.githubusercontent.com/u/26856659?v=4?s=100" width="100px;" alt="Denis Gurskij"/><br /><sub><b>Denis Gurskij</b></sub></a><br /><a href="#plugin-DGurskij" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://neferlopez.com"><img src="https://avatars.githubusercontent.com/u/11466949?v=4?s=100" width="100px;" alt="Nefer Lopez"/><br /><sub><b>Nefer Lopez</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=thatguynef" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fardeenpanjwani-codeglo"><img src="https://avatars.githubusercontent.com/u/141914308?v=4?s=100" width="100px;" alt="fardeenpanjwani-codeglo"/><br /><sub><b>fardeenpanjwani-codeglo</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=fardeenpanjwani-codeglo" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/landonmoir"><img src="https://avatars.githubusercontent.com/u/29764668?v=4?s=100" width="100px;" alt="Landon Moir"/><br /><sub><b>Landon Moir</b></sub></a><br /><a href="#plugin-landonmoir" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://lightspeed-it.nl/"><img src="https://avatars.githubusercontent.com/u/22002313?v=4?s=100" width="100px;" alt="Diego Nijboer"/><br /><sub><b>Diego Nijboer</b></sub></a><br /><a href="#plugin-lldiegon" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://ductan.me/"><img src="https://avatars.githubusercontent.com/u/24206229?v=4?s=100" width="100px;" alt="Tân Một Nắng"/><br /><sub><b>Tân Một Nắng</b></sub></a><br /><a href="#plugin-tanoggy" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://geteduca.com"><img src="https://avatars.githubusercontent.com/u/838788?v=4?s=100" width="100px;" alt="Gavin Foley"/><br /><sub><b>Gavin Foley</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=GFoley83" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dtrautwein.eu"><img src="https://avatars.githubusercontent.com/u/11836793?v=4?s=100" width="100px;" alt="Dennis Trautwein"/><br /><sub><b>Dennis Trautwein</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Adennis-tra" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/inspiredclick"><img src="https://avatars.githubusercontent.com/u/1548613?v=4?s=100" width="100px;" alt="Andrew Rosenblatt"/><br /><sub><b>Andrew Rosenblatt</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Ainspiredclick" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/w95"><img src="https://avatars.githubusercontent.com/u/6433752?v=4?s=100" width="100px;" alt="rika"/><br /><sub><b>rika</b></sub></a><br /><a href="#plugin-w95" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cyrilselasi"><img src="https://avatars.githubusercontent.com/u/7190330?v=4?s=100" width="100px;" alt="Cyril Selasi"/><br /><sub><b>Cyril Selasi</b></sub></a><br /><a href="#plugin-cyrilselasi" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://nijfranck.github.io"><img src="https://avatars.githubusercontent.com/u/9940307?v=4?s=100" width="100px;" alt="Franck Nijimbere"/><br /><sub><b>Franck Nijimbere</b></sub></a><br /><a href="#plugin-nijfranck" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alerdenisov"><img src="https://avatars.githubusercontent.com/u/3899837?v=4?s=100" width="100px;" alt="Aleksandr Denisov"/><br /><sub><b>Aleksandr Denisov</b></sub></a><br /><a href="#plugin-alerdenisov" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rbnswartz"><img src="https://avatars.githubusercontent.com/u/724704?v=4?s=100" width="100px;" alt="Reuben Swartz"/><br /><sub><b>Reuben Swartz</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=rbnswartz" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://lupianezjose.com"><img src="https://avatars.githubusercontent.com/u/4380557?v=4?s=100" width="100px;" alt="joselupianez"/><br /><sub><b>joselupianez</b></sub></a><br /><a href="#plugin-joselupianez" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.zidoary.com"><img src="https://avatars.githubusercontent.com/u/24081860?v=4?s=100" width="100px;" alt="Awais Manzoor"/><br /><sub><b>Awais Manzoor</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Aawais000" title="Bug reports">🐛</a> <a href="https://github.com/activepieces/activepieces/commits?author=awais000" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andchir"><img src="https://avatars.githubusercontent.com/u/6392311?v=4?s=100" width="100px;" alt="Andrei"/><br /><sub><b>Andrei</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Aandchir" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/derbbre"><img src="https://avatars.githubusercontent.com/u/281843?v=4?s=100" width="100px;" alt="derbbre"/><br /><sub><b>derbbre</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=derbbre" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/maor-rozenfeld"><img src="https://avatars.githubusercontent.com/u/49363375?v=4?s=100" width="100px;" alt="Maor Rozenfeld"/><br /><sub><b>Maor Rozenfeld</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=maor-rozenfeld" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/miqh"><img src="https://avatars.githubusercontent.com/u/43751307?v=4?s=100" width="100px;" alt="Michael Huynh"/><br /><sub><b>Michael Huynh</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=miqh" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fdundjer"><img src="https://avatars.githubusercontent.com/u/17405319?v=4?s=100" width="100px;" alt="Filip Dunđer"/><br /><sub><b>Filip Dunđer</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=fdundjer" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://donthorp.net"><img src="https://avatars.githubusercontent.com/u/8629?v=4?s=100" width="100px;" alt="Don Thorp"/><br /><sub><b>Don Thorp</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=donthorp" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://joeworkman.net"><img src="https://avatars.githubusercontent.com/u/225628?v=4?s=100" width="100px;" alt="Joe Workman"/><br /><sub><b>Joe Workman</b></sub></a><br /><a href="#plugin-joeworkman" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Autumnlight02"><img src="https://avatars.githubusercontent.com/u/68244453?v=4?s=100" width="100px;" alt="Aykut Akgün"/><br /><sub><b>Aykut Akgün</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=Autumnlight02" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yann120"><img src="https://avatars.githubusercontent.com/u/10012140?v=4?s=100" width="100px;" alt="Yann Petitjean"/><br /><sub><b>Yann Petitjean</b></sub></a><br /><a href="#plugin-yann120" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/activepieces/activepieces/issues?q=author%3Ayann120" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pfernandez98"><img src="https://avatars.githubusercontent.com/u/54374282?v=4?s=100" width="100px;" alt="pfernandez98"/><br /><sub><b>pfernandez98</b></sub></a><br /><a href="#plugin-pfernandez98" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://denieler.com"><img src="https://avatars.githubusercontent.com/u/2836281?v=4?s=100" width="100px;" alt="Daniel O."/><br /><sub><b>Daniel O.</b></sub></a><br /><a href="#plugin-denieler" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://myh.tw"><img src="https://avatars.githubusercontent.com/u/12458706?v=4?s=100" width="100px;" alt="Meng-Yuan Huang"/><br /><sub><b>Meng-Yuan Huang</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=MrMYHuang" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bigfluffycookie"><img src="https://avatars.githubusercontent.com/u/54935347?v=4?s=100" width="100px;" alt="Leyla"/><br /><sub><b>Leyla</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Abigfluffycookie" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://i-nithin.netlify.app/"><img src="https://avatars.githubusercontent.com/u/97078688?v=4?s=100" width="100px;" alt="i-nithin"/><br /><sub><b>i-nithin</b></sub></a><br /><a href="#plugin-i-nithin" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://lawrenceli.me"><img src="https://avatars.githubusercontent.com/u/24540598?v=4?s=100" width="100px;" alt="la3rence"/><br /><sub><b>la3rence</b></sub></a><br /><a href="#plugin-la3rence" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://dennisrongo.com"><img src="https://avatars.githubusercontent.com/u/51771021?v=4?s=100" width="100px;" alt="Dennis Rongo"/><br /><sub><b>Dennis Rongo</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Adennisrongo" title="Bug reports">🐛</a> <a href="#plugin-dennisrongo" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kartikmehta8"><img src="https://avatars.githubusercontent.com/u/77505989?v=4?s=100" width="100px;" alt="Kartik Mehta"/><br /><sub><b>Kartik Mehta</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=kartikmehta8" title="Documentation">📖</a> <a href="https://github.com/activepieces/activepieces/commits?author=kartikmehta8" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zakher.me"><img src="https://avatars.githubusercontent.com/u/46135573?v=4?s=100" width="100px;" alt="Zakher Masri"/><br /><sub><b>Zakher Masri</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=zaaakher" title="Documentation">📖</a> <a href="https://github.com/activepieces/activepieces/commits?author=zaaakher" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AbdullahBitar"><img src="https://avatars.githubusercontent.com/u/122645579?v=4?s=100" width="100px;" alt="AbdullahBitar"/><br /><sub><b>AbdullahBitar</b></sub></a><br /><a href="#plugin-AbdullahBitar" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mariomeyer"><img src="https://avatars.githubusercontent.com/u/867650?v=4?s=100" width="100px;" alt="Mario Meyer"/><br /><sub><b>Mario Meyer</b></sub></a><br /><a href="#plugin-mariomeyer" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/karimkhaleel"><img src="https://avatars.githubusercontent.com/u/94621779?v=4?s=100" width="100px;" alt="Karim Khaleel"/><br /><sub><b>Karim Khaleel</b></sub></a><br /><a href="#plugin-karimkhaleel" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CPonchet"><img src="https://avatars.githubusercontent.com/u/40756925?v=4?s=100" width="100px;" alt="CPonchet"/><br /><sub><b>CPonchet</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3ACPonchet" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AdamSelene"><img src="https://avatars.githubusercontent.com/u/79495?v=4?s=100" width="100px;" alt="Olivier Sambourg"/><br /><sub><b>Olivier Sambourg</b></sub></a><br /><a href="#plugin-AdamSelene" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Verlich"><img src="https://avatars.githubusercontent.com/u/30838131?v=4?s=100" width="100px;" alt="Ahmad(Ed)"/><br /><sub><b>Ahmad(Ed)</b></sub></a><br /><a href="#plugin-Verlich" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/leenmashni"><img src="https://avatars.githubusercontent.com/u/102361544?v=4?s=100" width="100px;" alt="leenmashni"/><br /><sub><b>leenmashni</b></sub></a><br /><a href="#plugin-leenmashni" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AliasKingsWorth"><img src="https://avatars.githubusercontent.com/u/47811610?v=4?s=100" width="100px;" alt="M Abdul Rauf"/><br /><sub><b>M Abdul Rauf</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=AliasKingsWorth" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vbarrier"><img src="https://avatars.githubusercontent.com/u/446808?v=4?s=100" width="100px;" alt="Vincent Barrier"/><br /><sub><b>Vincent Barrier</b></sub></a><br /><a href="#plugin-vbarrier" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://johnmark.dev"><img src="https://avatars.githubusercontent.com/u/65794951?v=4?s=100" width="100px;" alt="John"/><br /><sub><b>John</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=jmgb27" title="Code">💻</a> <a href="#plugin-jmgb27" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://joost.blog/"><img src="https://avatars.githubusercontent.com/u/487629?v=4?s=100" width="100px;" alt="Joost de Valk"/><br /><sub><b>Joost de Valk</b></sub></a><br /><a href="#plugin-jdevalk" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/nyamkamunhjin/"><img src="https://avatars.githubusercontent.com/u/44439626?v=4?s=100" width="100px;" alt="MJ"/><br /><sub><b>MJ</b></sub></a><br /><a href="#plugin-nyamkamunhjin" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/shravankshenoy"><img src="https://avatars.githubusercontent.com/u/29670290?v=4?s=100" width="100px;" alt="ShravanShenoy"/><br /><sub><b>ShravanShenoy</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=shravankshenoy" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://jonkristian.no"><img src="https://avatars.githubusercontent.com/u/13219?v=4?s=100" width="100px;" alt="Jon Kristian"/><br /><sub><b>Jon Kristian</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=jonkristian" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cr0fters"><img src="https://avatars.githubusercontent.com/u/1754858?v=4?s=100" width="100px;" alt="cr0fters"/><br /><sub><b>cr0fters</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Acr0fters" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bibek-timsina.com.np/"><img src="https://avatars.githubusercontent.com/u/29589003?v=4?s=100" width="100px;" alt="Bibek Timsina"/><br /><sub><b>Bibek Timsina</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Abimsina" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/szepeviktor/debian-server-tools/blob/master/CV.md"><img src="https://avatars.githubusercontent.com/u/952007?v=4?s=100" width="100px;" alt="Viktor Szépe"/><br /><sub><b>Viktor Szépe</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=szepeviktor" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rendyt1"><img src="https://avatars.githubusercontent.com/u/38492810?v=4?s=100" width="100px;" alt="Rendy Tan"/><br /><sub><b>Rendy Tan</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=rendyt1" title="Documentation">📖</a> <a href="#plugin-rendyt1" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://islamaf.github.io"><img src="https://avatars.githubusercontent.com/u/44944648?v=4?s=100" width="100px;" alt="Islam Abdelfattah"/><br /><sub><b>Islam Abdelfattah</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Aislamaf" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/uniqueeest"><img src="https://avatars.githubusercontent.com/u/123538138?v=4?s=100" width="100px;" alt="Yoonjae Choi"/><br /><sub><b>Yoonjae Choi</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=uniqueeest" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://javix64.com"><img src="https://avatars.githubusercontent.com/u/58471170?v=4?s=100" width="100px;" alt="Javier HM"/><br /><sub><b>Javier HM</b></sub></a><br /><a href="#plugin-javix64" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://farag.tech"><img src="https://avatars.githubusercontent.com/u/50884619?v=4?s=100" width="100px;" alt="Mohamed Hassan"/><br /><sub><b>Mohamed Hassan</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3AMohamedHassan499" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.coasy.com/"><img src="https://avatars.githubusercontent.com/u/17610709?v=4?s=100" width="100px;" alt="Christian Schab"/><br /><sub><b>Christian Schab</b></sub></a><br /><a href="#plugin-christian-schab" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.gamespecifications.com/"><img src="https://avatars.githubusercontent.com/u/37847256?v=4?s=100" width="100px;" alt="Pratik Kinage"/><br /><sub><b>Pratik Kinage</b></sub></a><br /><a href="#plugin-thirstycode" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LevwTech"><img src="https://avatars.githubusercontent.com/u/69399787?v=4?s=100" width="100px;" alt="Abdelrahman Mostafa "/><br /><sub><b>Abdelrahman Mostafa </b></sub></a><br /><a href="#plugin-LevwTech" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HamzaZagha"><img src="https://avatars.githubusercontent.com/u/45468866?v=4?s=100" width="100px;" alt="Hamza Zagha"/><br /><sub><b>Hamza Zagha</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3AHamzaZagha" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://founderblocks.io/"><img src="https://avatars.githubusercontent.com/u/88160672?v=4?s=100" width="100px;" alt="Lasse Schuirmann"/><br /><sub><b>Lasse Schuirmann</b></sub></a><br /><a href="#plugin-founderblocks-sils" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/cyril_duchon_doris"><img src="https://avatars.githubusercontent.com/u/7388889?v=4?s=100" width="100px;" alt="Cyril Duchon-Doris"/><br /><sub><b>Cyril Duchon-Doris</b></sub></a><br /><a href="#plugin-Startouf" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Javiink"><img src="https://avatars.githubusercontent.com/u/43996484?v=4?s=100" width="100px;" alt="Javiink"/><br /><sub><b>Javiink</b></sub></a><br /><a href="#plugin-Javiink" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hharchani"><img src="https://avatars.githubusercontent.com/u/6430611?v=4?s=100" width="100px;" alt="Harshit Harchani"/><br /><sub><b>Harshit Harchani</b></sub></a><br /><a href="#plugin-hharchani" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrAkber"><img src="https://avatars.githubusercontent.com/u/170118042?v=4?s=100" width="100px;" alt="MrAkber"/><br /><sub><b>MrAkber</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=MrAkber" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marek-slavicek"><img src="https://avatars.githubusercontent.com/u/136325104?v=4?s=100" width="100px;" alt="marek-slavicek"/><br /><sub><b>marek-slavicek</b></sub></a><br /><a href="#plugin-marek-slavicek" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hugh-codes"><img src="https://avatars.githubusercontent.com/u/166336705?v=4?s=100" width="100px;" alt="hugh-codes"/><br /><sub><b>hugh-codes</b></sub></a><br /><a href="#plugin-hugh-codes" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alewis001"><img src="https://avatars.githubusercontent.com/u/3482446?v=4?s=100" width="100px;" alt="Alex Lewis"/><br /><sub><b>Alex Lewis</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Aalewis001" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://yual.in"><img src="https://avatars.githubusercontent.com/u/21105863?v=4?s=100" width="100px;" alt="Yuanlin Lin"/><br /><sub><b>Yuanlin Lin</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=yuaanlin" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://klo.dev"><img src="https://avatars.githubusercontent.com/u/96867907?v=4?s=100" width="100px;" alt="Ala Shiban"/><br /><sub><b>Ala Shiban</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=AlaShibanAtKlo" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://hamedsh.medium.com"><img src="https://avatars.githubusercontent.com/u/6043214?v=4?s=100" width="100px;" alt="hamsh"/><br /><sub><b>hamsh</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=hamedsh" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.anne-mariel.com/"><img src="https://avatars.githubusercontent.com/u/77142075?v=4?s=100" width="100px;" alt="Anne Mariel Catapang"/><br /><sub><b>Anne Mariel Catapang</b></sub></a><br /><a href="#plugin-AnneMariel95" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hi.carlogino.com"><img src="https://avatars.githubusercontent.com/u/19299524?v=4?s=100" width="100px;" alt="Carlo Gino Catapang"/><br /><sub><b>Carlo Gino Catapang</b></sub></a><br /><a href="#plugin-codegino" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/drona2938"><img src="https://avatars.githubusercontent.com/u/34496554?v=4?s=100" width="100px;" alt="Aditya Rathore"/><br /><sub><b>Aditya Rathore</b></sub></a><br /><a href="#plugin-drona2938" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coderbob2"><img src="https://avatars.githubusercontent.com/u/47177246?v=4?s=100" width="100px;" alt="coderbob2"/><br /><sub><b>coderbob2</b></sub></a><br /><a href="#plugin-coderbob2" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://raamyy.netlify.app"><img src="https://avatars.githubusercontent.com/u/29176293?v=4?s=100" width="100px;" alt="Ramy Gamal"/><br /><sub><b>Ramy Gamal</b></sub></a><br /><a href="#plugin-Raamyy" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://alexandrudanpop.dev/"><img src="https://avatars.githubusercontent.com/u/15979292?v=4?s=100" width="100px;" alt="Alexandru-Dan Pop"/><br /><sub><b>Alexandru-Dan Pop</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=alexandrudanpop" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Trayshmhirk"><img src="https://avatars.githubusercontent.com/u/112286458?v=4?s=100" width="100px;" alt="Frank Micheal "/><br /><sub><b>Frank Micheal </b></sub></a><br /><a href="#plugin-Trayshmhirk" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/emmanuel-ferdman"><img src="https://avatars.githubusercontent.com/u/35470921?v=4?s=100" width="100px;" alt="Emmanuel Ferdman"/><br /><sub><b>Emmanuel Ferdman</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=emmanuel-ferdman" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sany2407"><img src="https://avatars.githubusercontent.com/u/179091674?v=4?s=100" width="100px;" alt="Sany A"/><br /><sub><b>Sany A</b></sub></a><br /><a href="#plugin-sany2407" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://swimburger.net"><img src="https://avatars.githubusercontent.com/u/3382717?v=4?s=100" width="100px;" alt="Niels Swimberghe"/><br /><sub><b>Niels Swimberghe</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3ASwimburger" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lostinbug"><img src="https://avatars.githubusercontent.com/u/157452389?v=4?s=100" width="100px;" alt="lostinbug"/><br /><sub><b>lostinbug</b></sub></a><br /><a href="#plugin-lostinbug" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gushkool"><img src="https://avatars.githubusercontent.com/u/64713308?v=4?s=100" width="100px;" alt="gushkool"/><br /><sub><b>gushkool</b></sub></a><br /><a href="#plugin-gushkool" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/omarsayed"><img src="https://avatars.githubusercontent.com/u/3813045?v=4?s=100" width="100px;" alt="Omar Sayed"/><br /><sub><b>Omar Sayed</b></sub></a><br /><a href="#plugin-OmarSayed" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rSnapkoOpenOps"><img src="https://avatars.githubusercontent.com/u/179845343?v=4?s=100" width="100px;" alt="rSnapkoOpenOps"/><br /><sub><b>rSnapkoOpenOps</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3ArSnapkoOpenOps" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ahronshor"><img src="https://avatars.githubusercontent.com/u/25138831?v=4?s=100" width="100px;" alt="ahronshor"/><br /><sub><b>ahronshor</b></sub></a><br /><a href="#plugin-ahronshor" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cezudas"><img src="https://avatars.githubusercontent.com/u/3786138?v=4?s=100" width="100px;" alt="Cezar"/><br /><sub><b>Cezar</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Acezudas" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geekyme-fsmk"><img src="https://avatars.githubusercontent.com/u/100678833?v=4?s=100" width="100px;" alt="Shawn Lim"/><br /><sub><b>Shawn Lim</b></sub></a><br /><a href="#plugin-geekyme-fsmk" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://shawn.storyline.io/"><img src="https://avatars.githubusercontent.com/u/977460?v=4?s=100" width="100px;" alt="Shawn Lim"/><br /><sub><b>Shawn Lim</b></sub></a><br /><a href="#plugin-geekyme" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pavloDeshko"><img src="https://avatars.githubusercontent.com/u/27104046?v=4?s=100" width="100px;" alt="pavloDeshko"/><br /><sub><b>pavloDeshko</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3ApavloDeshko" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/liuhuapiaoyuan"><img src="https://avatars.githubusercontent.com/u/8020726?v=4?s=100" width="100px;" alt="abc"/><br /><sub><b>abc</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=liuhuapiaoyuan" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/manojkum-d"><img src="https://avatars.githubusercontent.com/u/141437046?v=4?s=100" width="100px;" alt="manoj kumar d"/><br /><sub><b>manoj kumar d</b></sub></a><br /><a href="#plugin-manojkum-d" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/felifluid"><img src="https://avatars.githubusercontent.com/u/59516203?v=4?s=100" width="100px;" alt="Feli"/><br /><sub><b>Feli</b></sub></a><br /><a href="#plugin-felifluid" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mordonez"><img src="https://avatars.githubusercontent.com/u/293837?v=4?s=100" width="100px;" alt="Miguel"/><br /><sub><b>Miguel</b></sub></a><br /><a href="#plugin-mordonez" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dev-instasent"><img src="https://avatars.githubusercontent.com/u/116744368?v=4?s=100" width="100px;" alt="Instasent DEV"/><br /><sub><b>Instasent DEV</b></sub></a><br /><a href="#plugin-dev-instasent" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/matthieu-lombard"><img src="https://avatars.githubusercontent.com/u/33624489?v=4?s=100" width="100px;" alt="Matthieu Lombard"/><br /><sub><b>Matthieu Lombard</b></sub></a><br /><a href="#plugin-matthieu-lombard" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/beyondlevi"><img src="https://avatars.githubusercontent.com/u/57486338?v=4?s=100" width="100px;" alt="beyondlevi"/><br /><sub><b>beyondlevi</b></sub></a><br /><a href="#plugin-beyondlevi" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://rafal.fyi"><img src="https://avatars.githubusercontent.com/u/10667346?v=4?s=100" width="100px;" alt="Rafal Zawadzki"/><br /><sub><b>Rafal Zawadzki</b></sub></a><br /><a href="#plugin-rafalzawadzki" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.pdfmonkey.io/"><img src="https://avatars.githubusercontent.com/u/119303?v=4?s=100" width="100px;" alt="Simon Courtois"/><br /><sub><b>Simon Courtois</b></sub></a><br /><a href="#plugin-simonc" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alegria-solutions"><img src="https://avatars.githubusercontent.com/u/124846022?v=4?s=100" width="100px;" alt="alegria-solutions"/><br /><sub><b>alegria-solutions</b></sub></a><br /><a href="#plugin-alegria-solutions" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/D-Rowe-FS"><img src="https://avatars.githubusercontent.com/u/142934784?v=4?s=100" width="100px;" alt="D-Rowe-FS"/><br /><sub><b>D-Rowe-FS</b></sub></a><br /><a href="#plugin-D-Rowe-FS" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChineseHamberger"><img src="https://avatars.githubusercontent.com/u/101547635?v=4?s=100" width="100px;" alt="张晟杰"/><br /><sub><b>张晟杰</b></sub></a><br /><a href="#plugin-ChineseHamberger" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://codesign.rf.gd"><img src="https://avatars.githubusercontent.com/u/72438085?v=4?s=100" width="100px;" alt="Ashot"/><br /><sub><b>Ashot</b></sub></a><br /><a href="#plugin-AshotZaqoyan" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amrabuaza"><img src="https://avatars.githubusercontent.com/u/30035105?v=4?s=100" width="100px;" alt="Amr Abu Aza"/><br /><sub><b>Amr Abu Aza</b></sub></a><br /><a href="#plugin-amrabuaza" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://johng.io"><img src="https://avatars.githubusercontent.com/u/9030780?v=4?s=100" width="100px;" alt="John Goodliff"/><br /><sub><b>John Goodliff</b></sub></a><br /><a href="#plugin-jerboa88" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DiwashDev"><img src="https://avatars.githubusercontent.com/u/182864159?v=4?s=100" width="100px;" alt="Diwash Dev"/><br /><sub><b>Diwash Dev</b></sub></a><br /><a href="#plugin-DiwashDev" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.seven.io"><img src="https://avatars.githubusercontent.com/u/12965261?v=4?s=100" width="100px;" alt="André"/><br /><sub><b>André</b></sub></a><br /><a href="#plugin-matthiez" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loudotdigital"><img src="https://avatars.githubusercontent.com/u/7611772?v=4?s=100" width="100px;" alt="Lou | Digital Marketing"/><br /><sub><b>Lou | Digital Marketing</b></sub></a><br /><a href="#plugin-loudotdigital" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/maarteNNNN"><img src="https://avatars.githubusercontent.com/u/14275291?v=4?s=100" width="100px;" alt="Maarten Coppens"/><br /><sub><b>Maarten Coppens</b></sub></a><br /><a href="#plugin-maarteNNNN" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mahmuthamet"><img src="https://avatars.githubusercontent.com/u/90776946?v=4?s=100" width="100px;" alt="Mahmoud Hamed"/><br /><sub><b>Mahmoud Hamed</b></sub></a><br /><a href="#plugin-mahmuthamet" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dammaretz.com"><img src="https://avatars.githubusercontent.com/u/14098167?v=4?s=100" width="100px;" alt="Theo Dammaretz"/><br /><sub><b>Theo Dammaretz</b></sub></a><br /><a href="#plugin-Blightwidow" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/s31w4n"><img src="https://avatars.githubusercontent.com/u/63353528?v=4?s=100" width="100px;" alt="s31w4n"/><br /><sub><b>s31w4n</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=s31w4n" title="Documentation">📖</a> <a href="https://github.com/activepieces/activepieces/commits?author=s31w4n" title="Code">💻</a> <a href="#plugin-s31w4n" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://kallabot.com"><img src="https://avatars.githubusercontent.com/u/94991678?v=4?s=100" width="100px;" alt="Abdul Rahman"/><br /><sub><b>Abdul Rahman</b></sub></a><br /><a href="#plugin-abdulrahmanmajid" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coat"><img src="https://avatars.githubusercontent.com/u/1661?v=4?s=100" width="100px;" alt="Kent Smith"/><br /><sub><b>Kent Smith</b></sub></a><br /><a href="#plugin-coat" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ArvindEnvoy"><img src="https://avatars.githubusercontent.com/u/25014185?v=4?s=100" width="100px;" alt="Arvind Ramesh"/><br /><sub><b>Arvind Ramesh</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=ArvindEnvoy" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/valentin-mourtialon"><img src="https://avatars.githubusercontent.com/u/88686764?v=4?s=100" width="100px;" alt="valentin-mourtialon"/><br /><sub><b>valentin-mourtialon</b></sub></a><br /><a href="#plugin-valentin-mourtialon" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/psgpsg16"><img src="https://avatars.githubusercontent.com/u/188385621?v=4?s=100" width="100px;" alt="psgpsg16"/><br /><sub><b>psgpsg16</b></sub></a><br /><a href="#plugin-psgpsg16" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mariiawidrpay"><img src="https://avatars.githubusercontent.com/u/110456120?v=4?s=100" width="100px;" alt="Mariia Shyn"/><br /><sub><b>Mariia Shyn</b></sub></a><br /><a href="#plugin-mariiawidrpay" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/joshuaheslin"><img src="https://avatars.githubusercontent.com/u/48037470?v=4?s=100" width="100px;" alt="Joshua Heslin"/><br /><sub><b>Joshua Heslin</b></sub></a><br /><a href="#plugin-joshuaheslin" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ahmad-swanblocks"><img src="https://avatars.githubusercontent.com/u/165162455?v=4?s=100" width="100px;" alt="Ahmad"/><br /><sub><b>Ahmad</b></sub></a><br /><a href="#plugin-ahmad-swanblocks" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/danielpoonwj"><img src="https://avatars.githubusercontent.com/u/17039704?v=4?s=100" width="100px;" alt="Daniel Poon"/><br /><sub><b>Daniel Poon</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=danielpoonwj" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kevinyu-alan"><img src="https://avatars.githubusercontent.com/u/198612963?v=4?s=100" width="100px;" alt="Kévin Yu"/><br /><sub><b>Kévin Yu</b></sub></a><br /><a href="#plugin-Kevinyu-alan" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/flex-yeongeun"><img src="https://avatars.githubusercontent.com/u/186537288?v=4?s=100" width="100px;" alt="노영은"/><br /><sub><b>노영은</b></sub></a><br /><a href="#plugin-flex-yeongeun" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/reemayoush"><img src="https://avatars.githubusercontent.com/u/168414383?v=4?s=100" width="100px;" alt="reemayoush"/><br /><sub><b>reemayoush</b></sub></a><br /><a href="#plugin-reemayoush" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/briceflaceliere"><img src="https://avatars.githubusercontent.com/u/5811531?v=4?s=100" width="100px;" alt="Brice"/><br /><sub><b>Brice</b></sub></a><br /><a href="#security-briceflaceliere" title="Security">🛡️</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://mg-wunna.github.io/mg-wunna/"><img src="https://avatars.githubusercontent.com/u/63114419?v=4?s=100" width="100px;" alt="Mg Wunna"/><br /><sub><b>Mg Wunna</b></sub></a><br /><a href="#plugin-mg-wunna" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/harikrishnanum/"><img src="https://avatars.githubusercontent.com/u/61736905?v=4?s=100" width="100px;" alt="Harikrishnan U M"/><br /><sub><b>Harikrishnan U M</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/issues?q=author%3Ahakrsh" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/perrine-pullicino-alan"><img src="https://avatars.githubusercontent.com/u/143406842?v=4?s=100" width="100px;" alt="perrine-pullicino-alan"/><br /><sub><b>perrine-pullicino-alan</b></sub></a><br /><a href="#plugin-perrine-pullicino-alan" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kaovilai.pw"><img src="https://avatars.githubusercontent.com/u/11228024?v=4?s=100" width="100px;" alt="Tiger Kaovilai"/><br /><sub><b>Tiger Kaovilai</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=kaovilai" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CarefulGuru"><img src="https://avatars.githubusercontent.com/u/141072854?v=4?s=100" width="100px;" alt="CarefulGuru"/><br /><sub><b>CarefulGuru</b></sub></a><br /><a href="#plugin-CarefulGuru" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AnkitSharmaOnGithub"><img src="https://avatars.githubusercontent.com/u/53289186?v=4?s=100" width="100px;" alt="Ankit Kumar Sharma"/><br /><sub><b>Ankit Kumar Sharma</b></sub></a><br /><a href="#plugin-AnkitSharmaOnGithub" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nhnansari"><img src="https://avatars.githubusercontent.com/u/116841234?v=4?s=100" width="100px;" alt="Naeem Hassan"/><br /><sub><b>Naeem Hassan</b></sub></a><br /><a href="#plugin-nhnansari" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://timpetricola.com"><img src="https://avatars.githubusercontent.com/u/674084?v=4?s=100" width="100px;" alt="Tim Petricola"/><br /><sub><b>Tim Petricola</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=TimPetricola" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amaan-ai20"><img src="https://avatars.githubusercontent.com/u/188329978?v=4?s=100" width="100px;" alt="Amaan"/><br /><sub><b>Amaan</b></sub></a><br /><a href="#plugin-amaan-ai20" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.marcllopartriera.com"><img src="https://avatars.githubusercontent.com/u/1257083?v=4?s=100" width="100px;" alt="Marc Llopart"/><br /><sub><b>Marc Llopart</b></sub></a><br /><a href="#plugin-mllopart" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/onyedikachi-david"><img src="https://avatars.githubusercontent.com/u/51977119?v=4?s=100" width="100px;" alt="David Anyatonwu"/><br /><sub><b>David Anyatonwu</b></sub></a><br /><a href="#plugin-onyedikachi-david" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://huzef.com"><img src="https://avatars.githubusercontent.com/u/62795688?v=4?s=100" width="100px;" alt="neo773"/><br /><sub><b>neo773</b></sub></a><br /><a href="#plugin-neo773" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Daniel-Klippa"><img src="https://avatars.githubusercontent.com/u/207180643?v=4?s=100" width="100px;" alt="Daniel-Klippa"/><br /><sub><b>Daniel-Klippa</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=Daniel-Klippa" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/krushnarout"><img src="https://avatars.githubusercontent.com/u/129386740?v=4?s=100" width="100px;" alt="Krushna Kanta Rout"/><br /><sub><b>Krushna Kanta Rout</b></sub></a><br /><a href="#plugin-krushnarout" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.snimesh.com"><img src="https://avatars.githubusercontent.com/u/12984120?v=4?s=100" width="100px;" alt="Nimesh Solanki"/><br /><sub><b>Nimesh Solanki</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=nish17" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rimjhimyadav"><img src="https://avatars.githubusercontent.com/u/187646079?v=4?s=100" width="100px;" alt="Rimjhim Yadav"/><br /><sub><b>Rimjhim Yadav</b></sub></a><br /><a href="#plugin-rimjhimyadav" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gs03-dev"><img src="https://avatars.githubusercontent.com/u/70076620?v=4?s=100" width="100px;" alt="gs03"/><br /><sub><b>gs03</b></sub></a><br /><a href="#plugin-gs03-dev" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kunal-Darekar"><img src="https://avatars.githubusercontent.com/u/150500530?v=4?s=100" width="100px;" alt="Kunal Darekar"/><br /><sub><b>Kunal Darekar</b></sub></a><br /><a href="#plugin-Kunal-Darekar" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Sanket6652"><img src="https://avatars.githubusercontent.com/u/119039046?v=4?s=100" width="100px;" alt="Sanket6652"/><br /><sub><b>Sanket6652</b></sub></a><br /><a href="#plugin-Sanket6652" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ani-4x"><img src="https://avatars.githubusercontent.com/u/174266491?v=4?s=100" width="100px;" alt="Animesh"/><br /><sub><b>Animesh</b></sub></a><br /><a href="#plugin-Ani-4x" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://tarvent.com"><img src="https://avatars.githubusercontent.com/u/13419128?v=4?s=100" width="100px;" alt="Derek Johnson"/><br /><sub><b>Derek Johnson</b></sub></a><br /><a href="#plugin-DerekJDev" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mamiefurax"><img src="https://avatars.githubusercontent.com/u/3955802?v=4?s=100" width="100px;" alt="MamieFurax"/><br /><sub><b>MamieFurax</b></sub></a><br /><a href="#plugin-mamiefurax" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jadhavharshh"><img src="https://avatars.githubusercontent.com/u/182950168?v=4?s=100" width="100px;" alt="Harsh Jadhav"/><br /><sub><b>Harsh Jadhav</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=jadhavharshh" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/lucaslima_souza"><img src="https://avatars.githubusercontent.com/u/1576846?v=4?s=100" width="100px;" alt="Lucas Lima de Souza"/><br /><sub><b>Lucas Lima de Souza</b></sub></a><br /><a href="#plugin-lucaslimasouza" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BenjaminAlan"><img src="https://avatars.githubusercontent.com/u/42831606?v=4?s=100" width="100px;" alt="Benjamin Benouarka"/><br /><sub><b>Benjamin Benouarka</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=BenjaminAlan" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/chris-wu/"><img src="https://avatars.githubusercontent.com/u/4491213?v=4?s=100" width="100px;" alt="Chris Wu"/><br /><sub><b>Chris Wu</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=cjwooo" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/prasanna2000-max"><img src="https://avatars.githubusercontent.com/u/61037314?v=4?s=100" width="100px;" alt="Prasanna R"/><br /><sub><b>Prasanna R</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=prasanna2000-max" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AdminCraftHD"><img src="https://avatars.githubusercontent.com/u/33310274?v=4?s=100" width="100px;" alt="AdminCraftHD"/><br /><sub><b>AdminCraftHD</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=AdminCraftHD" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://tumrabertworld.vercel.app/resume"><img src="https://avatars.githubusercontent.com/u/38305310?v=4?s=100" width="100px;" alt="Tanakit Phentun"/><br /><sub><b>Tanakit Phentun</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=tumrabert" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marapper"><img src="https://avatars.githubusercontent.com/u/1397054?v=4?s=100" width="100px;" alt="Sergey Bondar"/><br /><sub><b>Sergey Bondar</b></sub></a><br /><a href="#plugin-marapper" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://yusufcirak.net"><img src="https://avatars.githubusercontent.com/u/81169996?v=4?s=100" width="100px;" alt="Yusuf Çırak"/><br /><sub><b>Yusuf Çırak</b></sub></a><br /><a href="#plugin-yusuf-cirak" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://ezhil.dev"><img src="https://avatars.githubusercontent.com/u/103899034?v=4?s=100" width="100px;" alt="Ezhil Shanmugham"/><br /><sub><b>Ezhil Shanmugham</b></sub></a><br /><a href="#plugin-ezhil56x" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sunorains"><img src="https://avatars.githubusercontent.com/u/211304820?v=4?s=100" width="100px;" alt="Anderson"/><br /><sub><b>Anderson</b></sub></a><br /><a href="#plugin-sunorains" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/calladodan"><img src="https://avatars.githubusercontent.com/u/7246416?v=4?s=100" width="100px;" alt="Daniel Callado"/><br /><sub><b>Daniel Callado</b></sub></a><br /><a href="#plugin-calladodan" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sparkybug"><img src="https://avatars.githubusercontent.com/u/52334088?v=4?s=100" width="100px;" alt="Ukaegbu Osinachi"/><br /><sub><b>Ukaegbu Osinachi</b></sub></a><br /><a href="#plugin-sparkybug" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://mavrick-portfolio.vercel.app/"><img src="https://avatars.githubusercontent.com/u/146999057?v=4?s=100" width="100px;" alt="Rishi Mondal"/><br /><sub><b>Rishi Mondal</b></sub></a><br /><a href="#plugin-MAVRICK-1" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Cloudieunnie"><img src="https://avatars.githubusercontent.com/u/178718590?v=4?s=100" width="100px;" alt="Cloudieunnie"/><br /><sub><b>Cloudieunnie</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=Cloudieunnie" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/balwant1707"><img src="https://avatars.githubusercontent.com/u/17769387?v=4?s=100" width="100px;" alt="Balwant Singh"/><br /><sub><b>Balwant Singh</b></sub></a><br /><a href="#plugin-balwant1707" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ravikiranvm"><img src="https://avatars.githubusercontent.com/u/36404296?v=4?s=100" width="100px;" alt="Ravi Kiran Vallamkonda"/><br /><sub><b>Ravi Kiran Vallamkonda</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=ravikiranvm" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/owuzo"><img src="https://avatars.githubusercontent.com/u/173556464?v=4?s=100" width="100px;" alt="Owuzo Joy"/><br /><sub><b>Owuzo Joy</b></sub></a><br /><a href="#plugin-owuzo" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/helenedurand-smet"><img src="https://avatars.githubusercontent.com/u/206527847?v=4?s=100" width="100px;" alt="helenedurand-smet"/><br /><sub><b>helenedurand-smet</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=helenedurand-smet" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nuvex-dev"><img src="https://avatars.githubusercontent.com/u/181783827?v=4?s=100" width="100px;" alt="Nuvex"/><br /><sub><b>Nuvex</b></sub></a><br /><a href="#plugin-nuvex-dev" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zebi15"><img src="https://avatars.githubusercontent.com/u/80625145?v=4?s=100" width="100px;" alt="Apostol Eusebiu"/><br /><sub><b>Apostol Eusebiu</b></sub></a><br /><a href="#plugin-Zebi15" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fortunamide"><img src="https://avatars.githubusercontent.com/u/122938302?v=4?s=100" width="100px;" alt="Fortunate"/><br /><sub><b>Fortunate</b></sub></a><br /><a href="#plugin-fortunamide" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://jaachiwrites.com"><img src="https://avatars.githubusercontent.com/u/173014495?v=4?s=100" width="100px;" alt="Jaachịmmá Anyatọnwụ"/><br /><sub><b>Jaachịmmá Anyatọnwụ</b></sub></a><br /><a href="#plugin-thejaachi" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://luizmainart.com"><img src="https://avatars.githubusercontent.com/u/55499897?v=4?s=100" width="100px;" alt="Luiz D. M. Mainart"/><br /><sub><b>Luiz D. M. Mainart</b></sub></a><br /><a href="#plugin-LuizDMM" title="Plugin/utility libraries">🔌</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/uvenkatateja"><img src="https://avatars.githubusercontent.com/u/118493739?v=4?s=100" width="100px;" alt="uvenkatateja"/><br /><sub><b>uvenkatateja</b></sub></a><br /><a href="#plugin-uvenkatateja" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://akramcodez.tech"><img src="https://avatars.githubusercontent.com/u/179671552?v=4?s=100" width="100px;" alt="SK Akram"/><br /><sub><b>SK Akram</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=akramcodez" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/im-soohyun"><img src="https://avatars.githubusercontent.com/u/127273427?v=4?s=100" width="100px;" alt="Kim SooHyun"/><br /><sub><b>Kim SooHyun</b></sub></a><br /><a href="#security-im-soohyun" title="Security">🛡️</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/srimalleswari205"><img src="https://avatars.githubusercontent.com/u/235991945?v=4?s=100" width="100px;" alt="Sri malleswari"/><br /><sub><b>Sri malleswari</b></sub></a><br /><a href="#plugin-srimalleswari205" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SinghaAnirban005"><img src="https://avatars.githubusercontent.com/u/143536290?v=4?s=100" width="100px;" alt="Anirban Singha"/><br /><sub><b>Anirban Singha</b></sub></a><br /><a href="#plugin-SinghaAnirban005" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://dania.es"><img src="https://avatars.githubusercontent.com/u/11240307?v=4?s=100" width="100px;" alt="Dania Es"/><br /><sub><b>Dania Es</b></sub></a><br /><a href="https://github.com/activepieces/activepieces/commits?author=Dania02525" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://allcontributors.org) specification.
|
||||
Contributions of any kind are welcome!
|
||||
@@ -1,39 +0,0 @@
|
||||
# Security
|
||||
|
||||
Contact: security@activepieces.com
|
||||
|
||||
Based on [https://supabase.com/.well-known/security.txt](https://supabase.com/.well-known/security.txt)
|
||||
|
||||
At Activepieces.com, we consider the security of our systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present.
|
||||
|
||||
If you discover a vulnerability, we would like to know about it so we can take steps to address it as quickly as possible. We would like to ask you to help us better protect our clients and our systems.
|
||||
|
||||
## Out of scope vulnerabilities:
|
||||
|
||||
- Clickjacking on pages with no sensitive actions.
|
||||
- Unauthenticated/logout/login CSRF.
|
||||
- Attacks requiring MITM or physical access to a user's device.
|
||||
- Any activity that could lead to the disruption of our service (DoS).
|
||||
- Content spoofing and text injection issues without showing an attack vector/without being able to modify HTML/CSS.
|
||||
- Email spoofing
|
||||
- Missing DNSSEC, CAA, CSP headers
|
||||
- Lack of Secure or HTTP only flag on non-sensitive cookies
|
||||
- Deadlinks
|
||||
|
||||
## Please do the following:
|
||||
|
||||
- E-mail your findings to [security@activepieces.com](mailto:security@activepieces.com).
|
||||
- Do not run automated scanners on our infrastructure or dashboard. If you wish to do this, contact us and we will set up a sandbox for you.
|
||||
- Do not take advantage of the vulnerability or problem you have discovered, for example by downloading more data than necessary to demonstrate the vulnerability or deleting or modifying other people's data,
|
||||
- Do not reveal the problem to others until it has been resolved,
|
||||
- Do not use attacks on physical security, social engineering, distributed denial of service, spam or applications of third parties,
|
||||
- Do provide sufficient information to reproduce the problem, so we will be able to resolve it as quickly as possible. Usually, the IP address or the URL of the affected system and a description of the vulnerability will be sufficient, but complex vulnerabilities may require further explanation.
|
||||
|
||||
## What we promise:
|
||||
|
||||
- We will respond to your report within 3 business days with our evaluation of the report and an expected resolution date,
|
||||
- If you have followed the instructions above, we will not take any legal action against you in regard to the report,
|
||||
- We will handle your report with strict confidentiality, and not pass on your personal details to third parties without your permission,
|
||||
- We will keep you informed of the progress towards resolving the problem,
|
||||
- In the public information concerning the problem reported, we will give your name as the discoverer of the problem (unless you desire otherwise), and
|
||||
- We strive to resolve all problems as quickly as possible, and we would like to play an active role in the ultimate publication on the problem after it is resolved.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.9 KiB |
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
module.exports = { extends: ['@commitlint/config-conventional'] };
|
||||
@@ -1,12 +0,0 @@
|
||||
project_id_env: CROWDIN_PROJECT_ID
|
||||
api_token_env: CROWDIN_PERSONAL_TOKEN
|
||||
base_path: .
|
||||
base_url: 'https://api.crowdin.com'
|
||||
preserve_hierarchy: 1
|
||||
files:
|
||||
- type: i18next_json
|
||||
source: packages/react-ui/public/locales/en/translation.json
|
||||
translation: /packages/react-ui/public/locales/%two_letters_code%/translation.json
|
||||
- type: json
|
||||
source: packages/pieces/**/**/src/i18n/translation.json
|
||||
translation: /packages/pieces/**/**/src/i18n/%two_letters_code%.json
|
||||
@@ -1,5 +0,0 @@
|
||||
# Ignore downloaded Helm chart dependencies
|
||||
charts/*.tgz
|
||||
|
||||
# Ignore Chart.lock file variations
|
||||
Chart.lock
|
||||
@@ -1,23 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -1,39 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: activepieces
|
||||
description: A Helm chart for Activepieces
|
||||
icon: https://cdn.activepieces.com/brand/logo.svg
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.3.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "0.71.2"
|
||||
|
||||
dependencies:
|
||||
- name: kubernetes-secret-generator
|
||||
version: "3.4.1"
|
||||
repository: "https://helm.mittwald.de"
|
||||
condition: kubernetes-secret-generator.enabled
|
||||
- name: postgresql
|
||||
version: "11.7.2"
|
||||
repository: "https://charts.bitnami.com/bitnami"
|
||||
condition: postgresql.enabled
|
||||
- name: redis
|
||||
version: "17.4.2"
|
||||
repository: "https://charts.bitnami.com/bitnami"
|
||||
condition: redis.enabled
|
||||
@@ -1 +0,0 @@
|
||||
Activepieces has been deployed successfully!
|
||||
@@ -1,62 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "activepieces.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "activepieces.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "activepieces.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "activepieces.labels" -}}
|
||||
helm.sh/chart: {{ include "activepieces.chart" . }}
|
||||
{{ include "activepieces.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "activepieces.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "activepieces.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "activepieces.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "activepieces.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,469 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "activepieces.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "activepieces.serviceAccountName" . }}
|
||||
{{- with .Values.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.container.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
# Core Activepieces configuration
|
||||
{{- if .Values.activepieces.frontendUrl }}
|
||||
- name: AP_FRONTEND_URL
|
||||
value: {{ .Values.activepieces.frontendUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.apiKey }}
|
||||
- name: AP_API_KEY
|
||||
value: {{ .Values.activepieces.apiKey | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.clientRealIpHeader }}
|
||||
- name: AP_CLIENT_REAL_IP_HEADER
|
||||
value: {{ .Values.activepieces.clientRealIpHeader | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.configPath }}
|
||||
- name: AP_CONFIG_PATH
|
||||
value: {{ .Values.activepieces.configPath | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.devPieces }}
|
||||
- name: AP_DEV_PIECES
|
||||
value: {{ .Values.activepieces.devPieces | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.internalUrl }}
|
||||
- name: AP_INTERNAL_URL
|
||||
value: {{ .Values.activepieces.internalUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.maxConcurrentJobsPerProject }}
|
||||
- name: AP_MAX_CONCURRENT_JOBS_PER_PROJECT
|
||||
value: {{ .Values.activepieces.maxConcurrentJobsPerProject | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.perplexityBaseUrl }}
|
||||
- name: AP_PERPLEXITY_BASE_URL
|
||||
value: {{ .Values.activepieces.perplexityBaseUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.piecesSyncMode }}
|
||||
- name: AP_PIECES_SYNC_MODE
|
||||
value: {{ .Values.activepieces.piecesSyncMode | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.featurebaseApiKey }}
|
||||
- name: AP_FEATUREBASE_API_KEY
|
||||
value: {{ .Values.activepieces.featurebaseApiKey | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.enableFlowOnPublish }}
|
||||
- name: AP_ENABLE_FLOW_ON_PUBLISH
|
||||
value: {{ .Values.activepieces.enableFlowOnPublish | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.issueArchiveDays }}
|
||||
- name: AP_ISSUE_ARCHIVE_DAYS
|
||||
value: {{ .Values.activepieces.issueArchiveDays | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.pausedFlowTimeoutDays }}
|
||||
- name: AP_PAUSED_FLOW_TIMEOUT_DAYS
|
||||
value: {{ .Values.activepieces.pausedFlowTimeoutDays | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.logLevel }}
|
||||
- name: AP_LOG_LEVEL
|
||||
value: {{ .Values.activepieces.logLevel | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.logPretty }}
|
||||
- name: AP_LOG_PRETTY
|
||||
value: {{ .Values.activepieces.logPretty | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.appWebhookSecrets }}
|
||||
- name: AP_APP_WEBHOOK_SECRETS
|
||||
value: {{ .Values.activepieces.appWebhookSecrets | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.maxFileSizeMb }}
|
||||
- name: AP_MAX_FILE_SIZE_MB
|
||||
value: {{ .Values.activepieces.maxFileSizeMb | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.sandboxMemoryLimit }}
|
||||
- name: AP_SANDBOX_MEMORY_LIMIT
|
||||
value: {{ .Values.activepieces.sandboxMemoryLimit | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.sandboxPropagatedEnvVars }}
|
||||
- name: AP_SANDBOX_PROPAGATED_ENV_VARS
|
||||
value: {{ .Values.activepieces.sandboxPropagatedEnvVars | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.piecesSource }}
|
||||
- name: AP_PIECES_SOURCE
|
||||
value: {{ .Values.activepieces.piecesSource | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.apiRateLimiting.authn.enabled }}
|
||||
- name: AP_API_RATE_LIMIT_AUTHN_ENABLED
|
||||
value: {{ .Values.activepieces.apiRateLimiting.authn.enabled | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.apiRateLimiting.authn.max }}
|
||||
- name: AP_API_RATE_LIMIT_AUTHN_MAX
|
||||
value: {{ .Values.activepieces.apiRateLimiting.authn.max | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.apiRateLimiting.authn.window }}
|
||||
- name: AP_API_RATE_LIMIT_AUTHN_WINDOW
|
||||
value: {{ .Values.activepieces.apiRateLimiting.authn.window | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.projectRateLimiter.enabled }}
|
||||
- name: AP_PROJECT_RATE_LIMITER_ENABLED
|
||||
value: {{ .Values.activepieces.projectRateLimiter.enabled | quote }}
|
||||
{{- end }}
|
||||
- name: AP_ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "activepieces.fullname" . }}-secrets
|
||||
key: encryption-key
|
||||
- name: AP_JWT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "activepieces.fullname" . }}-jwt-secret
|
||||
key: jwt-secret
|
||||
{{- if .Values.activepieces.environment }}
|
||||
- name: AP_ENVIRONMENT
|
||||
value: {{ .Values.activepieces.environment | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.edition }}
|
||||
- name: AP_EDITION
|
||||
value: {{ .Values.activepieces.edition | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.executionMode }}
|
||||
- name: AP_EXECUTION_MODE
|
||||
value: {{ .Values.activepieces.executionMode | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.telemetryEnabled }}
|
||||
- name: AP_TELEMETRY_ENABLED
|
||||
value: {{ .Values.activepieces.telemetryEnabled | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.templatesSourceUrl }}
|
||||
- name: AP_TEMPLATES_SOURCE_URL
|
||||
value: {{ .Values.activepieces.templatesSourceUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.flowWorkerConcurrency }}
|
||||
- name: AP_FLOW_WORKER_CONCURRENCY
|
||||
value: {{ .Values.activepieces.flowWorkerConcurrency | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.scheduledWorkerConcurrency }}
|
||||
- name: AP_SCHEDULED_WORKER_CONCURRENCY
|
||||
value: {{ .Values.activepieces.scheduledWorkerConcurrency | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.triggerDefaultPollInterval }}
|
||||
- name: AP_TRIGGER_DEFAULT_POLL_INTERVAL
|
||||
value: {{ .Values.activepieces.triggerDefaultPollInterval | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.triggerTimeoutSeconds }}
|
||||
- name: AP_TRIGGER_TIMEOUT_SECONDS
|
||||
value: {{ .Values.activepieces.triggerTimeoutSeconds | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.flowTimeoutSeconds }}
|
||||
- name: AP_FLOW_TIMEOUT_SECONDS
|
||||
value: {{ .Values.activepieces.flowTimeoutSeconds | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.webhookTimeoutSeconds }}
|
||||
- name: AP_WEBHOOK_TIMEOUT_SECONDS
|
||||
value: {{ .Values.activepieces.webhookTimeoutSeconds | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.executionDataRetentionDays }}
|
||||
- name: AP_EXECUTION_DATA_RETENTION_DAYS
|
||||
value: {{ .Values.activepieces.executionDataRetentionDays | quote }}
|
||||
{{- end }}
|
||||
{{- if or .Values.postgresql.enabled (or .Values.postgresql.host .Values.postgresql.url) }}
|
||||
# PostgreSQL configuration (subchart or external)
|
||||
- name: AP_DB_TYPE
|
||||
value: "POSTGRES"
|
||||
{{- if .Values.postgresql.auth.database }}
|
||||
- name: AP_POSTGRES_DATABASE
|
||||
value: {{ .Values.postgresql.auth.database | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.host }}
|
||||
- name: AP_POSTGRES_HOST
|
||||
value: {{ .Values.postgresql.host | quote }}
|
||||
{{- else if .Values.postgresql.enabled }}
|
||||
- name: AP_POSTGRES_HOST
|
||||
value: {{ printf "%s-postgresql" (include "activepieces.fullname" .) | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.port }}
|
||||
- name: AP_POSTGRES_PORT
|
||||
value: {{ .Values.postgresql.port | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.auth.username }}
|
||||
- name: AP_POSTGRES_USERNAME
|
||||
value: {{ .Values.postgresql.auth.username | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.auth.externalSecret }}
|
||||
- name: AP_POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.postgresql.auth.externalSecret.name | quote }}
|
||||
key: {{ .Values.postgresql.auth.externalSecret.key | quote }}
|
||||
{{- else if .Values.postgresql.auth.password }}
|
||||
- name: AP_POSTGRES_PASSWORD
|
||||
value: {{ .Values.postgresql.auth.password | quote }}
|
||||
{{- else if .Values.postgresql.enabled }}
|
||||
- name: AP_POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "activepieces.fullname" . }}-postgresql
|
||||
key: postgres-password
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.useSSL }}
|
||||
- name: AP_POSTGRES_USE_SSL
|
||||
value: {{ .Values.postgresql.useSSL | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.sslCa }}
|
||||
- name: AP_POSTGRES_SSL_CA
|
||||
value: {{ .Values.postgresql.sslCa | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.url }}
|
||||
- name: AP_POSTGRES_URL
|
||||
value: {{ .Values.postgresql.url | quote }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
# SQLite configuration (fallback)
|
||||
- name: AP_DB_TYPE
|
||||
value: "SQLITE3"
|
||||
{{- end }}
|
||||
{{- if or .Values.redis.enabled (or .Values.redis.host .Values.redis.url) }}
|
||||
# Redis configuration (subchart or external)
|
||||
{{- if .Values.redis.host }}
|
||||
- name: AP_REDIS_HOST
|
||||
value: {{ .Values.redis.host | quote }}
|
||||
{{- else if .Values.redis.enabled }}
|
||||
- name: AP_REDIS_HOST
|
||||
value: {{ printf "%s-redis-master" (include "activepieces.fullname" .) | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.port }}
|
||||
- name: AP_REDIS_PORT
|
||||
value: {{ .Values.redis.port | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.useSSL }}
|
||||
- name: AP_REDIS_USE_SSL
|
||||
value: {{ .Values.redis.useSSL | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.sslCaFile }}
|
||||
- name: AP_REDIS_SSL_CA_FILE
|
||||
value: {{ .Values.redis.sslCaFile | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.db }}
|
||||
- name: AP_REDIS_DB
|
||||
value: {{ .Values.redis.db | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.user }}
|
||||
- name: AP_REDIS_USER
|
||||
value: {{ .Values.redis.user | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.url }}
|
||||
- name: AP_REDIS_URL
|
||||
value: {{ .Values.redis.url | quote }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.redis.type "sentinel" }}
|
||||
- name: AP_REDIS_TYPE
|
||||
value: "SENTINEL"
|
||||
{{- else }}
|
||||
# Default to DEFAULT for standalone Redis
|
||||
- name: AP_REDIS_TYPE
|
||||
value: "DEFAULT"
|
||||
{{- end }}
|
||||
{{- if .Values.redis.sentinel.role }}
|
||||
- name: AP_REDIS_SENTINEL_ROLE
|
||||
value: {{ .Values.redis.sentinel.role | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.sentinel.hosts }}
|
||||
- name: AP_REDIS_SENTINEL_HOSTS
|
||||
value: {{ .Values.redis.sentinel.hosts | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.sentinel.name }}
|
||||
- name: AP_REDIS_SENTINEL_NAME
|
||||
value: {{ .Values.redis.sentinel.name | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.failedJob.retentionDays }}
|
||||
- name: AP_REDIS_FAILED_JOB_RETENTION_DAYS
|
||||
value: {{ .Values.redis.failedJob.retentionDays | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.failedJob.retentionMaxCount }}
|
||||
- name: AP_REDIS_FAILED_JOB_RETENTION_MAX_COUNT
|
||||
value: {{ .Values.redis.failedJob.retentionMaxCount | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.redis.auth.externalSecret }}
|
||||
- name: AP_REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.redis.auth.externalSecret.name | quote }}
|
||||
key: {{ .Values.redis.auth.externalSecret.key | quote }}
|
||||
{{- else if .Values.redis.auth.password }}
|
||||
- name: AP_REDIS_PASSWORD
|
||||
value: {{ .Values.redis.auth.password | quote }}
|
||||
{{- else if and .Values.redis.enabled .Values.redis.auth.enabled }}
|
||||
- name: AP_REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Release.Name }}-redis
|
||||
key: redis-password
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
# Memory queue (fallback)
|
||||
- name: AP_REDIS_TYPE
|
||||
value: "MEMORY"
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.enabled }}
|
||||
# SMTP configuration
|
||||
{{- if .Values.smtp.host }}
|
||||
- name: AP_SMTP_HOST
|
||||
value: {{ .Values.smtp.host | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.port }}
|
||||
- name: AP_SMTP_PORT
|
||||
value: {{ .Values.smtp.port | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.username }}
|
||||
- name: AP_SMTP_USERNAME
|
||||
value: {{ .Values.smtp.username | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.password }}
|
||||
- name: AP_SMTP_PASSWORD
|
||||
value: {{ .Values.smtp.password | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.senderEmail }}
|
||||
- name: AP_SMTP_SENDER_EMAIL
|
||||
value: {{ .Values.smtp.senderEmail | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.smtp.senderName }}
|
||||
- name: AP_SMTP_SENDER_NAME
|
||||
value: {{ .Values.smtp.senderName | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.enabled }}
|
||||
# S3 configuration
|
||||
{{- if .Values.s3.accessKeyId }}
|
||||
- name: AP_S3_ACCESS_KEY_ID
|
||||
value: {{ .Values.s3.accessKeyId | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.secretAccessKey }}
|
||||
- name: AP_S3_SECRET_ACCESS_KEY
|
||||
value: {{ .Values.s3.secretAccessKey | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.bucket }}
|
||||
- name: AP_S3_BUCKET
|
||||
value: {{ .Values.s3.bucket | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.endpoint }}
|
||||
- name: AP_S3_ENDPOINT
|
||||
value: {{ .Values.s3.endpoint | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.region }}
|
||||
- name: AP_S3_REGION
|
||||
value: {{ .Values.s3.region | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.useSignedUrls }}
|
||||
- name: AP_S3_USE_SIGNED_URLS
|
||||
value: {{ .Values.s3.useSignedUrls | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.s3.useIrsa }}
|
||||
- name: AP_S3_USE_IRSA
|
||||
value: {{ .Values.s3.useIrsa | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.queueUi.enabled }}
|
||||
# Queue UI configuration
|
||||
- name: AP_QUEUE_UI_ENABLED
|
||||
value: {{ .Values.queueUi.enabled | quote }}
|
||||
{{- if .Values.queueUi.username }}
|
||||
- name: AP_QUEUE_UI_USERNAME
|
||||
value: {{ .Values.queueUi.username | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.queueUi.password }}
|
||||
- name: AP_QUEUE_UI_PASSWORD
|
||||
value: {{ .Values.queueUi.password | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.engineExecutablePath }}
|
||||
- name: AP_ENGINE_EXECUTABLE_PATH
|
||||
value: {{ .Values.activepieces.engineExecutablePath | quote }}
|
||||
{{- end }}
|
||||
# OpenTelemetry configuration
|
||||
{{- if .Values.activepieces.otel.enabled }}
|
||||
- name: AP_OTEL_ENABLED
|
||||
value: {{ .Values.activepieces.otel.enabled | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.otel.exporterOtlpEndpoint }}
|
||||
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
||||
value: {{ .Values.activepieces.otel.exporterOtlpEndpoint | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.activepieces.otel.exporterOtlpHeaders }}
|
||||
- name: OTEL_EXPORTER_OTLP_HEADERS
|
||||
value: {{ .Values.activepieces.otel.exporterOtlpHeaders | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.persistence.enabled }}
|
||||
- name: cache
|
||||
mountPath: {{ .Values.persistence.mountPath | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.volumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if .Values.persistence.enabled }}
|
||||
- name: cache
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "activepieces.fullname" . }}-cache
|
||||
{{- end }}
|
||||
{{- with .Values.volumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,32 +0,0 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "activepieces.fullname" . }}
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,43 +0,0 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
{{- with .pathType }}
|
||||
pathType: {{ . }}
|
||||
{{- end }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "activepieces.fullname" $ }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,14 +0,0 @@
|
||||
{{- if .Values.persistence.enabled }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}-cache
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size | quote }}
|
||||
{{- end }}
|
||||
@@ -1,24 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}-secrets
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
secret-generator.v1.mittwald.de/autogenerate: encryption-key
|
||||
secret-generator.v1.mittwald.de/encoding: hex
|
||||
secret-generator.v1.mittwald.de/length: "32"
|
||||
type: Opaque
|
||||
data: {}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}-jwt-secret
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
secret-generator.v1.mittwald.de/autogenerate: jwt-secret
|
||||
secret-generator.v1.mittwald.de/length: "64"
|
||||
type: Opaque
|
||||
data: {}
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "activepieces.fullname" . }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "activepieces.selectorLabels" . | nindent 4 }}
|
||||
@@ -1,13 +0,0 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "activepieces.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "activepieces.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{- include "activepieces.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "activepieces.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
@@ -1,324 +0,0 @@
|
||||
# Default values for activepieces.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
|
||||
replicaCount: 1
|
||||
|
||||
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
|
||||
image:
|
||||
repository: ghcr.io/activepieces/activepieces
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
# This is to override the chart name.
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Automatically mount a ServiceAccount's API credentials?
|
||||
automount: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
# This is for setting Kubernetes Annotations to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
podAnnotations: {}
|
||||
# This is for setting Kubernetes Labels to a Pod.
|
||||
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
# Container configuration
|
||||
container:
|
||||
port: 80
|
||||
|
||||
# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
service:
|
||||
# This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
|
||||
type: ClusterIP
|
||||
# This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
|
||||
port: 80
|
||||
|
||||
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
hosts:
|
||||
- host: chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /v1/health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /v1/health
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
|
||||
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 100
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 2Gi
|
||||
mountPath: "/usr/src/app/cache"
|
||||
|
||||
volumes: []
|
||||
volumeMounts: []
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
activepieces:
|
||||
# ============================================================================
|
||||
# REQUIRED: Core configuration that must be set for production deployment
|
||||
# ============================================================================
|
||||
|
||||
# The URL where Activepieces will be accessible (e.g., https://activepieces.yourdomain.com)
|
||||
frontendUrl: "http://localhost:4200"
|
||||
|
||||
# Edition: ce (Community) or ee (Enterprise)
|
||||
# Community Edition (ce) is the default open-source version
|
||||
edition: "ce"
|
||||
|
||||
# Execution mode for flows - see: https://www.activepieces.com/docs/install/architecture/workers
|
||||
# Options: SANDBOX_CODE_ONLY, UNSANDBOXED
|
||||
executionMode: "SANDBOX_CODE_ONLY"
|
||||
|
||||
# Environment: prod or dev
|
||||
environment: "prod"
|
||||
|
||||
# ============================================================================
|
||||
# OPTIONAL: Additional configuration (defaults are usually sufficient)
|
||||
# ============================================================================
|
||||
|
||||
telemetryEnabled: true
|
||||
templatesSourceUrl: "https://cloud.activepieces.com/api/v1/templates"
|
||||
flowWorkerConcurrency: ""
|
||||
scheduledWorkerConcurrency: ""
|
||||
triggerDefaultPollInterval: ""
|
||||
triggerTimeoutSeconds: ""
|
||||
flowTimeoutSeconds: ""
|
||||
webhookTimeoutSeconds: ""
|
||||
executionDataRetentionDays: ""
|
||||
issueArchiveDays: ""
|
||||
pausedFlowTimeoutDays: ""
|
||||
logLevel: "info"
|
||||
logPretty: false
|
||||
apiRateLimiting:
|
||||
authn:
|
||||
enabled: false
|
||||
max: 100
|
||||
window: 60
|
||||
projectRateLimiter:
|
||||
enabled: false
|
||||
piecesSource: ""
|
||||
devPieces: false
|
||||
piecesSyncMode: ""
|
||||
|
||||
# ============================================================================
|
||||
# OPTIONAL: Advanced configuration (only set if needed)
|
||||
# ============================================================================
|
||||
|
||||
# Networking & API
|
||||
clientRealIpHeader: "" # Header to extract real client IP (e.g., X-Forwarded-For)
|
||||
apiKey: "" # API key for platform authentication
|
||||
internalUrl: "" # Internal URL for service communication
|
||||
|
||||
# Performance & Limits
|
||||
maxConcurrentJobsPerProject: "" # Limit concurrent jobs per project
|
||||
maxFileSizeMb: "" # Maximum file upload size in MB
|
||||
sandboxMemoryLimit: "" # Memory limit for sandbox execution
|
||||
sandboxPropagatedEnvVars: "" # Environment variables to pass to sandbox
|
||||
|
||||
# Integrations
|
||||
perplexityBaseUrl: "" # Custom Perplexity AI base URL
|
||||
featurebaseApiKey: "" # Featurebase API key for feedback
|
||||
appWebhookSecrets: "" # Secrets for app webhooks
|
||||
|
||||
# UI & Behavior
|
||||
showChangelog: true # Show changelog to users
|
||||
enableFlowOnPublish: true # Auto-enable flows when published
|
||||
|
||||
# System Paths
|
||||
configPath: "" # Custom config file path
|
||||
engineExecutablePath: "dist/packages/engine/main.js" # Engine executable path
|
||||
|
||||
# OpenTelemetry Configuration (for observability)
|
||||
otel:
|
||||
enabled: false
|
||||
exporterOtlpEndpoint: ""
|
||||
exporterOtlpHeaders: ""
|
||||
|
||||
# ============================================================================
|
||||
# Database Configuration
|
||||
# PostgreSQL is deployed by default using the Bitnami subchart
|
||||
# ============================================================================
|
||||
postgresql:
|
||||
# Set to true to deploy PostgreSQL subchart (Bitnami)
|
||||
# Set to false and provide host/url to use external PostgreSQL
|
||||
enabled: true
|
||||
# External PostgreSQL host (required if enabled=false and using external PostgreSQL)
|
||||
host: ""
|
||||
# PostgreSQL port
|
||||
port: 5432
|
||||
# Enable SSL for PostgreSQL connection
|
||||
useSSL: false
|
||||
# PostgreSQL connection URL (alternative to host/port/auth)
|
||||
# If provided, host/port/auth will be ignored
|
||||
url: ""
|
||||
# SSL CA certificate for PostgreSQL (if useSSL is true)
|
||||
sslCa: ""
|
||||
auth:
|
||||
database: "activepieces"
|
||||
username: "postgres"
|
||||
# Password for PostgreSQL
|
||||
# - If using subchart (enabled=true), password is automatically generated if not provided
|
||||
# - If using external PostgreSQL, provide password here or use externalSecret
|
||||
password: ""
|
||||
# External secret reference for password (alternative to password field)
|
||||
# Use this when password is stored in a Kubernetes secret (e.g., External Secrets Operator)
|
||||
# externalSecret:
|
||||
# name: "postgresql-credentials"
|
||||
# key: "password"
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
|
||||
# ============================================================================
|
||||
# Queue Configuration
|
||||
# Redis is deployed by default using the Bitnami subchart
|
||||
# ============================================================================
|
||||
redis:
|
||||
# Set to true to deploy Redis subchart (Bitnami)
|
||||
# Set to false and provide host/url to use external Redis
|
||||
enabled: true
|
||||
# External Redis host (required if enabled=false and using external Redis)
|
||||
host: ""
|
||||
# Redis port
|
||||
port: 6379
|
||||
# Enable SSL for Redis connection
|
||||
useSSL: false
|
||||
# SSL CA certificate file path for Redis (if useSSL is true)
|
||||
sslCaFile: ""
|
||||
# Redis database number
|
||||
db: 0
|
||||
# Redis connection URL (alternative to host/port/auth)
|
||||
# If provided, host/port/auth will be ignored
|
||||
url: ""
|
||||
# Redis type: "standalone" or "sentinel"
|
||||
type: "standalone"
|
||||
# Redis username (for Redis 6+ ACL)
|
||||
user: ""
|
||||
sentinel:
|
||||
name: ""
|
||||
hosts: ""
|
||||
role: ""
|
||||
failedJob:
|
||||
retentionDays: 7
|
||||
retentionMaxCount: 100
|
||||
auth:
|
||||
# Set to true if Redis requires authentication
|
||||
# - If using subchart (enabled=true), password is automatically generated if not provided
|
||||
# - If using external Redis, provide password or use externalSecret
|
||||
enabled: true
|
||||
# Password for Redis
|
||||
password: ""
|
||||
# External secret reference for password (alternative to password field)
|
||||
# Use this when password is stored in a Kubernetes secret (e.g., External Secrets Operator)
|
||||
# externalSecret:
|
||||
# name: "redis-credentials"
|
||||
# key: "password"
|
||||
master:
|
||||
persistence:
|
||||
enabled: true
|
||||
|
||||
# ============================================================================
|
||||
# OPTIONAL: Email Configuration
|
||||
# Enable SMTP to send email notifications
|
||||
# ============================================================================
|
||||
smtp:
|
||||
enabled: false # Set to true and configure below to enable emails
|
||||
host: ""
|
||||
port: 587
|
||||
username: ""
|
||||
password: ""
|
||||
senderEmail: ""
|
||||
senderName: ""
|
||||
|
||||
# ============================================================================
|
||||
# OPTIONAL: S3 Storage Configuration
|
||||
# Enable S3 for file storage (alternative to local storage)
|
||||
# ============================================================================
|
||||
s3:
|
||||
enabled: false # Set to true and configure below to use S3
|
||||
accessKeyId: ""
|
||||
secretAccessKey: ""
|
||||
bucket: ""
|
||||
endpoint: "" # For S3-compatible services like MinIO
|
||||
region: ""
|
||||
useSignedUrls: false
|
||||
useIrsa: false # Use IAM Roles for Service Accounts (EKS)
|
||||
|
||||
# ============================================================================
|
||||
# OPTIONAL: Queue UI Configuration
|
||||
# Enable BullMQ Board for monitoring job queues
|
||||
# ============================================================================
|
||||
queueUi:
|
||||
enabled: false # Set to true and configure credentials below
|
||||
username: ""
|
||||
password: ""
|
||||
33
activepieces-fork/deploy/pulumi/.gitignore
vendored
33
activepieces-fork/deploy/pulumi/.gitignore
vendored
@@ -1,33 +0,0 @@
|
||||
/.pulumi/
|
||||
/.vscode/
|
||||
/.vs/
|
||||
bin/
|
||||
build/
|
||||
node_modules/
|
||||
*.pyc
|
||||
.Python
|
||||
venv/
|
||||
include/
|
||||
lib/
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
# https://www.pulumi.com/blog/iac-recommended-practices-developer-stacks-git-branches/#using-developer-stacks
|
||||
# Pulumi.*.yaml
|
||||
# Pulumi.*dev*.yaml
|
||||
.idea/
|
||||
.ionide/
|
||||
*.iml
|
||||
key.rsa*
|
||||
obj/
|
||||
vendor
|
||||
Gopkg.lock
|
||||
**/.DS_Store
|
||||
|
||||
**/ci-scripts
|
||||
|
||||
# Java app
|
||||
.gradle/
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
||||
target/
|
||||
@@ -1,22 +0,0 @@
|
||||
encryptionsalt: v1:wHCVNl3bj/g=:v1:mxogi9ZeBjIcxNZC:q+bjpLv9rnJnu8qq7xwKGLd/GAZOqA==
|
||||
config:
|
||||
activepieces:environment: "dev"
|
||||
activepieces:apEncryptionKey:
|
||||
activepieces:apJwtSecret:
|
||||
activepieces:deployLocalBuild: "false"
|
||||
activepieces:repoName:
|
||||
activepieces:containerCpu: "256"
|
||||
activepieces:containerMemory: "512"
|
||||
activepieces:containerInstances: "1"
|
||||
activepieces:usePostgres: "false"
|
||||
activepieces:dbInstanceClass: "db.t3.small"
|
||||
activepieces:dbUsername: "postgres"
|
||||
activepieces:dbIsPublic: "false"
|
||||
activepieces:dbPassword:
|
||||
secure: v1:MXNSOcqZCp10X2PX:mU2iTrcETjdisk8FkD5yHLJYUxRei/9l
|
||||
activepieces:addIpToPostgresSecurityGroup:
|
||||
activepieces:useRedis: "false"
|
||||
activepieces:redisNodeType: "cache.t3.small"
|
||||
activepieces:domain:
|
||||
activepieces:subDomain:
|
||||
aws:region: "us-east-1"
|
||||
@@ -1,19 +0,0 @@
|
||||
encryptionsalt: v1:icXg2cmIvSc=:v1:y8+4YhdMCPPDY26J:5cNYmimH353n8sjUDDc6srvcPgb+8Q==
|
||||
config:
|
||||
activepieces:environment: "prod"
|
||||
activepieces:apEncryptionKey:
|
||||
activepieces:apJwtSecret:
|
||||
activepieces:deployLocalBuild: "true"
|
||||
activepieces:repoName: "activepieces-prod-repo"
|
||||
activepieces:containerCpu: "512"
|
||||
activepieces:containerMemory: "1024"
|
||||
activepieces:containerInstances: "1"
|
||||
activepieces:usePostgres: "true"
|
||||
activepieces:dbInstanceClass: "db.t3.small"
|
||||
activepieces:dbIsPublic: "false"
|
||||
activepieces:dbPassword:
|
||||
secure: v1:MXNSOcqZCp10X2PX:mU2iTrcETjdisk8FkD5yHLJYUxRei/9l
|
||||
activepieces:dbUsername: "postgres"
|
||||
activepieces:useRedis: "true"
|
||||
activepieces:redisNodeType: "cache.t3.small"
|
||||
aws:region: "us-east-1"
|
||||
@@ -1,56 +0,0 @@
|
||||
runtime: nodejs
|
||||
name: activepieces
|
||||
description: A Pulumi template to deploy Activepieces in a development or production configuration.
|
||||
stack: activepieces-dev
|
||||
template:
|
||||
description: Deploy Activepieces into into an ECS Fargate instance & optionally add Postgres, Redis and a DNS registration with SSL.
|
||||
config:
|
||||
aws:region:
|
||||
description: The AWS region to deploy into
|
||||
default: us-west-2
|
||||
environment:
|
||||
description: Environment
|
||||
default: prod
|
||||
containerCpu:
|
||||
description: The amount of CPU to allocate for the container
|
||||
default: 256
|
||||
containerMemory:
|
||||
description: The amount of memory to allocate for the container
|
||||
default: 512
|
||||
containerInstances:
|
||||
description: Number of running containers behind load balancer
|
||||
default: 1
|
||||
usePostgres:
|
||||
description: Add Postgres for storage or use SQLite3 locally
|
||||
default: true
|
||||
dbIsPublic:
|
||||
description: Should Db be publicly reachable. Ignored if usePostgres is false.
|
||||
default: false
|
||||
dbUsername:
|
||||
description: Default username for the Postgres. Ignored if usePostgres is false
|
||||
default: postgres
|
||||
dbPassword:
|
||||
description: Defaults to "postgres". Ignored if usePostgres is false
|
||||
default: postgres
|
||||
secret: true
|
||||
dbInstanceClass:
|
||||
description: The size of the RDS instance
|
||||
default: db.t3.micro
|
||||
useRedis:
|
||||
description: Use a single node Redis cluster or in-memory
|
||||
default: true
|
||||
redisNodeType:
|
||||
description: Node type for the Redis 7 cluster
|
||||
default: cache.t3.micro
|
||||
domain:
|
||||
description: Optional - E.g. "yourdomain.com". Hosted zone must already exist in Route 53. Creates SSL cert
|
||||
subDomain:
|
||||
description: Optional - E.g. "activepieces". "domain" must be set
|
||||
addIpToPostgresSecurityGroup:
|
||||
description: Optional - An IP address to add to the allowed inbound traffic for the Postgres
|
||||
apEncryptionKey:
|
||||
description: Optional - Run 'openssl rand -hex 16' locally to generate or leave blank to auto-generate
|
||||
secret: true
|
||||
apJwtSecret:
|
||||
description: Optional - Run 'openssl rand -hex 32' locally to generate or leave blank to auto-generate
|
||||
secret: true
|
||||
@@ -1,3 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
See instruction on https://www.activepieces.com/docs/install/options/aws
|
||||
@@ -1,16 +0,0 @@
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import { isTaggable } from "./taggable";
|
||||
|
||||
/**
|
||||
* registerAutoTags registers a global stack transformation that merges a set
|
||||
* of tags with whatever was also explicitly added to the resource definition.
|
||||
*/
|
||||
export function registerAutoTags(autoTags: Record<string, string>): void {
|
||||
pulumi.runtime.registerStackTransformation((args) => {
|
||||
if (isTaggable(args.type)) {
|
||||
args.props["tags"] = { ...args.props["tags"], ...autoTags };
|
||||
return { props: args.props, opts: args.opts };
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
@@ -1,466 +0,0 @@
|
||||
import * as aws from "@pulumi/aws";
|
||||
import * as docker from "@pulumi/docker";
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as awsx from "@pulumi/awsx";
|
||||
import { ApplicationLoadBalancer } from "@pulumi/awsx/lb/applicationLoadBalancer";
|
||||
import { registerAutoTags } from './autotag';
|
||||
import * as child_process from "child_process";
|
||||
|
||||
const stack = pulumi.getStack();
|
||||
const config = new pulumi.Config();
|
||||
|
||||
const apEncryptionKey = config.getSecret("apEncryptionKey")?.apply(secretValue => {
|
||||
return secretValue || child_process.execSync("openssl rand -hex 16").toString().trim();
|
||||
});
|
||||
const apJwtSecret = config.getSecret("apJwtSecret")?.apply(secretValue => {
|
||||
return secretValue || child_process.execSync("openssl rand -hex 32").toString().trim();
|
||||
});
|
||||
const containerCpu = config.requireNumber("containerCpu");
|
||||
const containerMemory = config.requireNumber("containerMemory");
|
||||
const containerInstances = config.requireNumber("containerInstances");
|
||||
const addIpToPostgresSecurityGroup = config.get("addIpToPostgresSecurityGroup");
|
||||
const domain = config.get("domain");
|
||||
const subDomain = config.get("subDomain");
|
||||
const usePostgres = config.requireBoolean("usePostgres");
|
||||
const useRedis = config.requireBoolean("useRedis");
|
||||
const redisNodeType = config.require("redisNodeType");
|
||||
const dbIsPublic = config.getBoolean("dbIsPublic");
|
||||
const dbUsername = config.get("dbUsername");
|
||||
const dbPassword = config.getSecret("dbPassword");
|
||||
const dbInstanceClass = config.require("dbInstanceClass");
|
||||
|
||||
// Add tags for every resource that allows them, with the following properties.
|
||||
// Useful to know who or what created the resource/service
|
||||
registerAutoTags({
|
||||
"pulumi:Project": pulumi.getProject(),
|
||||
"pulumi:Stack": pulumi.getStack(),
|
||||
"Created by": config.get("author") || child_process.execSync("pulumi whoami").toString().trim().replace('\\', '/')
|
||||
});
|
||||
|
||||
let imageName;
|
||||
|
||||
// Check if we're deploying a local build or direct from Docker Hub
|
||||
if (config.getBoolean("deployLocalBuild")) {
|
||||
|
||||
const repoName = config.require("repoName");
|
||||
|
||||
const repo = new aws.ecr.Repository(repoName, {
|
||||
name: repoName // https://www.pulumi.com/docs/intro/concepts/resources/names/#autonaming
|
||||
}); // Create a private ECR repository
|
||||
|
||||
const repoUrl = pulumi.interpolate`${repo.repositoryUrl}`; // Get registry info (creds and endpoint)
|
||||
const name = pulumi.interpolate`${repoUrl}:latest`;
|
||||
|
||||
// Get the repository credentials we use to push the image to the repository
|
||||
const repoCreds = repo.registryId.apply(async (registryId) => {
|
||||
const credentials = await aws.ecr.getCredentials({
|
||||
registryId: registryId,
|
||||
});
|
||||
const decodedCredentials = Buffer.from(credentials.authorizationToken, "base64").toString();
|
||||
const [username, password] = decodedCredentials.split(":");
|
||||
return {
|
||||
server: credentials.proxyEndpoint,
|
||||
username,
|
||||
password
|
||||
};
|
||||
});
|
||||
|
||||
// Build and publish the container image.
|
||||
const image = new docker.Image(stack, {
|
||||
build: {
|
||||
context: `../../`,
|
||||
dockerfile: `../../Dockerfile`,
|
||||
builderVersion: "BuilderBuildKit",
|
||||
args: {
|
||||
"BUILDKIT_INLINE_CACHE": "1"
|
||||
},
|
||||
},
|
||||
skipPush: pulumi.runtime.isDryRun(),
|
||||
imageName: name,
|
||||
registry: repoCreds
|
||||
});
|
||||
|
||||
imageName = image.imageName;
|
||||
|
||||
pulumi.log.info(`Finished pushing image to ECR`, image);
|
||||
} else {
|
||||
imageName = process.env.IMAGE_NAME || config.get("imageName") || "activepieces/activepieces:latest";
|
||||
}
|
||||
|
||||
const containerEnvironmentVars: awsx.types.input.ecs.TaskDefinitionKeyValuePairArgs[] = [];
|
||||
|
||||
// Allocate a new VPC with the default settings:
|
||||
const vpc = new awsx.ec2.Vpc(`${stack}-vpc`, {
|
||||
numberOfAvailabilityZones: 2,
|
||||
natGateways: {
|
||||
strategy: "Single"
|
||||
},
|
||||
tags: {
|
||||
// For some reason, this is how you name a VPC with AWS:
|
||||
// https://github.com/pulumi/pulumi-terraform/issues/38#issue-262186406
|
||||
Name: `${stack}-vpc`
|
||||
},
|
||||
enableDnsHostnames: true,
|
||||
enableDnsSupport: true
|
||||
});
|
||||
|
||||
const albSecGroup = new aws.ec2.SecurityGroup(`${stack}-alb-sg`, {
|
||||
name: `${stack}-alb-sg`,
|
||||
vpcId: vpc.vpcId,
|
||||
ingress: [{ // Allow only http & https traffic
|
||||
protocol: "tcp",
|
||||
fromPort: 443,
|
||||
toPort: 443,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
},
|
||||
{
|
||||
protocol: "tcp",
|
||||
fromPort: 80,
|
||||
toPort: 80,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
}],
|
||||
egress: [{
|
||||
protocol: "-1",
|
||||
fromPort: 0,
|
||||
toPort: 0,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
}]
|
||||
})
|
||||
|
||||
const fargateSecGroup = new aws.ec2.SecurityGroup(`${stack}-fargate-sg`, {
|
||||
name: `${stack}-fargate-sg`,
|
||||
vpcId: vpc.vpcId,
|
||||
ingress: [
|
||||
{
|
||||
protocol: "tcp",
|
||||
fromPort: 80,
|
||||
toPort: 80,
|
||||
securityGroups: [albSecGroup.id]
|
||||
}
|
||||
],
|
||||
egress: [ // allow all outbound traffic
|
||||
{
|
||||
protocol: "-1",
|
||||
fromPort: 0,
|
||||
toPort: 0,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (usePostgres) {
|
||||
const rdsSecurityGroupArgs: aws.ec2.SecurityGroupArgs = {
|
||||
name: `${stack}-db-sg`,
|
||||
vpcId: vpc.vpcId,
|
||||
ingress: [{
|
||||
protocol: "tcp",
|
||||
fromPort: 5432,
|
||||
toPort: 5432,
|
||||
securityGroups: [fargateSecGroup.id] // The id of the Fargate security group
|
||||
}],
|
||||
egress: [ // allow all outbound traffic
|
||||
{
|
||||
protocol: "-1",
|
||||
fromPort: 0,
|
||||
toPort: 0,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Optionally add the current outgoing public IP address to the CIDR block
|
||||
// so that they can connect directly to the Db during development
|
||||
if (addIpToPostgresSecurityGroup) {
|
||||
|
||||
// @ts-ignore
|
||||
rdsSecurityGroupArgs.ingress.push({
|
||||
protocol: "tcp",
|
||||
fromPort: 5432,
|
||||
toPort: 5432,
|
||||
cidrBlocks: [`${addIpToPostgresSecurityGroup}/32`],
|
||||
description: `Public IP for local connection`
|
||||
});
|
||||
}
|
||||
|
||||
const rdsSecurityGroup = new aws.ec2.SecurityGroup(`${stack}-db-sg`, rdsSecurityGroupArgs);
|
||||
|
||||
const rdsSubnets = new aws.rds.SubnetGroup(`${stack}-db-subnet-group`, {
|
||||
name: `${stack}-db-subnet-group`,
|
||||
subnetIds: dbIsPublic ? vpc.publicSubnetIds : vpc.privateSubnetIds
|
||||
});
|
||||
|
||||
const db = new aws.rds.Instance(stack, {
|
||||
allocatedStorage: 10,
|
||||
engine: "postgres",
|
||||
engineVersion: "14.9",
|
||||
identifier: stack, // In RDS
|
||||
dbName: "postgres", // When connected to the DB host
|
||||
instanceClass: dbInstanceClass,
|
||||
port: 5432,
|
||||
publiclyAccessible: dbIsPublic,
|
||||
skipFinalSnapshot: true,
|
||||
storageType: "gp2",
|
||||
username: dbUsername,
|
||||
password: dbPassword,
|
||||
dbSubnetGroupName: rdsSubnets.id,
|
||||
vpcSecurityGroupIds: [rdsSecurityGroup.id],
|
||||
backupRetentionPeriod: 0,
|
||||
applyImmediately: true,
|
||||
allowMajorVersionUpgrade: true,
|
||||
autoMinorVersionUpgrade: true
|
||||
}, {
|
||||
protect: dbIsPublic === false,
|
||||
deleteBeforeReplace: true
|
||||
});
|
||||
|
||||
containerEnvironmentVars.push(
|
||||
{
|
||||
name: "AP_POSTGRES_DATABASE",
|
||||
value: db.dbName
|
||||
},
|
||||
{
|
||||
name: "AP_POSTGRES_HOST",
|
||||
value: db.address
|
||||
},
|
||||
{
|
||||
name: "AP_POSTGRES_PORT",
|
||||
value: pulumi.interpolate`${db.port}`
|
||||
},
|
||||
{
|
||||
name: "AP_POSTGRES_USERNAME",
|
||||
value: db.username
|
||||
},
|
||||
{
|
||||
name: "AP_POSTGRES_PASSWORD",
|
||||
value: config.requireSecret("dbPassword")
|
||||
},
|
||||
{
|
||||
name: "AP_POSTGRES_USE_SSL",
|
||||
value: "false"
|
||||
});
|
||||
|
||||
} else {
|
||||
containerEnvironmentVars.push(
|
||||
{
|
||||
name: "AP_DB_TYPE",
|
||||
value: "SQLITE3"
|
||||
});
|
||||
}
|
||||
|
||||
if (useRedis) {
|
||||
|
||||
const redisCluster = new aws.elasticache.Cluster(`${stack}-redis-cluster`, {
|
||||
clusterId: `${stack}-redis-cluster`,
|
||||
engine: "redis",
|
||||
engineVersion: '7.0',
|
||||
nodeType: redisNodeType,
|
||||
numCacheNodes: 1,
|
||||
parameterGroupName: "default.redis7",
|
||||
port: 6379,
|
||||
subnetGroupName: new aws.elasticache.SubnetGroup(`${stack}-redis-subnet-group`, {
|
||||
name: `${stack}-redis-subnet-group`,
|
||||
subnetIds: vpc.privateSubnetIds
|
||||
}).id,
|
||||
securityGroupIds: [
|
||||
new aws.ec2.SecurityGroup(`${stack}-redis-sg`, {
|
||||
name: `${stack}-redis-sg`,
|
||||
vpcId: vpc.vpcId,
|
||||
ingress: [{
|
||||
protocol: "tcp",
|
||||
fromPort: 6379, // The standard port for Redis
|
||||
toPort: 6379,
|
||||
securityGroups: [fargateSecGroup.id]
|
||||
}],
|
||||
egress: [{
|
||||
protocol: "-1",
|
||||
fromPort: 0,
|
||||
toPort: 0,
|
||||
cidrBlocks: ["0.0.0.0/0"]
|
||||
}]
|
||||
}).id
|
||||
]
|
||||
});
|
||||
|
||||
const redisUrl = pulumi.interpolate`${redisCluster.cacheNodes[0].address}:${redisCluster.cacheNodes[0].port}`;
|
||||
containerEnvironmentVars.push(
|
||||
{
|
||||
name: "AP_REDIS_URL",
|
||||
value: redisUrl
|
||||
});
|
||||
|
||||
} else {
|
||||
containerEnvironmentVars.push(
|
||||
{
|
||||
name: "AP_QUEUE_MODE",
|
||||
value: "MEMORY"
|
||||
});
|
||||
}
|
||||
|
||||
let alb: ApplicationLoadBalancer;
|
||||
// Export the URL so we can easily access it.
|
||||
let frontendUrl;
|
||||
|
||||
if (subDomain && domain) {
|
||||
const fullDomain = `${subDomain}.${domain}`;
|
||||
|
||||
const exampleCertificate = new aws.acm.Certificate(`${stack}-cert`, {
|
||||
domainName: fullDomain,
|
||||
validationMethod: "DNS",
|
||||
});
|
||||
|
||||
const hostedZoneId = aws.route53.getZone({ name: domain }, { async: true }).then(zone => zone.zoneId);
|
||||
|
||||
// DNS records to verify SSL Certificate
|
||||
const certificateValidationDomain = new aws.route53.Record(`${fullDomain}-validation`, {
|
||||
name: exampleCertificate.domainValidationOptions[0].resourceRecordName,
|
||||
zoneId: hostedZoneId,
|
||||
type: exampleCertificate.domainValidationOptions[0].resourceRecordType,
|
||||
records: [exampleCertificate.domainValidationOptions[0].resourceRecordValue],
|
||||
ttl: 600,
|
||||
});
|
||||
|
||||
const certificateValidation = new aws.acm.CertificateValidation(`${fullDomain}-cert-validation`, {
|
||||
certificateArn: exampleCertificate.arn,
|
||||
validationRecordFqdns: [certificateValidationDomain.fqdn],
|
||||
});
|
||||
|
||||
// Creates an ALB associated with our custom VPC.
|
||||
alb = new awsx.lb.ApplicationLoadBalancer(`${stack}-alb`, {
|
||||
securityGroups: [albSecGroup.id],
|
||||
name: `${stack}-alb`,
|
||||
subnetIds: vpc.publicSubnetIds,
|
||||
listeners: [{
|
||||
port: 80, // port on the docker container
|
||||
protocol: "HTTP",
|
||||
defaultActions: [{
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
protocol: "HTTPS",
|
||||
port: "443",
|
||||
statusCode: "HTTP_301",
|
||||
},
|
||||
}]
|
||||
},
|
||||
{
|
||||
protocol: "HTTPS",
|
||||
port: 443,
|
||||
certificateArn: certificateValidation.certificateArn
|
||||
}],
|
||||
defaultTargetGroup: {
|
||||
name: `${stack}-alb-tg`,
|
||||
port: 80 // port on the docker container ,
|
||||
}
|
||||
});
|
||||
|
||||
// Create a DNS record for the load balancer
|
||||
const albDomain = new aws.route53.Record(fullDomain, {
|
||||
name: fullDomain,
|
||||
zoneId: hostedZoneId,
|
||||
type: "CNAME",
|
||||
records: [alb.loadBalancer.dnsName],
|
||||
ttl: 600,
|
||||
});
|
||||
|
||||
frontendUrl = pulumi.interpolate`https://${subDomain}.${domain}`;
|
||||
|
||||
} else {
|
||||
|
||||
// Creates an ALB associated with our custom VPC.
|
||||
alb = new awsx.lb.ApplicationLoadBalancer(`${stack}-alb`, {
|
||||
securityGroups: [albSecGroup.id],
|
||||
name: `${stack}-alb`,
|
||||
subnetIds: vpc.publicSubnetIds,
|
||||
listeners: [{
|
||||
port: 80, // exposed port from the docker file
|
||||
protocol: "HTTP"
|
||||
}],
|
||||
defaultTargetGroup: {
|
||||
name: `${stack}-alb-tg`,
|
||||
port: 80, // port on the docker container
|
||||
protocol: "HTTP"
|
||||
}
|
||||
});
|
||||
|
||||
frontendUrl = pulumi.interpolate`http://${alb.loadBalancer.dnsName}`;
|
||||
}
|
||||
|
||||
const environmentVariables = [
|
||||
...containerEnvironmentVars,
|
||||
{
|
||||
name: "AP_ENGINE_EXECUTABLE_PATH",
|
||||
value: "dist/packages/engine/main.js"
|
||||
},
|
||||
{
|
||||
name: "AP_ENCRYPTION_KEY",
|
||||
value: apEncryptionKey
|
||||
},
|
||||
{
|
||||
name: "AP_JWT_SECRET",
|
||||
value: apJwtSecret
|
||||
},
|
||||
{
|
||||
name: "AP_ENVIRONMENT",
|
||||
value: "prod"
|
||||
},
|
||||
{
|
||||
name: "AP_FRONTEND_URL",
|
||||
value: frontendUrl
|
||||
},
|
||||
{
|
||||
name: "AP_TRIGGER_DEFAULT_POLL_INTERVAL",
|
||||
value: "5"
|
||||
},
|
||||
{
|
||||
name: "AP_EXECUTION_MODE",
|
||||
value: "UNSANDBOXED"
|
||||
},
|
||||
{
|
||||
name: "AP_REDIS_USE_SSL",
|
||||
value: "false"
|
||||
},
|
||||
{
|
||||
name: "AP_SANDBOX_RUN_TIME_SECONDS",
|
||||
value: "600"
|
||||
},
|
||||
{
|
||||
name: "AP_TELEMETRY_ENABLED",
|
||||
value: "true"
|
||||
},
|
||||
{
|
||||
name: "AP_TEMPLATES_SOURCE_URL",
|
||||
value: "https://cloud.activepieces.com/api/v1/templates"
|
||||
}
|
||||
];
|
||||
|
||||
const fargateService = new awsx.ecs.FargateService(`${stack}-fg`, {
|
||||
name: `${stack}-fg`,
|
||||
cluster: (new aws.ecs.Cluster(`${stack}-cluster`, {
|
||||
name: `${stack}-cluster`
|
||||
})).arn,
|
||||
networkConfiguration: {
|
||||
subnets: vpc.publicSubnetIds,
|
||||
securityGroups: [fargateSecGroup.id],
|
||||
assignPublicIp: true
|
||||
},
|
||||
desiredCount: containerInstances,
|
||||
taskDefinitionArgs: {
|
||||
family: `${stack}-fg-task-definition`,
|
||||
container: {
|
||||
name: "activepieces",
|
||||
image: imageName,
|
||||
cpu: containerCpu,
|
||||
memory: containerMemory,
|
||||
portMappings: [{
|
||||
targetGroup: alb.defaultTargetGroup,
|
||||
}],
|
||||
environment: environmentVariables
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pulumi.log.info("Finished running Pulumi");
|
||||
|
||||
export const _ = {
|
||||
activePiecesUrl: frontendUrl,
|
||||
activepiecesEnv: environmentVariables
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "pulumi",
|
||||
"main": "index.ts",
|
||||
"devDependencies": {
|
||||
"@types/node": "^18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "^3.0.0",
|
||||
"@pulumi/aws": "^6.0.0",
|
||||
"@pulumi/awsx": "^2.20.0",
|
||||
"@pulumi/docker": "^4.4.0"
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
/**
|
||||
* isTaggable returns true if the given resource type is an AWS resource that supports tags.
|
||||
*/
|
||||
export function isTaggable(t: string): boolean {
|
||||
return (taggableResourceTypes.indexOf(t) !== -1);
|
||||
}
|
||||
|
||||
// taggableResourceTypes is a list of known AWS type tokens that are taggable.
|
||||
const taggableResourceTypes = [
|
||||
"aws:accessanalyzer/analyzer:Analyzer",
|
||||
"aws:acm/certificate:Certificate",
|
||||
"aws:acmpca/certificateAuthority:CertificateAuthority",
|
||||
"aws:alb/loadBalancer:LoadBalancer",
|
||||
"aws:alb/targetGroup:TargetGroup",
|
||||
"aws:apigateway/apiKey:ApiKey",
|
||||
"aws:apigateway/clientCertificate:ClientCertificate",
|
||||
"aws:apigateway/domainName:DomainName",
|
||||
"aws:apigateway/restApi:RestApi",
|
||||
"aws:apigateway/stage:Stage",
|
||||
"aws:apigateway/usagePlan:UsagePlan",
|
||||
"aws:apigateway/vpcLink:VpcLink",
|
||||
"aws:applicationloadbalancing/loadBalancer:LoadBalancer",
|
||||
"aws:applicationloadbalancing/targetGroup:TargetGroup",
|
||||
"aws:appmesh/mesh:Mesh",
|
||||
"aws:appmesh/route:Route",
|
||||
"aws:appmesh/virtualNode:VirtualNode",
|
||||
"aws:appmesh/virtualRouter:VirtualRouter",
|
||||
"aws:appmesh/virtualService:VirtualService",
|
||||
"aws:appsync/graphQLApi:GraphQLApi",
|
||||
"aws:athena/workgroup:Workgroup",
|
||||
"aws:autoscaling/group:Group",
|
||||
"aws:backup/plan:Plan",
|
||||
"aws:backup/vault:Vault",
|
||||
"aws:cfg/aggregateAuthorization:AggregateAuthorization",
|
||||
"aws:cfg/configurationAggregator:ConfigurationAggregator",
|
||||
"aws:cfg/rule:Rule",
|
||||
"aws:cloudformation/stack:Stack",
|
||||
"aws:cloudformation/stackSet:StackSet",
|
||||
"aws:cloudfront/distribution:Distribution",
|
||||
"aws:cloudhsmv2/cluster:Cluster",
|
||||
"aws:cloudtrail/trail:Trail",
|
||||
"aws:cloudwatch/eventRule:EventRule",
|
||||
"aws:cloudwatch/logGroup:LogGroup",
|
||||
"aws:cloudwatch/metricAlarm:MetricAlarm",
|
||||
"aws:codebuild/project:Project",
|
||||
"aws:codecommit/repository:Repository",
|
||||
"aws:codepipeline/pipeline:Pipeline",
|
||||
"aws:codepipeline/webhook:Webhook",
|
||||
"aws:codestarnotifications/notificationRule:NotificationRule",
|
||||
"aws:cognito/identityPool:IdentityPool",
|
||||
"aws:cognito/userPool:UserPool",
|
||||
"aws:datapipeline/pipeline:Pipeline",
|
||||
"aws:datasync/agent:Agent",
|
||||
"aws:datasync/efsLocation:EfsLocation",
|
||||
"aws:datasync/locationSmb:LocationSmb",
|
||||
"aws:datasync/nfsLocation:NfsLocation",
|
||||
"aws:datasync/s3Location:S3Location",
|
||||
"aws:datasync/task:Task",
|
||||
"aws:dax/cluster:Cluster",
|
||||
"aws:directconnect/connection:Connection",
|
||||
"aws:directconnect/hostedPrivateVirtualInterfaceAccepter:HostedPrivateVirtualInterfaceAccepter",
|
||||
"aws:directconnect/hostedPublicVirtualInterfaceAccepter:HostedPublicVirtualInterfaceAccepter",
|
||||
"aws:directconnect/hostedTransitVirtualInterfaceAcceptor:HostedTransitVirtualInterfaceAcceptor",
|
||||
"aws:directconnect/linkAggregationGroup:LinkAggregationGroup",
|
||||
"aws:directconnect/privateVirtualInterface:PrivateVirtualInterface",
|
||||
"aws:directconnect/publicVirtualInterface:PublicVirtualInterface",
|
||||
"aws:directconnect/transitVirtualInterface:TransitVirtualInterface",
|
||||
"aws:directoryservice/directory:Directory",
|
||||
"aws:dlm/lifecyclePolicy:LifecyclePolicy",
|
||||
"aws:dms/endpoint:Endpoint",
|
||||
"aws:dms/replicationInstance:ReplicationInstance",
|
||||
"aws:dms/replicationSubnetGroup:ReplicationSubnetGroup",
|
||||
"aws:dms/replicationTask:ReplicationTask",
|
||||
"aws:docdb/cluster:Cluster",
|
||||
"aws:docdb/clusterInstance:ClusterInstance",
|
||||
"aws:docdb/clusterParameterGroup:ClusterParameterGroup",
|
||||
"aws:docdb/subnetGroup:SubnetGroup",
|
||||
"aws:dynamodb/table:Table",
|
||||
"aws:ebs/snapshot:Snapshot",
|
||||
"aws:ebs/snapshotCopy:SnapshotCopy",
|
||||
"aws:ebs/volume:Volume",
|
||||
"aws:ec2/ami:Ami",
|
||||
"aws:ec2/amiCopy:AmiCopy",
|
||||
"aws:ec2/amiFromInstance:AmiFromInstance",
|
||||
"aws:ec2/capacityReservation:CapacityReservation",
|
||||
"aws:ec2/customerGateway:CustomerGateway",
|
||||
"aws:ec2/defaultNetworkAcl:DefaultNetworkAcl",
|
||||
"aws:ec2/defaultRouteTable:DefaultRouteTable",
|
||||
"aws:ec2/defaultSecurityGroup:DefaultSecurityGroup",
|
||||
"aws:ec2/defaultSubnet:DefaultSubnet",
|
||||
"aws:ec2/defaultVpc:DefaultVpc",
|
||||
"aws:ec2/defaultVpcDhcpOptions:DefaultVpcDhcpOptions",
|
||||
"aws:ec2/eip:Eip",
|
||||
"aws:ec2/fleet:Fleet",
|
||||
"aws:ec2/instance:Instance",
|
||||
"aws:ec2/internetGateway:InternetGateway",
|
||||
"aws:ec2/keyPair:KeyPair",
|
||||
"aws:ec2/launchTemplate:LaunchTemplate",
|
||||
"aws:ec2/natGateway:NatGateway",
|
||||
"aws:ec2/networkAcl:NetworkAcl",
|
||||
"aws:ec2/networkInterface:NetworkInterface",
|
||||
"aws:ec2/placementGroup:PlacementGroup",
|
||||
"aws:ec2/routeTable:RouteTable",
|
||||
"aws:ec2/securityGroup:SecurityGroup",
|
||||
"aws:ec2/spotInstanceRequest:SpotInstanceRequest",
|
||||
"aws:ec2/subnet:Subnet",
|
||||
"aws:ec2/vpc:Vpc",
|
||||
"aws:ec2/vpcDhcpOptions:VpcDhcpOptions",
|
||||
"aws:ec2/vpcEndpoint:VpcEndpoint",
|
||||
"aws:ec2/vpcEndpointService:VpcEndpointService",
|
||||
"aws:ec2/vpcPeeringConnection:VpcPeeringConnection",
|
||||
"aws:ec2/vpcPeeringConnectionAccepter:VpcPeeringConnectionAccepter",
|
||||
"aws:ec2/vpnConnection:VpnConnection",
|
||||
"aws:ec2/vpnGateway:VpnGateway",
|
||||
"aws:ec2clientvpn/endpoint:Endpoint",
|
||||
"aws:ec2transitgateway/routeTable:RouteTable",
|
||||
"aws:ec2transitgateway/transitGateway:TransitGateway",
|
||||
"aws:ec2transitgateway/vpcAttachment:VpcAttachment",
|
||||
"aws:ec2transitgateway/vpcAttachmentAccepter:VpcAttachmentAccepter",
|
||||
"aws:ecr/repository:Repository",
|
||||
"aws:ecs/capacityProvider:CapacityProvider",
|
||||
"aws:ecs/cluster:Cluster",
|
||||
"aws:ecs/service:Service",
|
||||
"aws:ecs/taskDefinition:TaskDefinition",
|
||||
"aws:efs/fileSystem:FileSystem",
|
||||
"aws:eks/cluster:Cluster",
|
||||
"aws:eks/fargateProfile:FargateProfile",
|
||||
"aws:eks/nodeGroup:NodeGroup",
|
||||
"aws:elasticache/cluster:Cluster",
|
||||
"aws:elasticache/replicationGroup:ReplicationGroup",
|
||||
"aws:elasticbeanstalk/application:Application",
|
||||
"aws:elasticbeanstalk/applicationVersion:ApplicationVersion",
|
||||
"aws:elasticbeanstalk/environment:Environment",
|
||||
"aws:elasticloadbalancing/loadBalancer:LoadBalancer",
|
||||
"aws:elasticloadbalancingv2/loadBalancer:LoadBalancer",
|
||||
"aws:elasticloadbalancingv2/targetGroup:TargetGroup",
|
||||
"aws:elasticsearch/domain:Domain",
|
||||
"aws:elb/loadBalancer:LoadBalancer",
|
||||
"aws:emr/cluster:Cluster",
|
||||
"aws:fsx/lustreFileSystem:LustreFileSystem",
|
||||
"aws:fsx/windowsFileSystem:WindowsFileSystem",
|
||||
"aws:gamelift/alias:Alias",
|
||||
"aws:gamelift/build:Build",
|
||||
"aws:gamelift/fleet:Fleet",
|
||||
"aws:gamelift/gameSessionQueue:GameSessionQueue",
|
||||
"aws:glacier/vault:Vault",
|
||||
"aws:glue/crawler:Crawler",
|
||||
"aws:glue/job:Job",
|
||||
"aws:glue/trigger:Trigger",
|
||||
"aws:iam/role:Role",
|
||||
"aws:iam/user:User",
|
||||
"aws:inspector/resourceGroup:ResourceGroup",
|
||||
"aws:kinesis/analyticsApplication:AnalyticsApplication",
|
||||
"aws:kinesis/firehoseDeliveryStream:FirehoseDeliveryStream",
|
||||
"aws:kinesis/stream:Stream",
|
||||
"aws:kms/externalKey:ExternalKey",
|
||||
"aws:kms/key:Key",
|
||||
"aws:lambda/function:Function",
|
||||
"aws:lb/loadBalancer:LoadBalancer",
|
||||
"aws:lb/targetGroup:TargetGroup",
|
||||
"aws:licensemanager/licenseConfiguration:LicenseConfiguration",
|
||||
"aws:lightsail/instance:Instance",
|
||||
"aws:mediaconvert/queue:Queue",
|
||||
"aws:mediapackage/channel:Channel",
|
||||
"aws:mediastore/container:Container",
|
||||
"aws:mq/broker:Broker",
|
||||
"aws:mq/configuration:Configuration",
|
||||
"aws:msk/cluster:Cluster",
|
||||
"aws:neptune/cluster:Cluster",
|
||||
"aws:neptune/clusterInstance:ClusterInstance",
|
||||
"aws:neptune/clusterParameterGroup:ClusterParameterGroup",
|
||||
"aws:neptune/eventSubscription:EventSubscription",
|
||||
"aws:neptune/parameterGroup:ParameterGroup",
|
||||
"aws:neptune/subnetGroup:SubnetGroup",
|
||||
"aws:opsworks/stack:Stack",
|
||||
"aws:organizations/account:Account",
|
||||
"aws:pinpoint/app:App",
|
||||
"aws:qldb/ledger:Ledger",
|
||||
"aws:ram/resourceShare:ResourceShare",
|
||||
"aws:rds/cluster:Cluster",
|
||||
"aws:rds/clusterEndpoint:ClusterEndpoint",
|
||||
"aws:rds/clusterInstance:ClusterInstance",
|
||||
"aws:rds/clusterParameterGroup:ClusterParameterGroup",
|
||||
"aws:rds/clusterSnapshot:ClusterSnapshot",
|
||||
"aws:rds/eventSubscription:EventSubscription",
|
||||
"aws:rds/instance:Instance",
|
||||
"aws:rds/optionGroup:OptionGroup",
|
||||
"aws:rds/parameterGroup:ParameterGroup",
|
||||
"aws:rds/securityGroup:SecurityGroup",
|
||||
"aws:rds/snapshot:Snapshot",
|
||||
"aws:rds/subnetGroup:SubnetGroup",
|
||||
"aws:redshift/cluster:Cluster",
|
||||
"aws:redshift/eventSubscription:EventSubscription",
|
||||
"aws:redshift/parameterGroup:ParameterGroup",
|
||||
"aws:redshift/snapshotCopyGrant:SnapshotCopyGrant",
|
||||
"aws:redshift/snapshotSchedule:SnapshotSchedule",
|
||||
"aws:redshift/subnetGroup:SubnetGroup",
|
||||
"aws:resourcegroups/group:Group",
|
||||
"aws:route53/healthCheck:HealthCheck",
|
||||
"aws:route53/resolverEndpoint:ResolverEndpoint",
|
||||
"aws:route53/resolverRule:ResolverRule",
|
||||
"aws:route53/zone:Zone",
|
||||
"aws:s3/bucket:Bucket",
|
||||
"aws:s3/bucketObject:BucketObject",
|
||||
"aws:sagemaker/endpoint:Endpoint",
|
||||
"aws:sagemaker/endpointConfiguration:EndpointConfiguration",
|
||||
"aws:sagemaker/model:Model",
|
||||
"aws:sagemaker/notebookInstance:NotebookInstance",
|
||||
"aws:secretsmanager/secret:Secret",
|
||||
"aws:servicecatalog/portfolio:Portfolio",
|
||||
"aws:sfn/activity:Activity",
|
||||
"aws:sfn/stateMachine:StateMachine",
|
||||
"aws:sns/topic:Topic",
|
||||
"aws:sqs/queue:Queue",
|
||||
"aws:ssm/activation:Activation",
|
||||
"aws:ssm/document:Document",
|
||||
"aws:ssm/maintenanceWindow:MaintenanceWindow",
|
||||
"aws:ssm/parameter:Parameter",
|
||||
"aws:ssm/patchBaseline:PatchBaseline",
|
||||
"aws:storagegateway/cachesIscsiVolume:CachesIscsiVolume",
|
||||
"aws:storagegateway/gateway:Gateway",
|
||||
"aws:storagegateway/nfsFileShare:NfsFileShare",
|
||||
"aws:storagegateway/smbFileShare:SmbFileShare",
|
||||
"aws:swf/domain:Domain",
|
||||
"aws:transfer/server:Server",
|
||||
"aws:transfer/user:User",
|
||||
"aws:waf/rateBasedRule:RateBasedRule",
|
||||
"aws:waf/rule:Rule",
|
||||
"aws:waf/ruleGroup:RuleGroup",
|
||||
"aws:waf/webAcl:WebAcl",
|
||||
"aws:wafregional/rateBasedRule:RateBasedRule",
|
||||
"aws:wafregional/rule:Rule",
|
||||
"aws:wafregional/ruleGroup:RuleGroup",
|
||||
"aws:wafregional/webAcl:WebAcl",
|
||||
"aws:workspaces/directory:Directory",
|
||||
"aws:workspaces/ipGroup:IpGroup",
|
||||
];
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"outDir": "bin",
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"pretty": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": false,
|
||||
"types": ["node"]
|
||||
},
|
||||
"files": [
|
||||
"index.ts"
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"id":"du7O4b0e8P"}
|
||||
@@ -1,23 +0,0 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:14.4
|
||||
environment:
|
||||
POSTGRES_DB: activepieces
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: A79Vm5D4p2VQHOp2gd5
|
||||
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
redis:
|
||||
image: redis:7.0.7
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
@@ -1,28 +0,0 @@
|
||||
services:
|
||||
app:
|
||||
extends:
|
||||
file: docker-compose.dev.yml
|
||||
service: app
|
||||
user: "${UID}:${GID}"
|
||||
command: /bin/sh -c "npm_config_cache=/usr/src/app/.npm-cache npx nx run-tests backend"
|
||||
|
||||
postgres:
|
||||
extends:
|
||||
file: docker-compose.dev.yml
|
||||
service: postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
|
||||
redis:
|
||||
extends:
|
||||
file: docker-compose.dev.yml
|
||||
service: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
volumes:
|
||||
postgres_data_dev:
|
||||
redis_data_dev:
|
||||
|
||||
networks:
|
||||
activepieces_dev:
|
||||
@@ -1,43 +0,0 @@
|
||||
services:
|
||||
activepieces:
|
||||
image: ghcr.io/activepieces/activepieces:0.74.3
|
||||
container_name: activepieces
|
||||
restart: unless-stopped
|
||||
## Enable the following line if you already use AP_EXECUTION_MODE with SANDBOX_PROCESS or old activepieces, checking the breaking change documentation for more info.
|
||||
## privileged: true
|
||||
ports:
|
||||
- '8080:80'
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./cache:/usr/src/app/cache
|
||||
networks:
|
||||
- activepieces
|
||||
postgres:
|
||||
image: 'postgres:14.4'
|
||||
container_name: postgres
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
- 'POSTGRES_DB=${AP_POSTGRES_DATABASE}'
|
||||
- 'POSTGRES_PASSWORD=${AP_POSTGRES_PASSWORD}'
|
||||
- 'POSTGRES_USER=${AP_POSTGRES_USERNAME}'
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- activepieces
|
||||
redis:
|
||||
image: 'redis:7.0.7'
|
||||
container_name: redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- 'redis_data:/data'
|
||||
networks:
|
||||
- activepieces
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
networks:
|
||||
activepieces:
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set default values if not provided
|
||||
export AP_APP_TITLE="${AP_APP_TITLE:-Activepieces}"
|
||||
export AP_FAVICON_URL="${AP_FAVICON_URL:-https://cdn.activepieces.com/brand/favicon.ico}"
|
||||
|
||||
# Debug: Print environment variables
|
||||
echo "AP_APP_TITLE: $AP_APP_TITLE"
|
||||
echo "AP_FAVICON_URL: $AP_FAVICON_URL"
|
||||
|
||||
# Process environment variables in index.html BEFORE starting services
|
||||
envsubst '${AP_APP_TITLE} ${AP_FAVICON_URL}' < /usr/share/nginx/html/index.html > /usr/share/nginx/html/index.html.tmp && \
|
||||
mv /usr/share/nginx/html/index.html.tmp /usr/share/nginx/html/index.html
|
||||
|
||||
|
||||
# Start Nginx server
|
||||
nginx -g "daemon off;" &
|
||||
|
||||
# Start backend server
|
||||
if [ "$AP_CONTAINER_TYPE" = "APP" ] && [ "$AP_PM2_ENABLED" = "true" ]; then
|
||||
echo "Starting backend server with PM2 (APP mode)"
|
||||
pm2-runtime start dist/packages/server/api/main.cjs --name "activepieces-app" --node-args="--enable-source-maps" -i 0
|
||||
else
|
||||
echo "Starting backend server with Node.js (WORKER mode or default)"
|
||||
node --enable-source-maps dist/packages/server/api/main.cjs
|
||||
fi
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Mintlify
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Mintlify Starter Kit
|
||||
|
||||
Use the starter kit to get your docs deployed and ready to customize.
|
||||
|
||||
Click the green **Use this template** button at the top of this repo to copy the Mintlify starter kit. The starter kit contains examples with
|
||||
|
||||
- Guide pages
|
||||
- Navigation
|
||||
- Customizations
|
||||
- API reference pages
|
||||
- Use of popular components
|
||||
|
||||
**[Follow the full quickstart guide](https://starter.mintlify.com/quickstart)**
|
||||
|
||||
## Development
|
||||
|
||||
Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command:
|
||||
|
||||
```
|
||||
npm i -g mint
|
||||
```
|
||||
|
||||
Run the following command at the root of your documentation, where your `docs.json` is located:
|
||||
|
||||
```
|
||||
mint dev
|
||||
```
|
||||
|
||||
View your local preview at `http://localhost:3000`.
|
||||
|
||||
## Publishing changes
|
||||
|
||||
Install our GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app) to propagate changes from your repo to your deployment. Changes are deployed to production automatically after pushing to the default branch.
|
||||
|
||||
## Need help?
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- If your dev environment isn't running: Run `mint update` to ensure you have the most recent version of the CLI.
|
||||
- If a page loads as a 404: Make sure you are running in a folder with a valid `docs.json`.
|
||||
|
||||
### Resources
|
||||
- [Mintlify documentation](https://mintlify.com/docs)
|
||||
@@ -1,3 +0,0 @@
|
||||
<Tip>
|
||||
This feature is available in our paid editions. Contact us [here](https://www.activepieces.com/sales), and we'll be delighted to assist you!
|
||||
</Tip>
|
||||
@@ -1,6 +0,0 @@
|
||||
| Name | Supports NPM in Code Piece | Requires Docker to be Privileged | Performance | Secure for Multi Tenant | Reusable Workers | Environment Variable |
|
||||
|-------------------------------|----------------------------|----------------------------------|-----------------------|-------------------------|------------------|-------------------------------------------|
|
||||
| V8/Code Sandboxing | ❌ | No | Fast & Lightweight | ✅ | ✅ | Set `AP_EXECUTION_MODE` to `SANDBOX_CODE_ONLY` |
|
||||
| No Sandboxing | ✅ | No | Fast & Lightweight | ❌ | ✅ | Set `AP_EXECUTION_MODE` to `UNSANDBOXED` |
|
||||
| Kernel Namespaces Sandboxing | ✅ | Yes | Slow & CPU Intensive | ✅ | ❌ | Set `AP_EXECUTION_MODE` to `SANDBOX_PROCESS` |
|
||||
| Combined Sandboxing | ❌ | Yes | Medium & CPU Intensive | ✅ | ✅ | Set `AP_EXECUTION_MODE` to `SANDBOX_CODE_AND_PROCESS` |
|
||||
@@ -1,3 +0,0 @@
|
||||
<Tip>
|
||||
If you would like your users to use your own OAuth2 apps, we recommend you check [this](/admin-guide/guides/manage-oauth2).
|
||||
</Tip>
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
title: "Changelog"
|
||||
description: "A log of all notable changes to Activepieces"
|
||||
icon: "code-commit"
|
||||
url: "https://github.com/activepieces/activepieces/releases"
|
||||
---
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
title: "i18n Translations"
|
||||
description: ""
|
||||
icon: "language"
|
||||
---
|
||||
|
||||
|
||||
This guide helps you understand how to change or add new translations.
|
||||
|
||||
Activepieces uses Crowdin because it helps translators who don't know how to code. It also makes the approval process easier. Activepieces automatically sync new text from the code and translations back into the code.
|
||||
|
||||
## Contribute to existing translations
|
||||
|
||||
1. Create Crowdin account
|
||||
2. Join the project https://crowdin.com/project/activepieces
|
||||
|
||||

|
||||
|
||||
3. Click on the language you want to translate
|
||||
|
||||
4. Click on "Translate All"
|
||||
|
||||

|
||||
|
||||
5. Select Strings you want to translate and click on "Save" button
|
||||
|
||||
|
||||
## Adding a new language
|
||||
- Please contact us (support@activepieces.com) if you want to add a new language. We will add it to the project and you can start translating.
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: "License"
|
||||
description: ""
|
||||
icon: 'file-contract'
|
||||
---
|
||||
|
||||
Activepieces' **core** is released as open source under the [MIT license](https://github.com/activepieces/activepieces/blob/main/LICENSE) and enterprise / cloud editions features are released under [Commercial License](https://github.com/activepieces/activepieces/blob/main/packages/ee/LICENSE)
|
||||
|
||||
The MIT license is a permissive license that grants users the freedom to use, modify, or distribute the software without any significant restrictions. The only requirement is that you include the license notice along with the software when distributing it.
|
||||
|
||||
Using the enterprise features (under the packages/ee and packages/server/api/src/app/ee folder) with a self-hosted instance requires an Activepieces license. If you are looking for these features, contact us at [sales@activepieces.com](mailto:sales@activepieces.com).
|
||||
|
||||
**Benefits of Dual Licensing Repo**
|
||||
|
||||
- **Transparency** - Everyone can see what we are doing and contribute to the project.
|
||||
- **Clarity** - Everyone can see what the difference is between the open source and commercial versions of our software.
|
||||
- **Audit** - Everyone can audit our code and see what we are doing.
|
||||
- **Faster Development** - We can develop faster and more efficiently.
|
||||
|
||||
<Tip>
|
||||
If you are still confused or have feedback, please open an issue on GitHub or send a message in the #contribution channel on Discord.
|
||||
</Tip>
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
title: "Override OAuth2 Apps"
|
||||
description: "Use your own OAuth2 credentials instead of the default Activepieces apps"
|
||||
icon: "lock"
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
## Default Behavior
|
||||
|
||||
When users connect to services like Google Sheets or Slack, they see "Activepieces" as the app requesting access. This works out of the box with no setup required.
|
||||
|
||||
## Why Replace OAuth2 Apps?
|
||||
|
||||
- **Branding**: Show your company name instead of "Activepieces" in authorization screens
|
||||
- **Higher Limits**: Some services have stricter rate limits for shared OAuth apps
|
||||
- **Compliance**: Your organization may require using company-owned credentials
|
||||
|
||||
## How to Configure
|
||||
|
||||
1. Go to **Platform Admin → Setup → Pieces**
|
||||
2. Find the piece you want to configure (e.g., Google Sheets)
|
||||
3. Click the lock icon to open the OAuth2 settings
|
||||
4. Enter your own Client ID and Client Secret
|
||||
|
||||

|
||||
@@ -1,88 +0,0 @@
|
||||
---
|
||||
title: "How to Manage Pieces"
|
||||
description: "Control which integrations are available to your users"
|
||||
icon: "puzzle-piece"
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
## Overview
|
||||
|
||||
**Pieces** are the building blocks of Activepieces — they are integrations and connectors (like Google Sheets, Slack, OpenAI, etc.) that users can use in their automation flows.
|
||||
|
||||
As a platform administrator, you have full control over which pieces are available to your users. This allows you to:
|
||||
|
||||
- **Enforce security policies** by restricting access to certain integrations
|
||||
- **Simplify the user experience** by showing only relevant pieces for your use case
|
||||
- **Deploy custom/private pieces** that are specific to your organization
|
||||
|
||||
There are **two levels** of piece management:
|
||||
|
||||
| Level | Who Can Manage | Scope |
|
||||
|-------|----------------|-------|
|
||||
| **Platform Level** | Platform Admin | Install and remove across the entire platform |
|
||||
| **Project Level** | Project Admin | Show/hide specific pieces for specfic project |
|
||||
|
||||
---
|
||||
|
||||
## Platform-Level Management
|
||||
|
||||
Platform administrators can manage pieces for the entire Activepieces instance from **Platform Admin → Setup → Pieces**.
|
||||
|
||||
## Project-Level Management
|
||||
|
||||
Project administrators can further restrict which pieces are available within their specific project. This is useful when different teams or projects need access to different integrations.
|
||||
|
||||
### Show/Hide Pieces in a Project
|
||||
|
||||
<Steps>
|
||||
<Step title="Open Project Settings">
|
||||
Navigate to your project and go to **Settings → Pieces**.
|
||||
</Step>
|
||||
<Step title="Configure Visibility">
|
||||
You'll see a list of all pieces installed on the platform. Toggle the visibility for each piece:
|
||||
- **Enabled**: Users in this project can use the piece
|
||||
- **Disabled**: The piece is hidden from users in this project
|
||||
</Step>
|
||||
<Step title="Save Changes">
|
||||
Changes take effect immediately — users will only see the enabled pieces when building their flows.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||

|
||||

|
||||
|
||||
<Note>
|
||||
Project-level settings can only **hide** pieces that are installed at the platform level. You cannot add pieces at the project level that aren't already installed on the platform.
|
||||
</Note>
|
||||
|
||||
|
||||
### Install Private Pieces
|
||||
|
||||
<Tip>
|
||||
For detailed instructions on building custom pieces, check the [Building Pieces](/build-pieces/building-pieces/overview) documentation.
|
||||
</Tip>
|
||||
|
||||
|
||||
If you've built a custom piece for your organization, you can upload it directly as a tarball (`.tgz`) file.
|
||||
|
||||
<Steps>
|
||||
<Step title="Build Your Piece">
|
||||
Build your piece using the Activepieces CLI:
|
||||
```bash
|
||||
npm run pieces -- build --name=your-piece-name
|
||||
```
|
||||
This generates a tarball in `dist/packages/pieces/your-piece-name`.
|
||||
</Step>
|
||||
<Step title="Navigate to Pieces Settings">
|
||||
Go to **Platform Admin → Setup → Pieces** and click **Install Piece**.
|
||||
</Step>
|
||||
<Step title="Select File Upload">
|
||||
Choose **Upload File** as the installation source.
|
||||
</Step>
|
||||
<Step title="Upload the Tarball">
|
||||
Select the `.tgz` file from your build output and upload it.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||

|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
title: "Manage User Roles"
|
||||
description: "Documentation on project permissions in Activepieces"
|
||||
icon: 'user'
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
Activepieces utilizes Role-Based Access Control (RBAC) for managing permissions within projects. Each project consists of multiple flows and users, with each user assigned specific roles that define their actions within the project.
|
||||
|
||||
## Default Roles
|
||||
|
||||
Activepieces comes with four standard roles out of the box. The table below shows the permissions for each role:
|
||||
|
||||
| Permission | Admin | Editor | Operator | Viewer |
|
||||
|------------|:-----:|:------:|:--------:|:------:|
|
||||
| **Flows** |||||
|
||||
| View Flows | ✓ | ✓ | ✓ | ✓ |
|
||||
| Edit Flows | ✓ | ✓ | | |
|
||||
| Publish / Toggle Flows | ✓ | ✓ | ✓ | |
|
||||
| **Runs** |||||
|
||||
| View Runs | ✓ | ✓ | ✓ | ✓ |
|
||||
| Retry Runs | ✓ | ✓ | ✓ | |
|
||||
| **Connections** |||||
|
||||
| View Connections | ✓ | ✓ | ✓ | ✓ |
|
||||
| Edit Connections | ✓ | ✓ | ✓ | |
|
||||
| **Team** |||||
|
||||
| View Project Members | ✓ | ✓ | ✓ | ✓ |
|
||||
| Add/Remove Project Members | ✓ | | | |
|
||||
| **Git Sync** | | | | |
|
||||
| Configure Git Repo | ✓ | | | |
|
||||
| Pull Flows from Git | ✓ | | | |
|
||||
| Push Flows to Git | ✓ | | | |
|
||||
|
||||
## Custom Roles
|
||||
|
||||
If the default roles don't fit your needs, you can create custom roles with specific permissions.
|
||||
|
||||
<Steps>
|
||||
<Step title="Navigate to Project Roles">
|
||||
Go to **Platform Admin** → **Security** → **Project Roles**
|
||||
</Step>
|
||||
<Step title="Create a New Role">
|
||||
Click **Create Role** and give it a name
|
||||
</Step>
|
||||
<Step title="Configure Permissions">
|
||||
Select the specific permissions you want to grant to this role
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Tip>
|
||||
Custom roles are useful when you need fine-grained control, such as allowing users to view and retry runs without being able to edit flows.
|
||||
</Tip>
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: "Setup AI Providers"
|
||||
description: ""
|
||||
icon: "sparkles"
|
||||
---
|
||||
|
||||
AI providers are configured by the platform admin to centrally manage credentials and access, making [AI pieces](https://www.activepieces.com/pieces/ai) and their features available to everyone in all projects.
|
||||
|
||||
## Supported Providers
|
||||
|
||||
- **OpenAI**
|
||||
- **Anthropic**
|
||||
- **Gemini**
|
||||
- **Vercel AI Gateway**
|
||||
- **Cloudflare AI Gateway**
|
||||
|
||||
## How to Setup
|
||||
|
||||
Go to **Admin Console** → **AI** page. Add your provider's base URL and API key. These settings apply to all projects.
|
||||
|
||||

|
||||
|
||||
## Cost Control & Logging
|
||||
|
||||
Use an AI gateway like **Vercel AI Gateway** or **Cloudflare AI Gateway** to:
|
||||
|
||||
- Set rate limits and budgets
|
||||
- Log and monitor all AI requests
|
||||
- Track usage across projects
|
||||
|
||||
Just set the gateway URL as your provider's base URL in the Admin Console.
|
||||
@@ -1,223 +0,0 @@
|
||||
---
|
||||
title: "How to Setup SSO"
|
||||
description: "Configure Single Sign-On (SSO) to enable secure, centralized authentication for your Activepieces platform"
|
||||
icon: 'key'
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
## Overview
|
||||
|
||||
Single Sign-On (SSO) allows your team to authenticate using your organization's existing identity provider, eliminating the need for separate Activepieces credentials. This improves security, simplifies user management, and provides a seamless login experience.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before configuring SSO, ensure you have:
|
||||
|
||||
- **Admin access** to your Activepieces platform
|
||||
- **Admin access** to your identity provider (Google, GitHub, Okta, or JumpCloud)
|
||||
- The **redirect URL** from your Activepieces SSO configuration screen
|
||||
|
||||
## Accessing SSO Configuration
|
||||
|
||||
Navigate to **Platform Settings** → **SSO** in your Activepieces admin dashboard to access the SSO configuration screen.
|
||||
|
||||

|
||||
|
||||
## Enforcing SSO
|
||||
|
||||
You can enforce SSO by specifying your organization's email domain. When SSO enforcement is enabled:
|
||||
|
||||
- Users with matching email domains must authenticate through the SSO provider
|
||||
- Email/password login can be disabled for enhanced security
|
||||
- All authentication is routed through your designated identity provider
|
||||
|
||||
<Tip>
|
||||
We recommend testing SSO with a small group of users before enforcing it organization-wide.
|
||||
</Tip>
|
||||
|
||||
## Supported SSO Providers
|
||||
|
||||
Activepieces supports multiple SSO providers to integrate with your existing identity management system.
|
||||
|
||||
### Google
|
||||
|
||||
<Steps>
|
||||
<Step title="Access Google Cloud Console">
|
||||
Go to the [Google Cloud Console](https://console.cloud.google.com/) and select your project (or create a new one).
|
||||
</Step>
|
||||
<Step title="Create OAuth2 Credentials">
|
||||
Navigate to **APIs & Services** → **Credentials** → **Create Credentials** → **OAuth client ID**.
|
||||
|
||||
Select **Web application** as the application type.
|
||||
</Step>
|
||||
<Step title="Configure Redirect URI">
|
||||
Copy the **Redirect URL** from the Activepieces SSO configuration screen and add it to the **Authorized redirect URIs** in Google Cloud Console.
|
||||
</Step>
|
||||
<Step title="Copy Credentials to Activepieces">
|
||||
Copy the **Client ID** and **Client Secret** from Google and paste them into the corresponding fields in Activepieces.
|
||||
</Step>
|
||||
<Step title="Save Configuration">
|
||||
Click **Finish** to complete the setup.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### GitHub
|
||||
|
||||
<Steps>
|
||||
<Step title="Access GitHub Developer Settings">
|
||||
Go to [GitHub Developer Settings](https://github.com/settings/developers) → **OAuth Apps** → **New OAuth App**.
|
||||
</Step>
|
||||
<Step title="Register New Application">
|
||||
Fill in the application details:
|
||||
- **Application name**: Choose a recognizable name (e.g., "Activepieces SSO")
|
||||
- **Homepage URL**: Enter your Activepieces instance URL
|
||||
</Step>
|
||||
<Step title="Configure Authorization Callback">
|
||||
Copy the **Redirect URL** from the Activepieces SSO configuration screen and paste it into the **Authorization callback URL** field.
|
||||
</Step>
|
||||
<Step title="Complete Registration">
|
||||
Click **Register application** to create the OAuth App.
|
||||
</Step>
|
||||
<Step title="Generate Client Secret">
|
||||
After registration, click **Generate a new client secret** and copy it immediately (it won't be shown again).
|
||||
</Step>
|
||||
<Step title="Copy Credentials to Activepieces">
|
||||
Copy the **Client ID** and **Client Secret** and paste them into the corresponding fields in Activepieces.
|
||||
</Step>
|
||||
<Step title="Save Configuration">
|
||||
Click **Finish** to complete the setup.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### SAML with Okta
|
||||
|
||||
<Steps>
|
||||
<Step title="Create New Application in Okta">
|
||||
Go to the [Okta Admin Portal](https://login.okta.com/) → **Applications** → **Create App Integration**.
|
||||
</Step>
|
||||
<Step title="Select SAML 2.0">
|
||||
Choose **SAML 2.0** as the sign-on method and click **Next**.
|
||||
</Step>
|
||||
<Step title="Configure General Settings">
|
||||
Enter an **App name** (e.g., "Activepieces") and optionally upload a logo. Click **Next**.
|
||||
</Step>
|
||||
<Step title="Configure SAML Settings">
|
||||
- **Single sign-on URL**: Copy the SSO URL from the Activepieces configuration screen
|
||||
- **Audience URI (SP Entity ID)**: Enter `Activepieces`
|
||||
- **Name ID format**: Select `EmailAddress`
|
||||
</Step>
|
||||
<Step title="Add Attribute Statements">
|
||||
Add the following attribute mappings:
|
||||
|
||||
| Name | Value |
|
||||
|------|-------|
|
||||
| `firstName` | `user.firstName` |
|
||||
| `lastName` | `user.lastName` |
|
||||
| `email` | `user.email` |
|
||||
</Step>
|
||||
<Step title="Complete Setup in Okta">
|
||||
Click **Next**, select the appropriate feedback option, and click **Finish**.
|
||||
</Step>
|
||||
<Step title="Export IdP Metadata">
|
||||
Go to the **Sign On** tab → **View SAML setup instructions** or **View IdP metadata**. Copy the Identity Provider metadata XML.
|
||||
</Step>
|
||||
<Step title="Configure Activepieces">
|
||||
- Paste the **IdP Metadata** XML into the corresponding field
|
||||
- Copy the **X.509 Certificate** from Okta and paste it into the **Signing Key** field
|
||||
</Step>
|
||||
<Step title="Save Configuration">
|
||||
Click **Save** to complete the setup.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### SAML with JumpCloud
|
||||
|
||||
<Steps>
|
||||
<Step title="Create New Application in JumpCloud">
|
||||
Go to the [JumpCloud Admin Portal](https://console.jumpcloud.com/) → **SSO Applications** → **Add New Application** → **Custom SAML App**.
|
||||
</Step>
|
||||
<Step title="Configure ACS URL">
|
||||
Copy the **ACS URL** from the Activepieces configuration screen and paste it into the **ACS URLs** field in JumpCloud.
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Configure SP Entity ID">
|
||||
Set the **SP Entity ID** (Audience URI) to `Activepieces`.
|
||||
</Step>
|
||||
<Step title="Add User Attributes">
|
||||
Configure the following attribute mappings:
|
||||
|
||||
| Service Provider Attribute | JumpCloud Attribute |
|
||||
|---------------------------|---------------------|
|
||||
| `firstName` | `firstname` |
|
||||
| `lastName` | `lastname` |
|
||||
| `email` | `email` |
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Enable HTTP-Redirect Binding">
|
||||
JumpCloud does not include the `HTTP-Redirect` binding by default. You **must** enable this option.
|
||||
|
||||

|
||||
|
||||
<Warning>
|
||||
Without HTTP-Redirect binding, the SSO integration will not work correctly.
|
||||
</Warning>
|
||||
</Step>
|
||||
<Step title="Export Metadata">
|
||||
Click **Save**, then refresh the page and click **Export Metadata**.
|
||||
|
||||

|
||||
|
||||
<Tip>
|
||||
Verify that the exported XML contains `Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"` to ensure the binding was properly enabled.
|
||||
</Tip>
|
||||
</Step>
|
||||
<Step title="Configure IdP Metadata in Activepieces">
|
||||
Paste the exported metadata XML into the **IdP Metadata** field in Activepieces.
|
||||
</Step>
|
||||
<Step title="Configure Signing Certificate">
|
||||
Locate the `<ds:X509Certificate>` element in the IdP metadata and extract its value. Format it as a PEM certificate:
|
||||
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
[PASTE THE CERTIFICATE VALUE HERE]
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
Paste this into the **Signing Key** field.
|
||||
</Step>
|
||||
<Step title="Assign Users to Application">
|
||||
In JumpCloud, assign the application to the appropriate users or user groups.
|
||||
|
||||

|
||||
</Step>
|
||||
<Step title="Save Configuration">
|
||||
Click **Finish** to complete the setup.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Users cannot log in after SSO configuration">
|
||||
- Verify the redirect URL is correctly configured in your identity provider
|
||||
- Ensure users are assigned to the application in your identity provider
|
||||
- Check that email domains match the SSO enforcement settings
|
||||
</Accordion>
|
||||
<Accordion title="SAML authentication fails">
|
||||
- Confirm the IdP metadata is complete and correctly formatted
|
||||
- Verify the signing certificate is properly formatted with BEGIN/END markers
|
||||
- Ensure all required attributes (firstName, lastName, email) are mapped
|
||||
</Accordion>
|
||||
<Accordion title="HTTP-Redirect binding error (JumpCloud)">
|
||||
- Enable the HTTP-Redirect binding option in JumpCloud
|
||||
- Re-export the metadata after enabling the binding
|
||||
- Verify the binding appears in the exported XML
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Need Help?
|
||||
|
||||
If you encounter issues during SSO setup, please contact our enterprise support or [sales team](https://www.activepieces.com/sales).
|
||||
@@ -1,15 +0,0 @@
|
||||
---
|
||||
title: "How to Structure Projects"
|
||||
description: ""
|
||||
icon: "building"
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
Projects in Activepieces are the main units for organizing your automations and resources within your organization. Every project contains its own flows, connections, and tables. Access to these resources is shared among everyone who has access to that project.
|
||||
|
||||
There are two types of projects:
|
||||
- **Personal Projects**: Each user invited to your organization automatically receives a personal project. This is a private space where only that user can create and manage flows, connections, and tables.
|
||||
- **Team Projects**: Team projects are shared spaces that can be created and managed from this page. Multiple users can be invited to a team project, allowing them to collaborate, share access to flows, connections, and tables, and work together.
|
||||
|
||||
When organizing your work, create team projects for group collaboration and utilize personal projects for individual or private tasks.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: "Overview"
|
||||
icon: "hand-wave"
|
||||
description: "Manage and customize your Activepieces instance"
|
||||
---
|
||||
|
||||
The **Platform Admin** is the centralized admin panel for managing your Activepieces instance. It's designed for teams and organizations that want full control over users, integrations, security, and internal automation.
|
||||
|
||||
## What Can You Do?
|
||||
|
||||
With Platform Admin, you can:
|
||||
|
||||
- **Custom Branding:** Tailor the appearance of Activepieces to match your organization's identity, including colors, logos, and fonts.
|
||||
|
||||
- **Project Management:** Create, edit, and organize projects for internal teams and users.
|
||||
|
||||
- **Piece Management:** Control which integration pieces are available, including managing custom or internal pieces for your team's workflows.
|
||||
|
||||
- **User Management:** Add and remove users, send invitations, and assign roles and permissions.
|
||||
|
||||
- **AI Provider Management:** Configure and manage AI providers (like OpenAI, Anthropic, etc.) available for use in your flows.
|
||||
|
||||
- **SSO & Security:** Configure Single Sign-On (SSO) providers and manage security settings to ensure your instance is secure.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Connection Deleted'
|
||||
openapi-schema: connection.deleted
|
||||
icon: link
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Connection Upserted'
|
||||
openapi-schema: connection.upserted
|
||||
icon: link
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Flow Created'
|
||||
openapi-schema: flow.created
|
||||
icon: bolt
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Flow Deleted'
|
||||
openapi-schema: flow.deleted
|
||||
icon: bolt
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Flow Run Finished'
|
||||
openapi-schema: flow.run.finished
|
||||
icon: play
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Flow Run Started'
|
||||
openapi-schema: flow.run.started
|
||||
icon: play
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Flow Updated'
|
||||
openapi-schema: flow.updated
|
||||
icon: bolt
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Folder Created'
|
||||
openapi-schema: folder.created
|
||||
icon: folder
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Folder Deleted'
|
||||
openapi-schema: folder.deleted
|
||||
icon: folder
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Folder Updated'
|
||||
openapi-schema: folder.updated
|
||||
icon: folder
|
||||
---
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
title: "Overview"
|
||||
description: ""
|
||||
---
|
||||
|
||||
<Snippet file="enterprise-feature.mdx" />
|
||||
|
||||
This table in admin console contains all application events. We are constantly adding new events, so there is no better place to see the events defined in the code than [here](https://github.com/activepieces/activepieces/blob/main/packages/ee/shared/src/lib/audit-events/index.ts).
|
||||
|
||||

|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'Signing Key Created'
|
||||
openapi-schema: signing.key.created
|
||||
icon: key
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'User Email Verified'
|
||||
openapi-schema: user.email.verified
|
||||
icon: lock
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'User Password Reset'
|
||||
openapi-schema: user.password.reset
|
||||
icon: lock
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'User Signed In'
|
||||
openapi-schema: user.signed.in
|
||||
icon: lock
|
||||
---
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 'User Signed Up'
|
||||
openapi-schema: user.signed.up
|
||||
icon: lock
|
||||
---
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
title: "Security & Data Practices"
|
||||
description: "We prioritize security and follow these practices to keep information safe."
|
||||
icon: 'lock'
|
||||
---
|
||||
|
||||
## External Systems Credentials
|
||||
|
||||
**Storing Credentials**
|
||||
|
||||
All credentials are stored with 256-bit encryption keys, and there is no API to retrieve them for the user. They are sent only during processing, after which access is revoked from the engine.
|
||||
|
||||
**Data Masking**
|
||||
|
||||
We implement a robust data masking mechanism where third-party credentials or any sensitive information are systematically censored within the logs, guaranteeing that sensitive information is never stored or documented.
|
||||
|
||||
**OAuth2**
|
||||
|
||||
Integrations with third parties are always done using OAuth2, with a limited number of scopes when third-party support allows.
|
||||
|
||||
## Vulnerability Disclosure
|
||||
|
||||
Activepieces is an open-source project that welcomes contributors to test and report security issues.
|
||||
|
||||
For detailed information about our security policy, please refer to our GitHub Security Policy at: [https://github.com/activepieces/activepieces/security/policy](https://github.com/activepieces/activepieces/security/policy)
|
||||
|
||||
## Access and Authentication
|
||||
|
||||
**Role-Based Access Control (RBAC)**
|
||||
|
||||
To manage user access, we utilize Role-Based Access Control (RBAC). Team admins assign roles to users, granting them specific permissions to access and interact with projects, folders, and resources. RBAC allows for fine-grained control, enabling administrators to define and enforce access policies based on user roles.
|
||||
|
||||
**Single Sign-On (SSO)**
|
||||
|
||||
Implementing Single Sign-On (SSO) serves as a pivotal component of our security strategy. SSO streamlines user authentication by allowing them to access Activepieces with a single set of credentials. This not only enhances user convenience but also strengthens security by reducing the potential attack surface associated with managing multiple login credentials.
|
||||
|
||||
**Audit Logs**
|
||||
|
||||
We maintain comprehensive audit logs to track and monitor all access activities within Activepieces. This includes user interactions, system changes, and other relevant events. Our meticulous logging helps identify security threats and ensures transparency and accountability in our security measures.
|
||||
|
||||
**Password Policy Enforcement**
|
||||
|
||||
Users log in to Activepieces using a password known only to them. Activepieces enforces password length and complexity standards. Passwords are not stored; instead, only a secure hash of the password is stored in the database. For more information.
|
||||
|
||||
## Privacy & Data
|
||||
|
||||
**Supported Cloud Regions**
|
||||
|
||||
Presently, our cloud services are available in Germany as the supported data region.
|
||||
|
||||
We have plans to expand to additional regions in the near future.
|
||||
If you opt for **self-hosting**, the available regions will depend on where you choose to host.
|
||||
|
||||
**Policy**
|
||||
|
||||
To better understand how we handle your data and prioritize your privacy, please take a moment to review our [Privacy Policy](https://www.activepieces.com/privacy). This document outlines in detail the measures we take to safeguard your information and the principles guiding our approach to privacy and data protection.
|
||||
@@ -1,109 +0,0 @@
|
||||
---
|
||||
title: 'Create Action'
|
||||
icon: 'circle-5'
|
||||
description: ''
|
||||
---
|
||||
|
||||
## Action Definition
|
||||
|
||||
Now let's create first action which fetch random ice-cream flavor.
|
||||
|
||||
```bash
|
||||
npm run cli actions create
|
||||
```
|
||||
|
||||
You will be asked three questions to define your new piece:
|
||||
|
||||
1. `Piece Folder Name`: This is the name associated with the folder where the action resides. It helps organize and categorize actions within the piece.
|
||||
2. `Action Display Name`: The name users see in the interface, conveying the action's purpose clearly.
|
||||
3. `Action Description`: A brief, informative text in the UI, guiding users about the action's function and purpose.
|
||||
Next, Let's create the action file:
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
npm run cli actions create
|
||||
|
||||
? Enter the piece folder name : gelato
|
||||
? Enter the action display name : get icecream flavor
|
||||
? Enter the action description : fetches random icecream flavor.
|
||||
```
|
||||
|
||||
This will create a new TypeScript file named `get-icecream-flavor.ts` in the `packages/pieces/community/gelato/src/lib/actions` directory.
|
||||
|
||||
Inside this file, paste the following code:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
PieceAuth,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { gelatoAuth } from '../..';
|
||||
|
||||
export const getIcecreamFlavor = createAction({
|
||||
name: 'get_icecream_flavor', // Must be a unique across the piece, this shouldn't be changed.
|
||||
auth: gelatoAuth,
|
||||
displayName: 'Get Icecream Flavor',
|
||||
description: 'Fetches random icecream flavor',
|
||||
props: {},
|
||||
async run(context) {
|
||||
const res = await httpClient.sendRequest<string[]>({
|
||||
method: HttpMethod.GET,
|
||||
url: 'https://cloud.activepieces.com/api/v1/webhooks/RGjv57ex3RAHOgs0YK6Ja/sync',
|
||||
headers: {
|
||||
Authorization: context.auth, // Pass API key in headers
|
||||
},
|
||||
});
|
||||
return res.body;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The createAction function takes an object with several properties, including the `name`, `displayName`, `description`, `props`, and `run` function of the action.
|
||||
|
||||
The `name` property is a unique identifier for the action. The `displayName` and `description` properties are used to provide a human-readable name and description for the action.
|
||||
|
||||
The `props` property is an object that defines the properties that the action requires from the user. In this case, the action doesn't require any properties.
|
||||
|
||||
The `run` function is the function that is called when the action is executed. It takes a single argument, context, which contains the values of the action's properties.
|
||||
|
||||
The `run` function utilizes the httpClient.sendRequest function to make a GET request, fetching a random ice cream flavor. It incorporates API key authentication in the request headers. Finally, it returns the response body.
|
||||
|
||||
## Expose The Definition
|
||||
|
||||
To make the action readable by Activepieces, add it to the array of actions in the piece definition.
|
||||
|
||||
```typescript
|
||||
import { createPiece } from '@activepieces/pieces-framework';
|
||||
// Don't forget to add the following import.
|
||||
import { getIcecreamFlavor } from './lib/actions/get-icecream-flavor';
|
||||
|
||||
export const gelato = createPiece({
|
||||
displayName: 'Gelato',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png',
|
||||
authors: [],
|
||||
auth: gelatoAuth,
|
||||
// Add the action here.
|
||||
actions: [getIcecreamFlavor], // <--------
|
||||
triggers: [],
|
||||
});
|
||||
```
|
||||
|
||||
# Testing
|
||||
|
||||
By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`.
|
||||
|
||||
For more details, check out the [Piece Development](./development-setup) section.
|
||||
|
||||
Once you edit the environment variable, restart the backend. The piece will be rebuilt. After this process, you'll need to **refresh** the frontend to see the changes.
|
||||
|
||||
<Tip>
|
||||
If the build fails, try debugging by running `npx nx run-many -t build --projects=gelato`.
|
||||
It will display any errors in your code.
|
||||
</Tip>
|
||||
|
||||
To test the action, use the flow builder in Activepieces. It should function as shown in the screenshot.
|
||||
|
||||

|
||||
@@ -1,137 +0,0 @@
|
||||
---
|
||||
title: 'Create Trigger'
|
||||
icon: 'circle-6'
|
||||
description: ''
|
||||
---
|
||||
|
||||
This tutorial will guide you through the process of creating trigger for a Gelato piece that fetches new icecream flavor.
|
||||
|
||||
## Trigger Definition
|
||||
|
||||
To create trigger run the following command,
|
||||
|
||||
```bash
|
||||
npm run cli triggers create
|
||||
```
|
||||
|
||||
1. `Piece Folder Name`: This is the name associated with the folder where the trigger resides. It helps organize and categorize triggers within the piece.
|
||||
2. `Trigger Display Name`: The name users see in the interface, conveying the trigger's purpose clearly.
|
||||
3. `Trigger Description`: A brief, informative text in the UI, guiding users about the trigger's function and purpose.
|
||||
4. `Trigger Technique`: Specifies the trigger type - either [polling](../piece-reference/triggers/polling-trigger) or [webhook](../piece-reference/triggers/webhook-trigger).
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
npm run cli triggers create
|
||||
|
||||
? Enter the piece folder name : gelato
|
||||
? Enter the trigger display name : new flavor created
|
||||
? Enter the trigger description : triggers when a new icecream flavor is created.
|
||||
? Select the trigger technique: polling
|
||||
```
|
||||
|
||||
This will create a new TypeScript file at `packages/pieces/community/gelato/src/lib/triggers` named `new-flavor-created.ts`.
|
||||
|
||||
Inside this file, paste the following code:
|
||||
|
||||
```ts
|
||||
import { gelatoAuth } from '../../';
|
||||
import {
|
||||
DedupeStrategy,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
Polling,
|
||||
httpClient,
|
||||
pollingHelper,
|
||||
} from '@activepieces/pieces-common';
|
||||
import {
|
||||
PiecePropValueSchema,
|
||||
TriggerStrategy,
|
||||
createTrigger,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const polling: Polling<
|
||||
PiecePropValueSchema<typeof gelatoAuth>,
|
||||
Record<string, never>
|
||||
> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: 'https://cloud.activepieces.com/api/v1/webhooks/aHlEaNLc6vcF1nY2XJ2ed/sync',
|
||||
headers: {
|
||||
authorization: auth,
|
||||
},
|
||||
};
|
||||
const res = await httpClient.sendRequest(request);
|
||||
return res.body['flavors'].map((flavor: string) => ({
|
||||
epochMilliSeconds: dayjs().valueOf(),
|
||||
data: flavor,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
export const newFlavorCreated = createTrigger({
|
||||
auth: gelatoAuth,
|
||||
name: 'newFlavorCreated',
|
||||
displayName: 'new flavor created',
|
||||
description: 'triggers when a new icecream flavor is created.',
|
||||
props: {},
|
||||
sampleData: {},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async onEnable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onEnable(polling, { store, auth, propsValue });
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const { store, auth, propsValue } = context;
|
||||
await pollingHelper.onDisable(polling, { store, auth, propsValue });
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The way polling triggers usually work is as follows:
|
||||
|
||||
`Run`:The run method executes every 5 minutes, fetching data from the endpoint within a specified timestamp range or continuing until it identifies the last item ID. It then returns the new items as an array. In this example, the httpClient.sendRequest method is utilized to retrieve new flavors, which are subsequently stored in the store along with a timestamp.
|
||||
|
||||
## Expose The Definition
|
||||
|
||||
To make the trigger readable by Activepieces, add it to the array of triggers in the piece definition.
|
||||
|
||||
```typescript
|
||||
import { createPiece } from '@activepieces/pieces-framework';
|
||||
import { getIcecreamFlavor } from './lib/actions/get-icecream-flavor';
|
||||
// Don't forget to add the following import.
|
||||
import { newFlavorCreated } from './lib/triggers/new-flavor-created';
|
||||
|
||||
export const gelato = createPiece({
|
||||
displayName: 'Gelato Tutorial',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png',
|
||||
authors: [],
|
||||
auth: gelatoAuth,
|
||||
actions: [getIcecreamFlavor],
|
||||
// Add the trigger here.
|
||||
triggers: [newFlavorCreated], // <--------
|
||||
});
|
||||
```
|
||||
|
||||
# Testing
|
||||
|
||||
By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`.
|
||||
|
||||
For more details, check out the [Piece Development](./development-setup) section.
|
||||
|
||||
Once you edit the environment variable, restart the backend. The piece will be rebuilt. After this process, you'll need to **refresh** the frontend to see the changes.
|
||||
|
||||
To test the trigger, use the load sample data from flow builder in Activepieces. It should function as shown in the screenshot.
|
||||
|
||||

|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: 'Development setup'
|
||||
icon: 'circle-2'
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js v18+
|
||||
- npm v9+
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Setup the environment
|
||||
|
||||
```bash
|
||||
node tools/setup-dev.js
|
||||
```
|
||||
|
||||
2. Start the environment
|
||||
|
||||
This command will start activepieces with sqlite3 and in memory queue.
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
<Note>
|
||||
By default, the development setup only builds specific pieces.Open the file
|
||||
`packages/server/api/.env` and add comma-separated list of pieces to make
|
||||
available.
|
||||
|
||||
For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section.
|
||||
|
||||
</Note>
|
||||
|
||||
3. Go to **_localhost:4200_** on your web browser and sign in with these details:
|
||||
|
||||
Email: `dev@ap.com`
|
||||
Password: `12345678`
|
||||
|
||||
|
||||
## Pieces Development
|
||||
|
||||
When [`AP_SYNC_MODE`](https://github.com/activepieces/activepieces/blob/main/packages/server/api/.env#L17) is set to `OFFICIAL_AUTO`, all pieces are automatically loaded from the cloud API and synced to the database on first launch. This process may take a few seconds to several minutes depending on your internet connection.
|
||||
|
||||
For local development, pieces are loaded from your local `dist` folder instead of the database. To enable this, set the [`AP_DEV_PIECES`](https://github.com/activepieces/activepieces/blob/main/packages/server/api/.env#L4) environment variable with a comma-separated list of pieces. For example, to develop with `google-sheets` and `cal-com`:
|
||||
|
||||
```sh
|
||||
AP_DEV_PIECES=google-sheets,cal-com npm start
|
||||
```
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: 'Overview'
|
||||
description: 'This section helps developers build and contribute pieces.'
|
||||
icon: 'hand-wave'
|
||||
---
|
||||
|
||||
Building pieces is fun and important; it allows you to customize Activepieces for your own needs.
|
||||
|
||||
<Tip>
|
||||
We love contributions! In fact, most of the pieces are contributed by the community. Feel free to open a pull request.
|
||||
</Tip>
|
||||
<Tip>
|
||||
**Friendly Tip:**
|
||||
For the fastest support, we recommend joining our Discord community. We are dedicated to addressing every question and concern raised there.
|
||||
</Tip>
|
||||
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Code with TypeScript" icon="code">
|
||||
Build pieces using TypeScript for a more powerful and flexible development process.
|
||||
</Card>
|
||||
<Card title="Hot Reloading" icon="cloud-bolt">
|
||||
See your changes in the browser within 7 seconds.
|
||||
</Card>
|
||||
<Card title="Open Source" icon="earth-americas">
|
||||
Work within the open-source environment, explore, and contribute to other pieces.
|
||||
</Card>
|
||||
<Card title="Community Support" icon="people">
|
||||
Join our large community, where you can ask questions, share ideas, and develop alongside others.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: 'Add Piece Authentication'
|
||||
icon: 'circle-4'
|
||||
description: ''
|
||||
---
|
||||
|
||||
|
||||
### Piece Authentication
|
||||
|
||||
Activepieces supports multiple forms of authentication, you can check those forms [here](../piece-reference/authentication)
|
||||
|
||||
Now, let's establish authentication for this piece, which necessitates the inclusion of an API Key in the headers.
|
||||
|
||||
Modify `src/index.ts` file to add authentication,
|
||||
|
||||
```ts
|
||||
import { PieceAuth, createPiece } from '@activepieces/pieces-framework';
|
||||
|
||||
export const gelatoAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
required: true,
|
||||
description: 'Please use **test-key** as value for API Key',
|
||||
});
|
||||
|
||||
export const gelato = createPiece({
|
||||
displayName: 'Gelato',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png',
|
||||
auth: gelatoAuth,
|
||||
authors: [],
|
||||
actions: [],
|
||||
triggers: [],
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
Use the value **test-key** as the API key when testing actions or triggers for
|
||||
Gelato.
|
||||
</Note>
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
title: 'Create Piece Definition'
|
||||
icon: 'circle-3'
|
||||
description: ''
|
||||
---
|
||||
|
||||
|
||||
This tutorial will guide you through the process of creating a Gelato piece with an action that fetches random icecream flavor and trigger that fetches new icecream flavor created. It assumes that you are familiar with the following:
|
||||
|
||||
- [Activepieces Local development](./development-setup) Or [GitHub Codespaces](../misc/codespaces).
|
||||
- TypeScript syntax.
|
||||
|
||||
## Piece Definition
|
||||
|
||||
To get started, let's generate a new piece for Gelato
|
||||
|
||||
```bash
|
||||
npm run cli pieces create
|
||||
```
|
||||
|
||||
You will be asked three questions to define your new piece:
|
||||
|
||||
1. `Piece Name`: Specify a name for your piece. This name uniquely identifies your piece within the ActivePieces ecosystem.
|
||||
2. `Package Name`: Optionally, you can enter a name for the npm package associated with your piece. If left blank, the default name will be used.
|
||||
3. `Piece Type`: Choose the piece type based on your intention. It can be either "custom" if it's a tailored solution for your needs, or "community" if it's designed to be shared and used by the broader community.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
npm run cli pieces create
|
||||
|
||||
? Enter the piece name: gelato
|
||||
? Enter the package name: @activepieces/piece-gelato
|
||||
? Select the piece type: community
|
||||
```
|
||||
|
||||
The piece will be generated at `packages/pieces/community/gelato/`,
|
||||
the `src/index.ts` file should contain the following code
|
||||
|
||||
```ts
|
||||
import { PieceAuth, createPiece } from '@activepieces/pieces-framework';
|
||||
|
||||
export const gelato = createPiece({
|
||||
displayName: 'Gelato',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/gelato.png',
|
||||
auth: PieceAuth.None(),
|
||||
authors: [],
|
||||
actions: [],
|
||||
triggers: [],
|
||||
});
|
||||
```
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
title: 'Fork Repository'
|
||||
icon: "circle-1"
|
||||
---
|
||||
|
||||
To start building pieces, we need to fork the repository that contains the framework library and the development environment. Later, we will publish these pieces as `npm` artifacts.
|
||||
|
||||
Follow these steps to fork the repository:
|
||||
|
||||
1. Go to the repository page at https://github.com/activepieces/activepieces.
|
||||
2. Click the `Fork` button located in the top right corner of the page.
|
||||
|
||||

|
||||
|
||||
|
||||
<Tip>
|
||||
If you are an enterprise customer and want to use the private pieces feature, you can refer to the tutorial on how to set up a [private fork](../misc/private-fork).
|
||||
</Tip>
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
title: 'Start Building'
|
||||
icon: 'hammer'
|
||||
description: ''
|
||||
---
|
||||
This section guides you in creating a Gelato piece, from setting up your development environment to contributing the piece. By the end of this tutorial, you will have a piece with an action that fetches a random ice cream flavor and a trigger that fetches newly created ice cream flavors.
|
||||
|
||||
<Info>
|
||||
These are the next sections. In each step, we will do one small thing. This tutorial should take around 30 minutes.
|
||||
</Info>
|
||||
|
||||
## Steps Overview
|
||||
|
||||
<Steps>
|
||||
<Step title="Fork Repository" icon="code-branch">
|
||||
Fork the repository to create your own copy of the codebase.
|
||||
</Step>
|
||||
<Step title="Setup Development Environment" icon="code">
|
||||
Set up your development environment with the necessary tools and dependencies.
|
||||
</Step>
|
||||
<Step title="Create Piece Definition" icon="gear">
|
||||
Define the structure and behavior of your Gelato piece.
|
||||
</Step>
|
||||
<Step title="Add Piece Authentication" icon="lock">
|
||||
Implement authentication mechanisms for your Gelato piece.
|
||||
</Step>
|
||||
<Step title="Create Action" icon="ice-cream">
|
||||
Create an action that fetches a random ice cream flavor.
|
||||
</Step>
|
||||
<Step title="Create Trigger" icon="ice-cream">
|
||||
Create a trigger that fetches newly created ice cream flavors.
|
||||
</Step>
|
||||
<Step title="Sharing Pieces" icon="share">
|
||||
Share your Gelato piece with others.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
|
||||
<Card title="Contribution" icon="gift" iconType="duotone" color="#6e41e2">
|
||||
Contribute a piece to our repo and receive +1,400 tasks/month on [Activepieces Cloud](https://cloud.activepieces.com).
|
||||
</Card>
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: 'Build Custom Pieces'
|
||||
icon: 'box'
|
||||
---
|
||||
|
||||
You can use the CLI to build custom pieces for the platform. This process compiles the pieces and exports them as a `.tgz` packed archive.
|
||||
|
||||
### How It Works
|
||||
|
||||
The CLI scans the `packages/pieces/` directory for the specified piece. It checks the **name** in the `package.json` file. If the piece is found, it builds and packages it into a `.tgz` archive.
|
||||
|
||||
### Usage
|
||||
|
||||
To build a piece, follow these steps:
|
||||
|
||||
1. Ensure you have the CLI installed by cloning the repository.
|
||||
2. Run the following command:
|
||||
|
||||
```bash
|
||||
npm run build-piece
|
||||
```
|
||||
|
||||
You will be prompted to enter the name of the piece you want to build. For example:
|
||||
|
||||
```bash
|
||||
? Enter the piece folder name : google-drive
|
||||
```
|
||||
|
||||
The CLI will build the piece and you will be given the path to the archive. For example:
|
||||
|
||||
```bash
|
||||
Piece 'google-drive' built and packed successfully at dist/packages/pieces/community/google-drive
|
||||
```
|
||||
|
||||
You may also build the piece non-interactively by passing the piece name as an argument. For example:
|
||||
```bash
|
||||
npm run build-piece google-drive
|
||||
```
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
title: 'GitHub Codespaces'
|
||||
icon: 'github'
|
||||
description: ''
|
||||
---
|
||||
|
||||
GitHub Codespaces is a cloud development platform that enables developers to write, run, and debug code directly in their browsers, seamlessly integrated with GitHub.
|
||||
|
||||
### Steps to setup Codespaces
|
||||
|
||||
1. Go to [Activepieces repo](https://github.com/activepieces/activepieces).
|
||||
|
||||
2. Click Code `<>`, then under codespaces click create codespace on main.
|
||||
|
||||

|
||||
|
||||
<Note>
|
||||
By default, the development setup only builds specific pieces.Open the file
|
||||
`packages/server/api/.env` and add comma-separated list of pieces to make
|
||||
available.
|
||||
|
||||
For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section.
|
||||
|
||||
</Note>
|
||||
|
||||
3. Open the terminal and run `npm start`
|
||||
|
||||
4. Access the frontend URL by opening port 4200 and signing in with these details:
|
||||
|
||||
Email: `dev@ap.com`
|
||||
Password: `12345678`
|
||||
@@ -1,101 +0,0 @@
|
||||
---
|
||||
title: 'Create New AI Provider'
|
||||
icon: 'sparkles'
|
||||
---
|
||||
|
||||
ActivePieces currently supports the following AI providers:
|
||||
|
||||
- OpenAI
|
||||
- Anthropic
|
||||
|
||||
To create a new AI provider, you need to follow these steps:
|
||||
|
||||
## Implement the AI Interface
|
||||
|
||||
Create a new factory that returns an instance of the `AI` interface in the `packages/pieces/community/common/src/lib/ai/providers/your-ai-provider.ts` file.
|
||||
|
||||
```typescript
|
||||
export const yourAiProvider = ({
|
||||
serverUrl,
|
||||
engineToken,
|
||||
}: { serverUrl: string, engineToken: string }): AI<YourAiProviderSDK> => {
|
||||
const impl = new YourAiProviderSDK(serverUrl, engineToken);
|
||||
return {
|
||||
provider: "YOUR_AI_PROVIDER" as const,
|
||||
chat: {
|
||||
text: async (params) => {
|
||||
try {
|
||||
const response = await impl.chat.text(params);
|
||||
return response;
|
||||
} catch (e: any) {
|
||||
if (e?.error?.error) {
|
||||
throw e.error.error;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## Register the AI Provider
|
||||
|
||||
Add the new AI provider to the `AiProviders` enum in `packages/pieces/community/common/src/lib/ai/providers/index.ts` file.
|
||||
|
||||
```diff
|
||||
export const AiProviders = [
|
||||
+ {
|
||||
+ logoUrl: 'https://cdn.activepieces.com/pieces/openai.png',
|
||||
+ defaultBaseUrl: 'https://api.your-ai-provider.com',
|
||||
+ label: 'Your AI Provider' as const,
|
||||
+ value: 'your-ai-provider' as const,
|
||||
+ models: [
|
||||
+ { label: 'model-1', value: 'model-1' },
|
||||
+ { label: 'model-2', value: 'model-2' },
|
||||
+ { label: 'model-3', value: 'model-3' },
|
||||
+ ],
|
||||
+ factory: yourAiProvider,
|
||||
+ },
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
## Define Authentication Header
|
||||
|
||||
Now we need to tell ActivePieces how to authenticate to your AI provider. You can do this by adding an `auth` property to the `AiProvider` object.
|
||||
|
||||
The `auth` property is an object that defines the authentication mechanism for your AI provider. It consists of two properties: `name` and `mapper`. The `name` property specifies the name of the header that will be used to authenticate with your AI provider, and the `mapper` property defines a function that maps the value of the header to the format that your AI provider expects.
|
||||
|
||||
Here's an example of how to define the authentication header for a bearer token:
|
||||
|
||||
```diff
|
||||
export const AiProviders = [
|
||||
{
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/openai.png',
|
||||
defaultBaseUrl: 'https://api.your-ai-provider.com',
|
||||
label: 'Your AI Provider' as const,
|
||||
value: 'your-ai-provider' as const,
|
||||
models: [
|
||||
{ label: 'model-1', value: 'model-1' },
|
||||
{ label: 'model-2', value: 'model-2' },
|
||||
{ label: 'model-3', value: 'model-3' },
|
||||
],
|
||||
+ auth: authHeader({ bearer: true }), // or authHeader({ name: 'x-api-key', bearer: false })
|
||||
factory: yourAiProvider,
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
## Test the AI Provider
|
||||
|
||||
To test the AI provider, you can use a **universal AI** piece in a flow. Follow these steps:
|
||||
|
||||
- Add the required headers from the admin console for the newly created AI provider. These headers will be used to authenticate the requests to the AI provider.
|
||||
|
||||

|
||||
|
||||
- Create a flow that uses our **universal AI** pieces. And select **"Your AI Provider"** as the AI provider in the **Ask AI** action settings.
|
||||
|
||||

|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
title: 'Dev Containers'
|
||||
icon: 'docker'
|
||||
description: ''
|
||||
---
|
||||
|
||||
## Using Dev Containers in Visual Studio Code
|
||||
|
||||
The project includes a dev container configuration that allows you to use Visual Studio Code's [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension to develop the project in a consistent environment. This can be especially helpful if you are new to the project or if you have a different environment setup on your local machine.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you can use the dev container, you will need to install the following:
|
||||
|
||||
- [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- The [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension for Visual Studio Code.
|
||||
- [Docker](https://www.docker.com/).
|
||||
|
||||
## Using the Dev Container
|
||||
|
||||
To use the dev container for the Activepieces project, follow these steps:
|
||||
|
||||
1. Clone the Activepieces repository to your local machine.
|
||||
2. Open the project in Visual Studio Code.
|
||||
3. Press `Ctrl+Shift+P` and type `> Dev Containers: Reopen in Container`.
|
||||
4. Run `npm start`.
|
||||
5. The backend will run at `localhost:3000` and the frontend will run at `localhost:4200`.
|
||||
|
||||
<Note>
|
||||
By default, the development setup only builds specific pieces.Open the file
|
||||
`packages/server/api/.env` and add comma-separated list of pieces to make
|
||||
available.
|
||||
|
||||
For more details, check out the [Piece Development](/build-pieces/building-pieces/development-setup#pieces-development) section.
|
||||
|
||||
</Note>
|
||||
|
||||
The login credentials are:
|
||||
Email: `dev@ap.com`
|
||||
Password: `12345678`
|
||||
|
||||
## Exiting the Dev Container
|
||||
|
||||
To exit the dev container and return to your local environment, follow these steps:
|
||||
|
||||
1. In the bottom left corner of Visual Studio Code, click the `Remote-Containers: Reopen folder locally` button.
|
||||
2. Visual Studio Code will close the connection to the dev container and reopen the project in your local environment.
|
||||
|
||||
## Troubleshoot
|
||||
|
||||
One of the best trouble shoot after an error occur is to reset the dev container.
|
||||
|
||||
1. Exit the dev container
|
||||
2. Run the following
|
||||
```sh
|
||||
sh tools/reset-dev.sh
|
||||
```
|
||||
3. Rebuild the dev container from above steps
|
||||
@@ -1,82 +0,0 @@
|
||||
---
|
||||
title: 'Custom Pieces CI/CD'
|
||||
icon: 'hammer'
|
||||
---
|
||||
|
||||
You can use the CLI to sync custom pieces. There is no need to rebuild the Docker image as they are loaded directly from npm.
|
||||
|
||||
### How It Works
|
||||
|
||||
Use the CLI to sync items from `packages/pieces/custom/` to instances. In production, Activepieces acts as an npm registry, storing all piece versions.
|
||||
|
||||
The CLI scans the directory for `package.json` files, checking the **name** and **version** of each piece. If a piece isn't uploaded, it packages and uploads it via the API.
|
||||
|
||||
### Usage
|
||||
|
||||
To use the CLI, follow these steps:
|
||||
|
||||
1. Generate an API Key from the Admin Interface. Go to Settings and generate the API Key.
|
||||
2. Install the CLI by cloning the repository.
|
||||
3. Run the following command, replacing `API_KEY` with your generated API Key and `INSTANCE_URL` with your instance URL:
|
||||
|
||||
|
||||
```bash
|
||||
AP_API_KEY=your_api_key_here bun run sync-pieces -- --apiUrl https://INSTANCE_URL/api
|
||||
```
|
||||
|
||||
### Developer Workflow
|
||||
|
||||
1. Developers create and modify the pieces offline.
|
||||
2. Increment the piece version in their corresponding `package.json`. For more information, refer to the [piece versioning](../piece-reference/piece-versioning) documentation.
|
||||
3. Open a pull request towards the main branch.
|
||||
4. Once the pull request is merged to the main branch, manually run the CLI or use a GitHub/GitLab Action to trigger the synchronization process.
|
||||
|
||||
### GitHub Action
|
||||
|
||||
```yaml
|
||||
name: Sync Custom Pieces
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
sync-pieces:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Step 1: Check out the repository code with full history
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Step 2: Set up Bun
|
||||
- name: Set up Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
# Step 3: Cache Bun dependencies
|
||||
- name: Cache Bun dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.bun/install/cache
|
||||
key: bun-${{ hashFiles('bun.lockb') }}
|
||||
restore-keys: |
|
||||
bun-
|
||||
|
||||
# Step 4: Install dependencies using Bun
|
||||
- name: Install dependencies
|
||||
run: bun install --no-save
|
||||
|
||||
# Step 5: Sync Custom Pieces
|
||||
- name: Sync Custom Pieces
|
||||
env:
|
||||
AP_API_KEY: ${{ secrets.AP_API_KEY }}
|
||||
run: bun run sync-pieces -- --apiUrl ${{ secrets.INSTANCE_URL }}/api
|
||||
|
||||
```
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
---
|
||||
title: 'Setup Private Fork'
|
||||
icon: "code-branch"
|
||||
---
|
||||
|
||||
<Tip>
|
||||
**Friendly Tip #1:** If you want to experiment, you can fork or clone the public repository.
|
||||
</Tip>
|
||||
|
||||
<Tip>
|
||||
For private piece installation, you will need the paid edition. However, you can still develop pieces, contribute them back, **OR** publish them to the public npm registry and use them in your own instance or project.
|
||||
</Tip>
|
||||
|
||||
## Create a Private Fork (Private Pieces)
|
||||
|
||||
By following these steps, you can create a private fork on GitHub, GitLab or another platform and configure the "activepieces" repository as the upstream source, allowing you to incorporate changes from the "activepieces" repository.
|
||||
|
||||
1. **Clone the Repository:**
|
||||
|
||||
Begin by creating a bare clone of the repository. Remember that this is a temporary step and will be deleted later.
|
||||
|
||||
```bash
|
||||
git clone --bare git@github.com:activepieces/activepieces.git
|
||||
```
|
||||
|
||||
2. **Create a Private Git Repository**
|
||||
|
||||
Generate a new private repository on GitHub or your chosen platform. When initializing the new repository, do not include a README, license, or gitignore files. This precaution is essential to avoid merge conflicts when synchronizing your fork with the original repository.
|
||||
|
||||
3. **Mirror-Push to the Private Repository:**
|
||||
|
||||
Mirror-push the bare clone you created earlier to your newly created "activepieces" repository. Make sure to replace `<your_username>` in the URL below with your actual GitHub username.
|
||||
|
||||
```bash
|
||||
cd activepieces.git
|
||||
git push --mirror git@github.com:<your_username>/activepieces.git
|
||||
```
|
||||
|
||||
4. **Remove the Temporary Local Repository:**
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf activepieces.git
|
||||
```
|
||||
|
||||
5. **Clone Your Private Repository:**
|
||||
|
||||
Now, you can clone your "activepieces" repository onto your local machine into your desired directory.
|
||||
|
||||
```bash
|
||||
cd ~/path/to/directory
|
||||
git clone git@github.com:<your_username>/activepieces.git
|
||||
```
|
||||
|
||||
6. **Add the Original Repository as a Remote:**
|
||||
|
||||
If desired, you can add the original repository as a remote to fetch potential future changes. However, remember to disable push operations for this remote, as you are not permitted to push changes to it.
|
||||
|
||||
```bash
|
||||
git remote add upstream git@github.com:activepieces/activepieces.git
|
||||
git remote set-url --push upstream DISABLE
|
||||
```
|
||||
|
||||
You can view a list of all your remotes using `git remote -v`. It should resemble the following:
|
||||
|
||||
```
|
||||
origin git@github.com:<your_username>/activepieces.git (fetch)
|
||||
origin git@github.com:<your_username>/activepieces.git (push)
|
||||
upstream git@github.com:activepieces/activepieces.git (fetch)
|
||||
upstream DISABLE (push)
|
||||
```
|
||||
|
||||
> When pushing changes, always use `git push origin`.
|
||||
|
||||
### Sync Your Fork
|
||||
|
||||
To retrieve changes from the "upstream" repository, fetch the remote and rebase your work on top of it.
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
Conflict resolution should not be necessary since you've only added pieces to your repository.
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
title: 'Publish Custom Pieces'
|
||||
icon: 'upload'
|
||||
---
|
||||
|
||||
You can use the CLI to publish custom pieces to the platform. This process packages the pieces and uploads them to the specified API endpoint.
|
||||
|
||||
### How It Works
|
||||
|
||||
The CLI scans the `packages/pieces/` directory for the specified piece. It checks the **name** and **version** in the `package.json` file. If the piece is not already published, it builds, packages, and uploads it to the platform using the API.
|
||||
|
||||
### Usage
|
||||
|
||||
To publish a piece, follow these steps:
|
||||
|
||||
1. Ensure you have an API Key. Generate it from the Admin Interface by navigating to Settings.
|
||||
2. Install the CLI by cloning the repository.
|
||||
3. Run the following command:
|
||||
|
||||
```bash
|
||||
npm run publish-piece-to-api
|
||||
```
|
||||
|
||||
4. You will be asked three questions to publish your piece:
|
||||
|
||||
- `Piece Folder Name`: This is the name associated with the folder where the action resides. It helps organize and categorize actions within the piece.
|
||||
|
||||
- `API URL`: This is the URL of the API endpoint where the piece will be published (ex: https://cloud.activepieces.com/api).
|
||||
|
||||
- `API Key Source`: This is the source of the API key. It can be either `Env Variable (AP_API_KEY)` or `Manually`.
|
||||
|
||||
|
||||
In case you choose `Env Variable (AP_API_KEY)`, the CLI will use the API key from the `.env` file in the `packages/server/api` directory.
|
||||
|
||||
In case you choose `Manually`, you will be asked to enter the API key.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
npm run publish-piece-to-api
|
||||
|
||||
? Enter the piece folder name : google-drive
|
||||
? Enter the API URL : https://cloud.activepieces.com/api
|
||||
? Enter the API Key Source : Env Variable (AP_API_KEY)
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run publish-piece-to-api
|
||||
|
||||
? Enter the piece folder name : google-drive
|
||||
? Enter the API URL : https://cloud.activepieces.com/api
|
||||
? Enter the API Key Source : Manually
|
||||
? Enter the API Key : ap_1234567890abcdef1234567890abcdef
|
||||
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user