From 56580c4b9fe7fbb33ac99135d9f636bf7bdbb94b Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Wed, 2 Apr 2025 18:07:50 -0700 Subject: [PATCH 1/2] feat(marketplace): adding marketplace workflow to registry --- .../marketplace/components/workflow-card.tsx | 24 +- .../w/marketplace/constants/categories.tsx | 5 + sim/db/schema.ts | 7 +- sim/stores/workflows/registry/store.ts | 322 ++++++++++++------ sim/stores/workflows/registry/types.ts | 10 +- 5 files changed, 261 insertions(+), 107 deletions(-) diff --git a/sim/app/w/marketplace/components/workflow-card.tsx b/sim/app/w/marketplace/components/workflow-card.tsx index 562438290f5..4413b0453f6 100644 --- a/sim/app/w/marketplace/components/workflow-card.tsx +++ b/sim/app/w/marketplace/components/workflow-card.tsx @@ -1,8 +1,10 @@ 'use client' import { useEffect, useState } from 'react' +import { useRouter } from 'next/navigation' import { Eye, Star } from 'lucide-react' import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { Workflow } from '../marketplace' import { WorkflowPreview } from './workflow-preview' @@ -25,6 +27,8 @@ interface WorkflowCardProps { */ export function WorkflowCard({ workflow, onHover }: WorkflowCardProps) { const [isPreviewReady, setIsPreviewReady] = useState(!!workflow.workflowState) + const router = useRouter() + const { createWorkflow } = useWorkflowRegistry() // When workflow state becomes available, update preview ready state useEffect(() => { @@ -44,10 +48,11 @@ export function WorkflowCard({ workflow, onHover }: WorkflowCardProps) { } /** - * Handle workflow card click - track views + * Handle workflow card click - track views and import workflow */ const handleClick = async () => { try { + // Track view await fetch(`/api/marketplace/workflows`, { method: 'POST', headers: { @@ -55,8 +60,23 @@ export function WorkflowCard({ workflow, onHover }: WorkflowCardProps) { }, body: JSON.stringify({ id: workflow.id }), }) + + // Create a local copy of the marketplace workflow + if (workflow.workflowState) { + const newWorkflowId = createWorkflow({ + name: `${workflow.name} (Copy)`, + description: workflow.description, + marketplaceId: workflow.id, + marketplaceState: workflow.workflowState, + }) + + // Navigate to the new workflow + router.push(`/w/${newWorkflowId}`) + } else { + console.error('Cannot import workflow: state is not available') + } } catch (error) { - console.error('Failed to track workflow view:', error) + console.error('Failed to handle workflow click:', error) } } diff --git a/sim/app/w/marketplace/constants/categories.tsx b/sim/app/w/marketplace/constants/categories.tsx index 279bef6d481..1d576ae4bc3 100644 --- a/sim/app/w/marketplace/constants/categories.tsx +++ b/sim/app/w/marketplace/constants/categories.tsx @@ -74,6 +74,11 @@ export const getCategoryByValue = (value: string): Category => { } export const getCategoryLabel = (value: string): string => { + // Special handling for "popular" and "recent" sections + if (value === 'popular') return 'Popular' + if (value === 'recent') return 'Recent' + + // Default handling for regular categories return getCategoryByValue(value).label } diff --git a/sim/db/schema.ts b/sim/db/schema.ts index c0fb291788c..cf42416b5dc 100644 --- a/sim/db/schema.ts +++ b/sim/db/schema.ts @@ -73,11 +73,16 @@ export const workflow = pgTable('workflow', { updatedAt: timestamp('updated_at').notNull(), isDeployed: boolean('is_deployed').notNull().default(false), deployedAt: timestamp('deployed_at'), - isPublished: boolean('is_published').notNull().default(false), collaborators: json('collaborators').notNull().default('[]'), runCount: integer('run_count').notNull().default(0), lastRunAt: timestamp('last_run_at'), variables: json('variables').default('{}'), + marketplaceData: json('marketplace_data').default(null), // Format: { id: string, status: 'owner' | 'temp' | 'star' } + + // These columns are kept for backward compatibility during migration + // and should be marked as deprecated + // @deprecated - Use marketplaceData instead + isPublished: boolean('is_published').notNull().default(false), }) export const waitlist = pgTable('waitlist', { diff --git a/sim/stores/workflows/registry/store.ts b/sim/stores/workflows/registry/store.ts index 905d968b74a..fb2cea1ed18 100644 --- a/sim/stores/workflows/registry/store.ts +++ b/sim/stores/workflows/registry/store.ts @@ -138,126 +138,241 @@ export const useWorkflowRegistry = create()( // Generate workflow metadata with appropriate name and color const newWorkflow: WorkflowMetadata = { id, - name: generateUniqueName(workflows), + name: options.name || generateUniqueName(workflows), lastModified: new Date(), - description: 'New workflow', - color: getNextWorkflowColor(workflows), + description: options.description || 'New workflow', + color: options.marketplaceId ? '#808080' : getNextWorkflowColor(workflows), // Gray for marketplace imports + marketplaceStatus: options.marketplaceId ? 'temp' : undefined, + marketplaceId: options.marketplaceId, } - // Create starter block for new workflow - const starterId = crypto.randomUUID() - const starterBlock = { - id: starterId, - type: 'starter' as const, - name: 'Start', - position: { x: 100, y: 100 }, - subBlocks: { - startWorkflow: { - id: 'startWorkflow', - type: 'dropdown' as const, - value: 'manual', - }, - webhookPath: { - id: 'webhookPath', - type: 'short-input' as const, - value: '', - }, - webhookSecret: { - id: 'webhookSecret', - type: 'short-input' as const, - value: '', - }, - scheduleType: { - id: 'scheduleType', - type: 'dropdown' as const, - value: 'daily', - }, - minutesInterval: { - id: 'minutesInterval', - type: 'short-input' as const, - value: '', - }, - minutesStartingAt: { - id: 'minutesStartingAt', - type: 'short-input' as const, - value: '', - }, - hourlyMinute: { - id: 'hourlyMinute', - type: 'short-input' as const, - value: '', - }, - dailyTime: { - id: 'dailyTime', - type: 'short-input' as const, - value: '', - }, - weeklyDay: { - id: 'weeklyDay', - type: 'dropdown' as const, - value: 'MON', - }, - weeklyDayTime: { - id: 'weeklyDayTime', - type: 'short-input' as const, - value: '', - }, - monthlyDay: { - id: 'monthlyDay', - type: 'short-input' as const, - value: '', + let initialState; + + // If this is a marketplace import with existing state + if (options.marketplaceId && options.marketplaceState) { + initialState = { + blocks: options.marketplaceState.blocks || {}, + edges: options.marketplaceState.edges || [], + loops: options.marketplaceState.loops || {}, + isDeployed: false, + deployedAt: undefined, + history: { + past: [], + present: { + state: { + blocks: options.marketplaceState.blocks || {}, + edges: options.marketplaceState.edges || [], + loops: options.marketplaceState.loops || {}, + isDeployed: false, + deployedAt: undefined, + }, + timestamp: Date.now(), + action: 'Imported from marketplace', + subblockValues: {}, + }, + future: [], }, - monthlyTime: { - id: 'monthlyTime', - type: 'short-input' as const, - value: '', + lastSaved: Date.now(), + } + + logger.info(`Created workflow from marketplace: ${options.marketplaceId}`) + } else { + // Create starter block for new workflow + const starterId = crypto.randomUUID() + const starterBlock = { + id: starterId, + type: 'starter' as const, + name: 'Start', + position: { x: 100, y: 100 }, + subBlocks: { + startWorkflow: { + id: 'startWorkflow', + type: 'dropdown' as const, + value: 'manual', + }, + webhookPath: { + id: 'webhookPath', + type: 'short-input' as const, + value: '', + }, + webhookSecret: { + id: 'webhookSecret', + type: 'short-input' as const, + value: '', + }, + scheduleType: { + id: 'scheduleType', + type: 'dropdown' as const, + value: 'daily', + }, + minutesInterval: { + id: 'minutesInterval', + type: 'short-input' as const, + value: '', + }, + minutesStartingAt: { + id: 'minutesStartingAt', + type: 'short-input' as const, + value: '', + }, + hourlyMinute: { + id: 'hourlyMinute', + type: 'short-input' as const, + value: '', + }, + dailyTime: { + id: 'dailyTime', + type: 'short-input' as const, + value: '', + }, + weeklyDay: { + id: 'weeklyDay', + type: 'dropdown' as const, + value: 'MON', + }, + weeklyDayTime: { + id: 'weeklyDayTime', + type: 'short-input' as const, + value: '', + }, + monthlyDay: { + id: 'monthlyDay', + type: 'short-input' as const, + value: '', + }, + monthlyTime: { + id: 'monthlyTime', + type: 'short-input' as const, + value: '', + }, + cronExpression: { + id: 'cronExpression', + type: 'short-input' as const, + value: '', + }, + timezone: { + id: 'timezone', + type: 'dropdown' as const, + value: 'UTC', + }, }, - cronExpression: { - id: 'cronExpression', - type: 'short-input' as const, - value: '', + outputs: { + response: { + type: { + input: 'any', + }, + }, }, - timezone: { - id: 'timezone', - type: 'dropdown' as const, - value: 'UTC', + enabled: true, + horizontalHandles: true, + isWide: false, + height: 0, + } + + initialState = { + blocks: { + [starterId]: starterBlock, }, - }, - outputs: { - response: { - type: { - input: 'any', + edges: [], + loops: {}, + isDeployed: false, + deployedAt: undefined, + history: { + past: [], + present: { + state: { + blocks: { + [starterId]: starterBlock, + }, + edges: [], + loops: {}, + isDeployed: false, + deployedAt: undefined, + }, + timestamp: Date.now(), + action: 'Initial state', + subblockValues: {}, }, + future: [], }, + lastSaved: Date.now(), + } + } + + // Add workflow to registry + set((state) => ({ + workflows: { + ...state.workflows, + [id]: newWorkflow, }, - enabled: true, - horizontalHandles: true, - isWide: false, - height: 0, + error: null, + })) + + // Save workflow list to localStorage + const updatedWorkflows = get().workflows + saveRegistry(updatedWorkflows) + + // Save initial workflow state to localStorage + saveWorkflowState(id, initialState) + + // Initialize subblock values if this is a marketplace import + if (options.marketplaceId && options.marketplaceState?.blocks) { + useSubBlockStore.getState().initializeFromWorkflow(id, options.marketplaceState.blocks) + } + + // If this is the first workflow or it's an initial workflow, set it as active + if (options.isInitial || Object.keys(updatedWorkflows).length === 1) { + set({ activeWorkflowId: id }) + useWorkflowStore.setState(initialState) } + // Trigger sync + workflowSync.sync() + + return id + }, + + /** + * Creates a new workflow from a marketplace workflow + * @param marketplaceId - The ID of the marketplace workflow to import + * @param state - The state of the marketplace workflow (blocks, edges, loops) + * @param metadata - Additional metadata like name, description from marketplace + * @returns The ID of the newly created workflow + */ + createMarketplaceWorkflow: (marketplaceId: string, state: any, metadata: Partial) => { + const { workflows } = get() + const id = crypto.randomUUID() + + // Generate workflow metadata with marketplace properties + const newWorkflow: WorkflowMetadata = { + id, + name: metadata.name || `Marketplace workflow`, + lastModified: new Date(), + description: metadata.description || 'Imported from marketplace', + color: metadata.color || getNextWorkflowColor(workflows), + marketplaceStatus: 'temp', // Initial status is temp, user can star it later + marketplaceId: marketplaceId, // Reference to original marketplace workflow + } + + // Prepare workflow state based on the marketplace workflow state const initialState = { - blocks: { - [starterId]: starterBlock, - }, - edges: [], - loops: {}, + blocks: state.blocks || {}, + edges: state.edges || [], + loops: state.loops || {}, isDeployed: false, deployedAt: undefined, history: { past: [], present: { state: { - blocks: { - [starterId]: starterBlock, - }, - edges: [], - loops: {}, + blocks: state.blocks || {}, + edges: state.edges || [], + loops: state.loops || {}, isDeployed: false, deployedAt: undefined, }, timestamp: Date.now(), - action: 'Initial state', + action: 'Imported from marketplace', subblockValues: {}, }, future: [], @@ -278,18 +393,19 @@ export const useWorkflowRegistry = create()( const updatedWorkflows = get().workflows saveRegistry(updatedWorkflows) - // Save initial workflow state to localStorage + // Save workflow state to localStorage saveWorkflowState(id, initialState) - // If this is the first workflow or it's an initial workflow, set it as active - if (options.isInitial || Object.keys(updatedWorkflows).length === 1) { - set({ activeWorkflowId: id }) - useWorkflowStore.setState(initialState) + // Initialize subblock values from state blocks + if (state.blocks) { + useSubBlockStore.getState().initializeFromWorkflow(id, state.blocks) } - // Trigger sync + // Trigger sync to save to the database with marketplace attributes workflowSync.sync() + logger.info(`Created marketplace workflow ${id} imported from ${marketplaceId}`) + return id }, diff --git a/sim/stores/workflows/registry/types.ts b/sim/stores/workflows/registry/types.ts index cd8fa68b69b..84389b33e2e 100644 --- a/sim/stores/workflows/registry/types.ts +++ b/sim/stores/workflows/registry/types.ts @@ -4,6 +4,8 @@ export interface WorkflowMetadata { lastModified: Date description?: string color: string + marketplaceStatus?: 'temp' | 'star' | null + marketplaceId?: string } export interface WorkflowRegistryState { @@ -17,7 +19,13 @@ export interface WorkflowRegistryActions { setActiveWorkflow: (id: string) => Promise removeWorkflow: (id: string) => void updateWorkflow: (id: string, metadata: Partial) => void - createWorkflow: (options?: { isInitial?: boolean }) => string + createWorkflow: (options?: { + isInitial?: boolean, + marketplaceId?: string, + marketplaceState?: any, + name?: string, + description?: string + }) => string } export type WorkflowRegistry = WorkflowRegistryState & WorkflowRegistryActions From e9a8209325519f012292ed62df0df65adacbeac3 Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Wed, 2 Apr 2025 18:14:48 -0700 Subject: [PATCH 2/2] fix(db): updated schema --- sim/db/migrations/0024_next_whizzer.sql | 1 + sim/db/migrations/meta/0024_snapshot.json | 1274 +++++++++++++++++++++ sim/db/migrations/meta/_journal.json | 9 +- 3 files changed, 1283 insertions(+), 1 deletion(-) create mode 100644 sim/db/migrations/0024_next_whizzer.sql create mode 100644 sim/db/migrations/meta/0024_snapshot.json diff --git a/sim/db/migrations/0024_next_whizzer.sql b/sim/db/migrations/0024_next_whizzer.sql new file mode 100644 index 00000000000..ea3ecb8fca2 --- /dev/null +++ b/sim/db/migrations/0024_next_whizzer.sql @@ -0,0 +1 @@ +ALTER TABLE "workflow" ADD COLUMN "marketplace_data" json DEFAULT 'null'::json; \ No newline at end of file diff --git a/sim/db/migrations/meta/0024_snapshot.json b/sim/db/migrations/meta/0024_snapshot.json new file mode 100644 index 00000000000..a788edcc5be --- /dev/null +++ b/sim/db/migrations/meta/0024_snapshot.json @@ -0,0 +1,1274 @@ +{ + "id": "2df7e46c-e8b8-4fb2-8d97-f7e5dbc23519", + "prevId": "7b78c285-cc37-4833-86a4-75506efba35a", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.marketplace": { + "name": "marketplace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_name": { + "name": "author_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stars": { + "name": "stars", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "marketplace_workflow_id_workflow_id_fk": { + "name": "marketplace_workflow_id_workflow_id_fk", + "tableFrom": "marketplace", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "marketplace_author_id_user_id_fk": { + "name": "marketplace_author_id_user_id_fk", + "tableFrom": "marketplace", + "tableTo": "user", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.marketplace_star": { + "name": "marketplace_star", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "marketplace_id": { + "name": "marketplace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_marketplace_idx": { + "name": "user_marketplace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "marketplace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "marketplace_star_marketplace_id_marketplace_id_fk": { + "name": "marketplace_star_marketplace_id_marketplace_id_fk", + "tableFrom": "marketplace_star", + "tableTo": "marketplace", + "columnsFrom": [ + "marketplace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "marketplace_star_user_id_user_id_fk": { + "name": "marketplace_star_user_id_user_id_fk", + "tableFrom": "marketplace_star", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "general": { + "name": "general", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "path_idx": { + "name": "path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#3972F6'" + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "collaborators": { + "name": "collaborators", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "marketplace_data": { + "name": "marketplace_data", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'null'::json" + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_logs": { + "name": "workflow_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "duration": { + "name": "duration", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_logs_workflow_id_workflow_id_fk": { + "name": "workflow_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_logs", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workflow_schedule_workflow_id_unique": { + "name": "workflow_schedule_workflow_id_unique", + "nullsNotDistinct": false, + "columns": [ + "workflow_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/sim/db/migrations/meta/_journal.json b/sim/db/migrations/meta/_journal.json index 240ca2eb3b3..aff642a9939 100644 --- a/sim/db/migrations/meta/_journal.json +++ b/sim/db/migrations/meta/_journal.json @@ -169,6 +169,13 @@ "when": 1743024111706, "tag": "0023_nervous_tyger_tiger", "breakpoints": true + }, + { + "idx": 24, + "version": "7", + "when": 1743642824678, + "tag": "0024_next_whizzer", + "breakpoints": true } ] -} +} \ No newline at end of file