diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 95eebe1e8..70ec578bf 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -59,12 +59,6 @@ body { --content-gap: 1.75rem; } -/* Remove custom layout variable overrides to fallback to fumadocs defaults */ - -/* ============================================ - Navbar Light Mode Styling - ============================================ */ - /* Light mode navbar and search styling */ :root:not(.dark) nav { background-color: hsla(0, 0%, 96%, 0.85) !important; @@ -88,10 +82,6 @@ body { -webkit-backdrop-filter: blur(25px) saturate(180%) brightness(0.6) !important; } -/* ============================================ - Custom Sidebar Styling (Turborepo-inspired) - ============================================ */ - /* Floating sidebar appearance - remove background */ [data-sidebar-container], #nd-sidebar { @@ -468,10 +458,6 @@ aside[data-sidebar], writing-mode: horizontal-tb !important; } -/* ============================================ - Code Block Styling (Improved) - ============================================ */ - /* Apply Geist Mono to code elements */ code, pre, @@ -532,10 +518,6 @@ pre code .line { color: var(--color-fd-primary); } -/* ============================================ - TOC (Table of Contents) Styling - ============================================ */ - /* Remove the thin border-left on nested TOC items (keeps main indicator only) */ #nd-toc a[style*="padding-inline-start"] { border-left: none !important; @@ -554,10 +536,6 @@ main article, padding-bottom: 4rem; } -/* ============================================ - Center and Constrain Main Content Width - ============================================ */ - /* Main content area - center and constrain like turborepo/raindrop */ /* Note: --sidebar-offset and --toc-offset are now applied at #nd-docs-layout level */ main[data-main] { diff --git a/apps/docs/content/docs/en/tools/incidentio.mdx b/apps/docs/content/docs/en/tools/incidentio.mdx index 595eda032..3476d3535 100644 --- a/apps/docs/content/docs/en/tools/incidentio.mdx +++ b/apps/docs/content/docs/en/tools/incidentio.mdx @@ -234,7 +234,6 @@ List actions from incident.io. Optionally filter by incident ID. | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | incident.io API Key | | `incident_id` | string | No | Filter actions by incident ID \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) | -| `page_size` | number | No | Number of actions to return per page \(e.g., 10, 25, 50\) | #### Output @@ -309,7 +308,6 @@ List follow-ups from incident.io. Optionally filter by incident ID. | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | incident.io API Key | | `incident_id` | string | No | Filter follow-ups by incident ID \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) | -| `page_size` | number | No | Number of follow-ups to return per page \(e.g., 10, 25, 50\) | #### Output @@ -396,6 +394,7 @@ List all users in your Incident.io workspace. Returns user details including id, | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Incident.io API Key | | `page_size` | number | No | Number of results to return per page \(e.g., 10, 25, 50\). Default: 25 | +| `after` | string | No | Pagination cursor to fetch the next page of results | #### Output @@ -406,6 +405,10 @@ List all users in your Incident.io workspace. Returns user details including id, | ↳ `name` | string | Full name of the user | | ↳ `email` | string | Email address of the user | | ↳ `role` | string | Role of the user in the workspace | +| `pagination_meta` | object | Pagination metadata | +| ↳ `after` | string | Cursor for next page | +| ↳ `page_size` | number | Number of items per page | +| ↳ `total_record_count` | number | Total number of records | ### `incidentio_users_show` @@ -644,7 +647,6 @@ List all escalation policies in incident.io | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | incident.io API Key | -| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\). Default: 25 | #### Output diff --git a/apps/docs/content/docs/en/tools/pipedrive.mdx b/apps/docs/content/docs/en/tools/pipedrive.mdx index 28b8f723b..40ad2d1b4 100644 --- a/apps/docs/content/docs/en/tools/pipedrive.mdx +++ b/apps/docs/content/docs/en/tools/pipedrive.mdx @@ -49,6 +49,7 @@ Retrieve all deals from Pipedrive with optional filters | `pipeline_id` | string | No | If supplied, only deals in the specified pipeline are returned \(e.g., "1"\) | | `updated_since` | string | No | If set, only deals updated after this time are returned. Format: 2025-01-01T10:20:00Z | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | +| `cursor` | string | No | For pagination, the marker representing the first item on the next page | #### Output @@ -74,6 +75,8 @@ Retrieve all deals from Pipedrive with optional filters | `metadata` | object | Pagination metadata for the response | | ↳ `total_items` | number | Total number of items | | ↳ `has_more` | boolean | Whether more items are available | +| ↳ `next_cursor` | string | Cursor for fetching the next page \(v2 endpoints\) | +| ↳ `next_start` | number | Offset for fetching the next page \(v1 endpoints\) | | `success` | boolean | Operation success status | ### `pipedrive_get_deal` @@ -148,10 +151,9 @@ Retrieve files from Pipedrive with optional filters | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `deal_id` | string | No | Filter files by deal ID \(e.g., "123"\) | -| `person_id` | string | No | Filter files by person ID \(e.g., "456"\) | -| `org_id` | string | No | Filter files by organization ID \(e.g., "789"\) | -| `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | +| `sort` | string | No | Sort files by field \(supported: "id", "update_time"\) | +| `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 100\) | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | | `downloadFiles` | boolean | No | Download file contents into file outputs | #### Output @@ -171,6 +173,8 @@ Retrieve files from Pipedrive with optional filters | ↳ `url` | string | File download URL | | `downloadedFiles` | file[] | Downloaded files from Pipedrive | | `total_items` | number | Total number of files returned | +| `has_more` | boolean | Whether more files are available | +| `next_start` | number | Offset for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_get_mail_messages` @@ -183,6 +187,7 @@ Retrieve mail threads from Pipedrive mailbox | --------- | ---- | -------- | ----------- | | `folder` | string | No | Filter by folder: inbox, drafts, sent, archive \(default: inbox\) | | `limit` | string | No | Number of results to return \(e.g., "25", default: 50\) | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | #### Output @@ -190,6 +195,8 @@ Retrieve mail threads from Pipedrive mailbox | --------- | ---- | ----------- | | `messages` | array | Array of mail thread objects from Pipedrive mailbox | | `total_items` | number | Total number of mail threads returned | +| `has_more` | boolean | Whether more messages are available | +| `next_start` | number | Offset for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_get_mail_thread` @@ -221,7 +228,7 @@ Retrieve all pipelines from Pipedrive | `sort_by` | string | No | Field to sort by: id, update_time, add_time \(default: id\) | | `sort_direction` | string | No | Sorting direction: asc, desc \(default: asc\) | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | -| `cursor` | string | No | For pagination, the marker representing the first item on the next page | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | #### Output @@ -237,6 +244,8 @@ Retrieve all pipelines from Pipedrive | ↳ `add_time` | string | When the pipeline was created | | ↳ `update_time` | string | When the pipeline was last updated | | `total_items` | number | Total number of pipelines returned | +| `has_more` | boolean | Whether more pipelines are available | +| `next_start` | number | Offset for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_get_pipeline_deals` @@ -249,8 +258,8 @@ Retrieve all deals in a specific pipeline | --------- | ---- | -------- | ----------- | | `pipeline_id` | string | Yes | The ID of the pipeline \(e.g., "1"\) | | `stage_id` | string | No | Filter by specific stage within the pipeline \(e.g., "2"\) | -| `status` | string | No | Filter by deal status: open, won, lost | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | #### Output @@ -271,6 +280,7 @@ Retrieve all projects or a specific project from Pipedrive | `project_id` | string | No | Optional: ID of a specific project to retrieve \(e.g., "123"\) | | `status` | string | No | Filter by project status: open, completed, deleted \(only for listing all\) | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500, only for listing all\) | +| `cursor` | string | No | For pagination, the marker representing the first item on the next page | #### Output @@ -279,6 +289,8 @@ Retrieve all projects or a specific project from Pipedrive | `projects` | array | Array of project objects \(when listing all\) | | `project` | object | Single project object \(when project_id is provided\) | | `total_items` | number | Total number of projects returned | +| `has_more` | boolean | Whether more projects are available | +| `next_cursor` | string | Cursor for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_create_project` @@ -309,12 +321,11 @@ Retrieve activities (tasks) from Pipedrive with optional filters | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `deal_id` | string | No | Filter activities by deal ID \(e.g., "123"\) | -| `person_id` | string | No | Filter activities by person ID \(e.g., "456"\) | -| `org_id` | string | No | Filter activities by organization ID \(e.g., "789"\) | +| `user_id` | string | No | Filter activities by user ID \(e.g., "123"\) | | `type` | string | No | Filter by activity type \(call, meeting, task, deadline, email, lunch\) | | `done` | string | No | Filter by completion status: 0 for not done, 1 for done | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | #### Output @@ -335,6 +346,8 @@ Retrieve activities (tasks) from Pipedrive with optional filters | ↳ `add_time` | string | When the activity was created | | ↳ `update_time` | string | When the activity was last updated | | `total_items` | number | Total number of activities returned | +| `has_more` | boolean | Whether more activities are available | +| `next_start` | number | Offset for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_create_activity` @@ -399,6 +412,7 @@ Retrieve all leads or a specific lead from Pipedrive | `person_id` | string | No | Filter by person ID \(e.g., "456"\) | | `organization_id` | string | No | Filter by organization ID \(e.g., "789"\) | | `limit` | string | No | Number of results to return \(e.g., "50", default: 100, max: 500\) | +| `start` | string | No | Pagination start offset \(0-based index of the first item to return\) | #### Output @@ -433,6 +447,8 @@ Retrieve all leads or a specific lead from Pipedrive | ↳ `add_time` | string | When the lead was created \(ISO 8601\) | | ↳ `update_time` | string | When the lead was last updated \(ISO 8601\) | | `total_items` | number | Total number of leads returned | +| `has_more` | boolean | Whether more leads are available | +| `next_start` | number | Offset for fetching the next page | | `success` | boolean | Operation success status | ### `pipedrive_create_lead` diff --git a/apps/docs/content/docs/en/tools/supabase.mdx b/apps/docs/content/docs/en/tools/supabase.mdx index 089def746..a076f4e5e 100644 --- a/apps/docs/content/docs/en/tools/supabase.mdx +++ b/apps/docs/content/docs/en/tools/supabase.mdx @@ -57,6 +57,7 @@ Query data from a Supabase table | `filter` | string | No | PostgREST filter \(e.g., "id=eq.123"\) | | `orderBy` | string | No | Column to order by \(add DESC for descending\) | | `limit` | number | No | Maximum number of rows to return | +| `offset` | number | No | Number of rows to skip \(for pagination\) | | `apiKey` | string | Yes | Your Supabase service role secret key | #### Output @@ -211,6 +212,7 @@ Perform full-text search on a Supabase table | `searchType` | string | No | Search type: plain, phrase, or websearch \(default: websearch\) | | `language` | string | No | Language for text search configuration \(default: english\) | | `limit` | number | No | Maximum number of rows to return | +| `offset` | number | No | Number of rows to skip \(for pagination\) | | `apiKey` | string | Yes | Your Supabase service role secret key | #### Output diff --git a/apps/docs/content/docs/en/tools/typeform.mdx b/apps/docs/content/docs/en/tools/typeform.mdx index dc364b260..b8a7e97e5 100644 --- a/apps/docs/content/docs/en/tools/typeform.mdx +++ b/apps/docs/content/docs/en/tools/typeform.mdx @@ -43,6 +43,8 @@ Retrieve form responses from Typeform | `formId` | string | Yes | Typeform form ID \(e.g., "abc123XYZ"\) | | `apiKey` | string | Yes | Typeform Personal Access Token | | `pageSize` | number | No | Number of responses to retrieve \(e.g., 10, 25, 50\) | +| `before` | string | No | Cursor token for fetching the next page of older responses | +| `after` | string | No | Cursor token for fetching the next page of newer responses | | `since` | string | No | Retrieve responses submitted after this date \(e.g., "2024-01-01T00:00:00Z"\) | | `until` | string | No | Retrieve responses submitted before this date \(e.g., "2024-12-31T23:59:59Z"\) | | `completed` | string | No | Filter by completion status \(e.g., "true", "false", "all"\) | diff --git a/apps/docs/content/docs/en/tools/zendesk.mdx b/apps/docs/content/docs/en/tools/zendesk.mdx index d01a0660a..06b11c19b 100644 --- a/apps/docs/content/docs/en/tools/zendesk.mdx +++ b/apps/docs/content/docs/en/tools/zendesk.mdx @@ -67,10 +67,9 @@ Retrieve a list of tickets from Zendesk with optional filtering | `type` | string | No | Filter by type: "problem", "incident", "question", or "task" | | `assigneeId` | string | No | Filter by assignee user ID as a numeric string \(e.g., "12345"\) | | `organizationId` | string | No | Filter by organization ID as a numeric string \(e.g., "67890"\) | -| `sortBy` | string | No | Sort field: "created_at", "updated_at", "priority", or "status" | -| `sortOrder` | string | No | Sort order: "asc" or "desc" | +| `sort` | string | No | Sort field for ticket listing \(only applies without filters\): "updated_at", "id", or "status". Prefix with "-" for descending \(e.g., "-updated_at"\) | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `pageAfter` | string | No | Cursor from a previous response to fetch the next page of results | #### Output @@ -129,10 +128,10 @@ Retrieve a list of tickets from Zendesk with optional filtering | ↳ `from_messaging_channel` | boolean | Whether the ticket originated from a messaging channel | | ↳ `ticket_form_id` | number | Ticket form ID | | ↳ `generated_timestamp` | number | Unix timestamp of the ticket generation | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | @@ -515,7 +514,7 @@ Retrieve a list of users from Zendesk with optional filtering | `role` | string | No | Filter by role: "end-user", "agent", or "admin" | | `permissionSet` | string | No | Filter by permission set ID as a numeric string \(e.g., "12345"\) | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `pageAfter` | string | No | Cursor from a previous response to fetch the next page of results | #### Output @@ -563,10 +562,10 @@ Retrieve a list of users from Zendesk with optional filtering | ↳ `shared` | boolean | Whether the user is shared from a different Zendesk | | ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk | | ↳ `remote_photo_url` | string | URL to a remote photo | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | @@ -706,7 +705,7 @@ Search for users in Zendesk using a query string | `query` | string | No | Search query string \(e.g., user name or email\) | | `externalId` | string | No | External ID to search by \(your system identifier\) | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `page` | string | No | Page number for pagination \(1-based\) | #### Output @@ -754,10 +753,10 @@ Search for users in Zendesk using a query string | ↳ `shared` | boolean | Whether the user is shared from a different Zendesk | | ↳ `shared_agent` | boolean | Whether the agent is shared from a different Zendesk | | ↳ `remote_photo_url` | string | URL to a remote photo | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | @@ -999,7 +998,7 @@ Retrieve a list of organizations from Zendesk | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain \(e.g., "mycompany" for mycompany.zendesk.com\) | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `pageAfter` | string | No | Cursor from a previous response to fetch the next page of results | #### Output @@ -1020,10 +1019,10 @@ Retrieve a list of organizations from Zendesk | ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) | | ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) | | ↳ `external_id` | string | External ID for linking to external records | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | @@ -1075,7 +1074,7 @@ Autocomplete organizations in Zendesk by name prefix (for name matching/autocomp | `subdomain` | string | Yes | Your Zendesk subdomain | | `name` | string | Yes | Organization name prefix to search for \(e.g., "Acme"\) | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `page` | string | No | Page number for pagination \(1-based\) | #### Output @@ -1096,10 +1095,10 @@ Autocomplete organizations in Zendesk by name prefix (for name matching/autocomp | ↳ `created_at` | string | When the organization was created \(ISO 8601 format\) | | ↳ `updated_at` | string | When the organization was last updated \(ISO 8601 format\) | | ↳ `external_id` | string | External ID for linking to external records | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | @@ -1249,19 +1248,18 @@ Unified search across tickets, users, and organizations in Zendesk | `apiToken` | string | Yes | Zendesk API token | | `subdomain` | string | Yes | Your Zendesk subdomain | | `query` | string | Yes | Search query string using Zendesk search syntax \(e.g., "type:ticket status:open"\) | -| `sortBy` | string | No | Sort field: "relevance", "created_at", "updated_at", "priority", "status", or "ticket_type" | -| `sortOrder` | string | No | Sort order: "asc" or "desc" | +| `filterType` | string | Yes | Resource type to search for: "ticket", "user", "organization", or "group" | | `perPage` | string | No | Results per page as a number string \(default: "100", max: "100"\) | -| `page` | string | No | Page number as a string \(e.g., "1", "2"\) | +| `pageAfter` | string | No | Cursor from a previous response to fetch the next page of results | #### Output | Parameter | Type | Description | | --------- | ---- | ----------- | -| `paging` | object | Pagination information | +| `paging` | object | Cursor-based pagination information | +| ↳ `after_cursor` | string | Cursor for fetching the next page of results | +| ↳ `has_more` | boolean | Whether more results are available | | ↳ `next_page` | string | URL for next page of results | -| ↳ `previous_page` | string | URL for previous page of results | -| ↳ `count` | number | Total count of items | | `metadata` | object | Response metadata | | ↳ `total_returned` | number | Number of items returned in this response | | ↳ `has_more` | boolean | Whether more items are available | diff --git a/apps/sim/app/(auth)/components/oauth-provider-checker.tsx b/apps/sim/app/(auth)/components/oauth-provider-checker.tsx index c7eba7af1..6a7177e4f 100644 --- a/apps/sim/app/(auth)/components/oauth-provider-checker.tsx +++ b/apps/sim/app/(auth)/components/oauth-provider-checker.tsx @@ -1,5 +1,3 @@ -'use server' - import { env } from '@/lib/core/config/env' import { isProd } from '@/lib/core/config/feature-flags' diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx index 0d92b9672..2f13fd7ff 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-block/landing-node.tsx @@ -85,7 +85,7 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan transform: isAnimated ? 'translateY(0) scale(1)' : 'translateY(8px) scale(0.98)', transition: 'opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1)', - willChange: 'transform, opacity', + willChange: isAnimated ? 'auto' : 'transform, opacity', }} > diff --git a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx index 65c48f33e..aa43a60bf 100644 --- a/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx +++ b/apps/sim/app/(landing)/components/hero/components/landing-canvas/landing-edge/landing-edge.tsx @@ -67,7 +67,6 @@ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) { strokeLinejoin: 'round', pointerEvents: 'none', animation: `landing-edge-dash-${id} 1s linear infinite`, - willChange: 'stroke-dashoffset', ...style, }} /> diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css index 96e8981e3..f7e15a76c 100644 --- a/apps/sim/app/_styles/globals.css +++ b/apps/sim/app/_styles/globals.css @@ -754,3 +754,100 @@ input[type="search"]::-ms-clear { text-decoration: none !important; color: inherit !important; } + +/** + * Respect user's prefers-reduced-motion setting (WCAG 2.3.3) + * Disables animations and transitions for users who prefer reduced motion. + */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} + +/* WandPromptBar status indicator */ +@keyframes smoke-pulse { + 0%, + 100% { + transform: scale(0.8); + opacity: 0.4; + } + 50% { + transform: scale(1.1); + opacity: 0.8; + } +} + +.status-indicator { + position: relative; + width: 12px; + height: 12px; + border-radius: 50%; + overflow: hidden; + background-color: hsl(var(--muted-foreground) / 0.5); + transition: background-color 0.3s ease; +} + +.status-indicator.streaming { + background-color: transparent; +} + +.status-indicator.streaming::before { + content: ""; + position: absolute; + inset: 0; + border-radius: 50%; + background: radial-gradient( + circle, + hsl(var(--primary) / 0.9) 0%, + hsl(var(--primary) / 0.4) 60%, + transparent 80% + ); + animation: smoke-pulse 1.8s ease-in-out infinite; + opacity: 0.9; +} + +.dark .status-indicator.streaming::before { + background: #6b7280; + opacity: 0.9; + animation: smoke-pulse 1.8s ease-in-out infinite; +} + +/* MessageContainer loading dot */ +@keyframes growShrink { + 0%, + 100% { + transform: scale(0.9); + } + 50% { + transform: scale(1.1); + } +} + +.loading-dot { + animation: growShrink 1.5s infinite ease-in-out; +} + +/* Subflow node z-index and drag-over styles */ +.workflow-container .react-flow__node-subflowNode { + z-index: -1 !important; +} + +.workflow-container .react-flow__node-subflowNode:has([data-subflow-selected="true"]) { + z-index: 10 !important; +} + +.loop-node-drag-over, +.parallel-node-drag-over { + box-shadow: 0 0 0 1.75px var(--brand-secondary) !important; + border-radius: 8px !important; +} + +.react-flow__node[data-parent-node-id] .react-flow__handle { + z-index: 30; +} diff --git a/apps/sim/app/api/tools/pipedrive/get-files/route.ts b/apps/sim/app/api/tools/pipedrive/get-files/route.ts index 93111c94b..fae904ffc 100644 --- a/apps/sim/app/api/tools/pipedrive/get-files/route.ts +++ b/apps/sim/app/api/tools/pipedrive/get-files/route.ts @@ -22,15 +22,20 @@ interface PipedriveFile { interface PipedriveApiResponse { success: boolean data?: PipedriveFile[] + additional_data?: { + pagination?: { + more_items_in_collection: boolean + next_start: number + } + } error?: string } const PipedriveGetFilesSchema = z.object({ accessToken: z.string().min(1, 'Access token is required'), - deal_id: z.string().optional().nullable(), - person_id: z.string().optional().nullable(), - org_id: z.string().optional().nullable(), + sort: z.enum(['id', 'update_time']).optional().nullable(), limit: z.string().optional().nullable(), + start: z.string().optional().nullable(), downloadFiles: z.boolean().optional().default(false), }) @@ -54,20 +59,19 @@ export async function POST(request: NextRequest) { const body = await request.json() const validatedData = PipedriveGetFilesSchema.parse(body) - const { accessToken, deal_id, person_id, org_id, limit, downloadFiles } = validatedData + const { accessToken, sort, limit, start, downloadFiles } = validatedData const baseUrl = 'https://api.pipedrive.com/v1/files' const queryParams = new URLSearchParams() - if (deal_id) queryParams.append('deal_id', deal_id) - if (person_id) queryParams.append('person_id', person_id) - if (org_id) queryParams.append('org_id', org_id) + if (sort) queryParams.append('sort', sort) if (limit) queryParams.append('limit', limit) + if (start) queryParams.append('start', start) const queryString = queryParams.toString() const apiUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl - logger.info(`[${requestId}] Fetching files from Pipedrive`, { deal_id, person_id, org_id }) + logger.info(`[${requestId}] Fetching files from Pipedrive`) const urlValidation = await validateUrlWithDNS(apiUrl, 'apiUrl') if (!urlValidation.isValid) { @@ -93,6 +97,8 @@ export async function POST(request: NextRequest) { } const files = data.data || [] + const hasMore = data.additional_data?.pagination?.more_items_in_collection || false + const nextStart = data.additional_data?.pagination?.next_start ?? null const downloadedFiles: Array<{ name: string mimeType: string @@ -149,6 +155,8 @@ export async function POST(request: NextRequest) { files, downloadedFiles: downloadedFiles.length > 0 ? downloadedFiles : undefined, total_items: files.length, + has_more: hasMore, + next_start: nextStart, success: true, }, }) diff --git a/apps/sim/app/chat/components/message-container/message-container.tsx b/apps/sim/app/chat/components/message-container/message-container.tsx index 8695878e9..df7d5e751 100644 --- a/apps/sim/app/chat/components/message-container/message-container.tsx +++ b/apps/sim/app/chat/components/message-container/message-container.tsx @@ -30,21 +30,6 @@ export const ChatMessageContainer = memo(function ChatMessageContainer({ }: ChatMessageContainerProps) { return (
- - {/* Scrollable Messages Area */}
('idle') const [isInitialized, setIsInitialized] = useState(false) const [isMuted, setIsMuted] = useState(false) - const [audioLevels, setAudioLevels] = useState(new Array(200).fill(0)) + const [audioLevels, setAudioLevels] = useState(() => new Array(200).fill(0)) const [permissionStatus, setPermissionStatus] = useState<'prompt' | 'granted' | 'denied'>( 'prompt' ) diff --git a/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/page.tsx b/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/page.tsx index e82182edb..1f78f7e68 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/page.tsx @@ -1,4 +1,4 @@ -import { redirect } from 'next/navigation' +import { redirect, unstable_rethrow } from 'next/navigation' import { getSession } from '@/lib/auth' import { getWorkspaceFile } from '@/lib/uploads/contexts/workspace' import { verifyWorkspaceMembership } from '@/app/api/workflows/utils' @@ -14,24 +14,27 @@ interface FileViewerPageProps { export default async function FileViewerPage({ params }: FileViewerPageProps) { const { workspaceId, fileId } = await params - try { - const session = await getSession() - if (!session?.user?.id) { - redirect('/') - } + const session = await getSession() + if (!session?.user?.id) { + redirect('/') + } - const hasPermission = await verifyWorkspaceMembership(session.user.id, workspaceId) - if (!hasPermission) { - redirect(`/workspace/${workspaceId}`) - } - - const fileRecord = await getWorkspaceFile(workspaceId, fileId) - if (!fileRecord) { - redirect(`/workspace/${workspaceId}`) - } - - return - } catch (error) { + const hasPermission = await verifyWorkspaceMembership(session.user.id, workspaceId) + if (!hasPermission) { redirect(`/workspace/${workspaceId}`) } + + let fileRecord: Awaited> + try { + fileRecord = await getWorkspaceFile(workspaceId, fileId) + } catch (error) { + unstable_rethrow(error) + redirect(`/workspace/${workspaceId}`) + } + + if (!fileRecord) { + redirect(`/workspace/${workspaceId}`) + } + + return } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx index 18222f8df..479dde41d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/copilot.tsx @@ -131,10 +131,8 @@ export const Copilot = forwardRef(({ panelWidth }, ref resumeActiveStream, }) - // Handle scroll management (80px stickiness for copilot) - const { scrollAreaRef, scrollToBottom } = useScrollManagement(messages, isSendingMessage, { - stickinessThreshold: 40, - }) + // Handle scroll management + const { scrollAreaRef, scrollToBottom } = useScrollManagement(messages, isSendingMessage) // Handle chat history grouping const { groupedChats, handleHistoryDropdownOpen: handleHistoryDropdownOpenHook } = useChatHistory( diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx index 32036c21d..f20da325f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx @@ -1,5 +1,5 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { useReactFlow } from 'reactflow' import { useStoreWithEqualityFn } from 'zustand/traditional' import { Combobox, type ComboboxOption } from '@/components/emcn/components' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx index d8d3ec00e..355463819 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/dropdown/dropdown.tsx @@ -1,5 +1,5 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { useStoreWithEqualityFn } from 'zustand/traditional' import { Badge } from '@/components/emcn' import { Combobox, type ComboboxOption } from '@/components/emcn/components' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/messages-input/messages-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/messages-input/messages-input.tsx index b5cd52600..69ed53a5c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/messages-input/messages-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/messages-input/messages-input.tsx @@ -7,7 +7,7 @@ import { useRef, useState, } from 'react' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { ChevronDown, ChevronsUpDown, ChevronUp, Plus } from 'lucide-react' import { Button, Popover, PopoverContent, PopoverItem, PopoverTrigger } from '@/components/emcn' import { Trash } from '@/components/emcn/icons/trash' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx index 180b8bb12..35a90e159 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx @@ -1,5 +1,5 @@ import { type JSX, type MouseEvent, memo, useCallback, useRef, useState } from 'react' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { AlertTriangle, ArrowLeftRight, ArrowUp, Check, Clipboard } from 'lucide-react' import { Button, Input, Label, Tooltip } from '@/components/emcn/components' import { cn } from '@/lib/core/utils/cn' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx index 9f1905c83..6d7829c17 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/editor.tsx @@ -1,7 +1,7 @@ 'use client' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { BookOpen, Check, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx index 96c85791f..6205818cd 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/subflow-node.tsx @@ -10,40 +10,6 @@ import { ActionBar } from '@/app/workspace/[workspaceId]/w/[workflowId]/componen import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks' import { usePanelEditorStore } from '@/stores/panel' -/** - * Global styles for subflow nodes (loop and parallel containers). - * Includes animations for drag-over states and hover effects. - * - * @returns Style component with global CSS - */ -const SubflowNodeStyles: React.FC = () => { - return ( - - ) -} - /** * Data structure for subflow nodes (loop and parallel containers) */ @@ -151,133 +117,130 @@ export const SubflowNodeComponent = memo(({ data, id, selected }: NodeProps - -
+
+
setCurrentBlockId(id)} + className={cn( + 'workflow-drag-handle relative cursor-grab select-none rounded-[8px] border border-[var(--border-1)] [&:active]:cursor-grabbing', + 'transition-block-bg transition-ring', + 'z-[20]' + )} + style={{ + width: data.width || 500, + height: data.height || 300, + position: 'relative', + overflow: 'visible', + pointerEvents: isPreview ? 'none' : 'all', + }} + data-node-id={id} + data-type='subflowNode' + data-nesting-level={nestingLevel} + data-subflow-selected={isFocused || isSelected || isPreviewSelected} + > + {!isPreview && ( + + )} + + {/* Header Section */}
setCurrentBlockId(id)} className={cn( - 'workflow-drag-handle relative cursor-grab select-none rounded-[8px] border border-[var(--border-1)] [&:active]:cursor-grabbing', - 'transition-block-bg transition-ring', - 'z-[20]' + 'flex items-center justify-between rounded-t-[8px] border-[var(--border)] border-b bg-[var(--surface-2)] py-[8px] pr-[12px] pl-[8px]' )} - style={{ - width: data.width || 500, - height: data.height || 300, - position: 'relative', - overflow: 'visible', - pointerEvents: isPreview ? 'none' : 'all', - }} - data-node-id={id} - data-type='subflowNode' - data-nesting-level={nestingLevel} - data-subflow-selected={isFocused || isSelected || isPreviewSelected} > - {!isPreview && ( - - )} - - {/* Header Section */} -
-
-
- -
- - {blockName} - -
-
- {!isEnabled && disabled} - {isLocked && locked} -
-
- - {!isPreview && ( +
- )} - -
- {/* Subflow Start */} -
- Start - - +
+ + {blockName} + +
+
+ {!isEnabled && disabled} + {isLocked && locked}
- - {/* Input handle on left middle */} - - - {/* Output handle on right middle */} - - - {hasRing && ( -
- )}
+ + {!isPreview && ( +
+ )} + +
+ {/* Subflow Start */} +
+ Start + + +
+
+ + {/* Input handle on left middle */} + + + {/* Output handle on right middle */} + + + {hasRing && ( +
+ )}
- +
) }) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx index a15022ea5..e39cbbb9c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/wand-prompt-bar/wand-prompt-bar.tsx @@ -134,57 +134,6 @@ export function WandPromptBar({ )}
- -
) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx index c0f89e2b3..434ea73cc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx @@ -1,6 +1,6 @@ import { memo, useCallback, useEffect, useMemo, useRef } from 'react' import { createLogger } from '@sim/logger' -import { isEqual } from 'lodash' +import isEqual from 'lodash/isEqual' import { useParams } from 'next/navigation' import { Handle, type NodeProps, Position, useUpdateNodeInternals } from 'reactflow' import { useStoreWithEqualityFn } from 'zustand/traditional' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-scroll-management.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-scroll-management.ts index 8b43eee10..9a330475d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-scroll-management.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-scroll-management.ts @@ -16,7 +16,7 @@ interface UseScrollManagementOptions { /** * Distance from bottom (in pixels) within which auto-scroll stays active * @remarks Lower values = less sticky (user can scroll away easier) - * @defaultValue 100 + * @defaultValue 30 */ stickinessThreshold?: number } @@ -41,7 +41,7 @@ export function useScrollManagement( const lastScrollTopRef = useRef(0) const scrollBehavior = options?.behavior ?? 'smooth' - const stickinessThreshold = options?.stickinessThreshold ?? 100 + const stickinessThreshold = options?.stickinessThreshold ?? 30 /** Scrolls the container to the bottom */ const scrollToBottom = useCallback(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/help-modal/help-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/help-modal/help-modal.tsx index aefb340b4..9c558baa5 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/help-modal/help-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/help-modal/help-modal.tsx @@ -514,6 +514,7 @@ export function HelpModal({ open, onOpenChange, workflowId, workspaceId }: HelpM alt={`Preview ${index + 1}`} fill unoptimized + sizes='(max-width: 768px) 100vw, 50vw' className='object-contain' />