-
+
Are you sure you want to delete the "{selectedTag?.displayName}" tag? This will
remove this tag from {selectedTagUsage?.documentCount || 0} document
{selectedTagUsage?.documentCount !== 1 ? 's' : ''}.{' '}
@@ -494,12 +486,7 @@ export function BaseTagsModal({ open, onOpenChange, knowledgeBaseId }: BaseTagsM
>
Cancel
-
+
{isDeletingTag ? <>Deleting...> : 'Delete Tag'}
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/base-card/base-card.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/base-card/base-card.tsx
index 50ba8d61d7..c643347a55 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/base-card/base-card.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/base-card/base-card.tsx
@@ -67,26 +67,26 @@ function formatAbsoluteDate(dateString: string): string {
*/
export function BaseCardSkeleton() {
return (
-
+
@@ -122,9 +122,9 @@ export function BaseCard({ id, title, docCount, description, updatedAt }: BaseCa
return (
-
+
-
+
{title}
{shortId && {shortId} }
@@ -139,7 +139,7 @@ export function BaseCard({ id, title, docCount, description, updatedAt }: BaseCa
{updatedAt && (
-
+
last updated: {formatRelativeTime(updatedAt)}
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/constants.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/components/constants.ts
index 07d6943b84..aa5b7618fe 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/constants.ts
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/constants.ts
@@ -1,8 +1,8 @@
export const filterButtonClass =
- 'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
+ 'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-2)]'
export const dropdownContentClass =
- 'w-[220px] rounded-lg border-[#E5E5E5] bg-[var(--white)] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
+ 'w-[220px] rounded-lg border-[#E5E5E5] bg-[var(--white)] p-0 shadow-xs dark:border-[#414141] dark:bg-[var(--surface-2)]'
export const commandListClass = 'overflow-y-auto overflow-x-hidden'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx
index 928fd52954..4434093045 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/components/create-base-modal/create-base-modal.tsx
@@ -388,7 +388,7 @@ export function CreateBaseModal({
/>
-
+
Min Chunk Size (characters)
@@ -562,7 +562,7 @@ export function CreateBaseModal({
Cancel
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
index 757b0731fb..65c677c7a3 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
@@ -145,7 +145,7 @@ export function Knowledge() {
-
+
setIsCreateModalOpen(true)}
disabled={userPermissions.canEdit !== true}
- variant='primary'
+ variant='tertiary'
className='h-[32px] rounded-[6px]'
>
Create
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx
index d4e4fab887..24a80a8f80 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx
@@ -671,7 +671,7 @@ function LineChartComponent({
const top = Math.min(Math.max(anchorY - 26, padding.top), height - padding.bottom - 18)
return (
{currentHoverDate && (
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/status-bar/status-bar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/status-bar/status-bar.tsx
index 38510f497b..b701c78e8a 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/status-bar/status-bar.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/status-bar/status-bar.tsx
@@ -97,7 +97,7 @@ export function StatusBar({
{hoverIndex !== null && segments[hoverIndex] && (
onToggleWorkflow(workflow.workflowId)}
>
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
index ebbb3a88db..5aaafb4652 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/dashboard.tsx
@@ -36,7 +36,7 @@ const SKELETON_BAR_HEIGHTS = [
function GraphCardSkeleton({ title }: { title: string }) {
return (
-
+
{title}
@@ -570,7 +570,7 @@ export default function Dashboard({ logs, isLoading, error }: DashboardProps) {
-
+
Runs
@@ -597,7 +597,7 @@ export default function Dashboard({ logs, isLoading, error }: DashboardProps) {
-
+
Errors
@@ -624,7 +624,7 @@ export default function Dashboard({ logs, isLoading, error }: DashboardProps) {
-
+
Latency
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts b/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
index 3458318613..b59a2eac56 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/index.ts
@@ -4,9 +4,4 @@ export { FileCards } from './log-details/components/file-download'
export { FrozenCanvas } from './log-details/components/frozen-canvas'
export { TraceSpans } from './log-details/components/trace-spans'
export { LogsList } from './logs-list'
-export {
- AutocompleteSearch,
- Controls,
- LogsToolbar,
- NotificationSettings,
-} from './logs-toolbar'
+export { AutocompleteSearch, LogsToolbar, NotificationSettings } from './logs-toolbar'
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx
index 39020ea1cd..f422241cbe 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx
@@ -277,10 +277,10 @@ function ExpandableRowHeader({
aria-expanded={hasChildren ? isExpanded : undefined}
aria-label={hasChildren ? (isExpanded ? 'Collapse' : 'Expand') : undefined}
>
-
+
{hasChildren && (
)}
@@ -418,14 +418,14 @@ function InputOutputSection({
'font-medium text-[12px] transition-colors',
isError
? 'text-[var(--text-error)]'
- : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-secondary)]'
+ : 'text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
)}
>
{label}
+
{span.children!.map((child, childIndex) => (
0 && isCardExpanded && (
-
+
{inlineChildren.map((childSpan, index) => (
+
{[...toolCallSpans, ...inlineChildren].map((childSpan, index) => {
const childId = childSpan.id || `${spanId}-inline-${index}`
const childIsError = childSpan.status === 'error'
@@ -731,7 +731,7 @@ const TraceSpanItem = memo(function TraceSpanItem({
{/* Nested children */}
{showChildrenInProgressBar && hasNestedChildren && isNestedExpanded && (
-
+
{childSpan.children!.map((nestedChild, nestedIndex) => (
setIsFrozenCanvasOpen(true)}
- className='flex items-center justify-between rounded-[6px] bg-[var(--surface-1)] px-[10px] py-[8px] transition-colors hover:bg-[var(--c-2A2A2A)]'
+ className='flex items-center justify-between rounded-[6px] bg-[var(--surface-1)] px-[10px] py-[8px] transition-colors hover:bg-[var(--surface-4)]'
>
View Snapshot
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx
index 65d07744a6..b7a9118c79 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-list/logs-list.tsx
@@ -36,8 +36,8 @@ const LogRow = memo(
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/controls.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/controls.tsx
deleted file mode 100644
index dc8c05af66..0000000000
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/controls.tsx
+++ /dev/null
@@ -1,263 +0,0 @@
-import { type ReactNode, useState } from 'react'
-import { ArrowUp, Bell, ChevronDown, Loader2, RefreshCw, Search } from 'lucide-react'
-import {
- Button,
- Popover,
- PopoverContent,
- PopoverItem,
- PopoverScrollArea,
- PopoverTrigger,
- Tooltip,
-} from '@/components/emcn'
-import { MoreHorizontal } from '@/components/emcn/icons'
-import { Input } from '@/components/ui/input'
-import { cn } from '@/lib/core/utils/cn'
-import { soehne } from '@/app/_styles/fonts/soehne/soehne'
-import { useFilterStore } from '@/stores/logs/filters/store'
-import type { TimeRange } from '@/stores/logs/filters/types'
-
-const FILTER_BUTTON_CLASS =
- 'w-full justify-between rounded-[10px] border-[#E5E5E5] bg-[var(--white)] font-normal text-sm dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
-
-type TimelineProps = {
- variant?: 'default' | 'header'
-}
-
-/**
- * Timeline component for time range selection.
- * Displays a dropdown with predefined time ranges.
- * @param props - The component props
- * @returns Time range selector dropdown
- */
-function Timeline({ variant = 'default' }: TimelineProps = {}) {
- const { timeRange, setTimeRange } = useFilterStore()
- const [isPopoverOpen, setIsPopoverOpen] = useState(false)
-
- const specificTimeRanges: TimeRange[] = [
- 'Past 30 minutes',
- 'Past hour',
- 'Past 6 hours',
- 'Past 12 hours',
- 'Past 24 hours',
- 'Past 3 days',
- 'Past 7 days',
- 'Past 14 days',
- 'Past 30 days',
- ]
-
- const handleTimeRangeSelect = (range: TimeRange) => {
- setTimeRange(range)
- setIsPopoverOpen(false)
- }
-
- return (
-
-
-
- {timeRange}
-
-
-
-
-
- handleTimeRangeSelect('All time')}
- >
- All time
-
-
-
-
- {specificTimeRanges.map((range) => (
- handleTimeRangeSelect(range)}
- >
- {range}
-
- ))}
-
-
-
- )
-}
-
-interface ControlsProps {
- searchQuery?: string
- setSearchQuery?: (v: string) => void
- isRefetching: boolean
- resetToNow: () => void
- live: boolean
- setLive: (v: (prev: boolean) => boolean) => void
- viewMode: string
- setViewMode: (mode: 'logs' | 'dashboard') => void
- searchComponent?: ReactNode
- showExport?: boolean
- onExport?: () => void
- canConfigureNotifications?: boolean
- onConfigureNotifications?: () => void
-}
-
-export function Controls({
- searchQuery,
- setSearchQuery,
- isRefetching,
- resetToNow,
- live,
- setLive,
- viewMode,
- setViewMode,
- searchComponent,
- onExport,
- canConfigureNotifications,
- onConfigureNotifications,
-}: ControlsProps) {
- return (
-
- {searchComponent ? (
- searchComponent
- ) : (
-
-
-
setSearchQuery?.(e.target.value)}
- className='h-9 w-full border-[#E5E5E5] bg-[var(--white)] pr-10 pl-9 dark:border-[#414141] dark:bg-[var(--surface-elevated)]'
- />
- {searchQuery && (
-
setSearchQuery?.('')}
- className='-translate-y-1/2 absolute top-1/2 right-3 text-muted-foreground hover:text-foreground'
- >
-
-
-
-
- )}
-
- )}
-
-
- {viewMode !== 'dashboard' && (
-
-
-
-
- More options
-
-
-
-
-
-
- Export as CSV
-
-
-
- Configure Notifications
-
-
-
-
- )}
-
-
-
-
- {isRefetching ? (
-
- ) : (
-
- )}
- Refresh
-
-
- {isRefetching ? 'Refreshing...' : 'Refresh'}
-
-
-
- setLive((v) => !v)}
- className={cn(
- 'h-7 rounded-[8px] px-3 font-normal text-xs',
- live
- ? 'bg-[var(--brand-primary-hex)] text-white shadow-[0_0_0_0_var(--brand-primary-hex)] hover:bg-[var(--brand-primary-hover-hex)] hover:text-white hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)]'
- : 'text-muted-foreground hover:text-foreground'
- )}
- aria-pressed={live}
- >
- Live
-
-
-
-
- setViewMode('logs')}
- className={cn(
- 'h-7 rounded-[8px] px-3 font-normal text-xs',
- (viewMode as string) !== 'dashboard'
- ? 'bg-muted text-foreground'
- : 'text-muted-foreground hover:text-foreground'
- )}
- aria-pressed={(viewMode as string) !== 'dashboard'}
- >
- Logs
-
- setViewMode('dashboard')}
- className={cn(
- 'h-7 rounded-[8px] px-3 font-normal text-xs',
- (viewMode as string) === 'dashboard'
- ? 'bg-muted text-foreground'
- : 'text-muted-foreground hover:text-foreground'
- )}
- aria-pressed={(viewMode as string) === 'dashboard'}
- >
- Dashboard
-
-
-
-
-
-
-
-
- )
-}
-
-export default Controls
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/index.ts b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/index.ts
deleted file mode 100644
index 0c5bf9faf6..0000000000
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/controls/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { Controls, default } from './controls'
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/notifications.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/notifications.tsx
index 81bedb0393..a5c09c005e 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/notifications.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/notifications/notifications.tsx
@@ -39,9 +39,6 @@ import { WorkflowSelector } from './components/workflow-selector'
const logger = createLogger('NotificationSettings')
-const PRIMARY_BUTTON_STYLES =
- '!bg-[var(--brand-tertiary-2)] !text-[var(--text-inverse)] hover:!bg-[var(--brand-tertiary-2)]/90'
-
type NotificationType = 'webhook' | 'email' | 'slack'
type LogLevel = 'info' | 'error'
type AlertRule =
@@ -618,10 +615,9 @@ export function NotificationSettings({
handleTest(subscription.id)}
disabled={testNotification.isPending && testStatus?.id !== subscription.id}
- className={PRIMARY_BUTTON_STYLES}
>
{testStatus?.id === subscription.id
? testStatus.success
@@ -703,7 +699,7 @@ export function NotificationSettings({
{activeTab === 'email' && (
Email Recipients
-
+
{invalidEmails.map((email, index) => (
)}
{createNotification.isPending || updateNotification.isPending
? editingId
@@ -1322,9 +1317,8 @@ export function NotificationSettings({
resetForm()
setShowForm(true)
}}
- variant='primary'
+ variant='tertiary'
disabled={isLoading}
- className={PRIMARY_BUTTON_STYLES}
>
Add
@@ -1338,7 +1332,7 @@ export function NotificationSettings({
Delete Notification
-
+
This will permanently remove the notification and stop all deliveries.{' '}
This action cannot be undone.
@@ -1352,10 +1346,9 @@ export function NotificationSettings({
Cancel
{deleteNotification.isPending ? 'Deleting...' : 'Delete'}
@@ -1379,7 +1372,7 @@ function EmailTag({ email, onRemove, isInvalid }: EmailTagProps) {
'flex w-auto items-center gap-[4px] rounded-[4px] border px-[6px] py-[2px] text-[12px]',
isInvalid
? 'border-[var(--text-error)] bg-[color-mix(in_srgb,var(--text-error)_10%,transparent)] text-[var(--text-error)] dark:bg-[color-mix(in_srgb,var(--text-error)_16%,transparent)]'
- : 'border-[var(--surface-11)] bg-[var(--surface-5)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]'
+ : 'border-[var(--border-1)] bg-[var(--surface-4)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]'
)}
>
{email}
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/search/search.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/search/search.tsx
index e5ccb326db..2569d6c5fb 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/search/search.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/components/search/search.tsx
@@ -163,7 +163,7 @@ export function AutocompleteSearch({
}}
>
-
+
{/* Search Icon */}
@@ -266,8 +266,8 @@ export function AutocompleteSearch({
data-index={0}
className={cn(
'w-full rounded-[6px] px-3 py-2 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-focus)]',
- 'hover:bg-[var(--surface-9)]',
- highlightedIndex === 0 && 'bg-[var(--surface-9)]'
+ 'hover:bg-[var(--surface-5)]',
+ highlightedIndex === 0 && 'bg-[var(--surface-5)]'
)}
onMouseEnter={() => setHighlightedIndex(0)}
onMouseDown={(e) => {
@@ -296,8 +296,8 @@ export function AutocompleteSearch({
data-index={index}
className={cn(
'w-full rounded-[6px] px-3 py-2 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-focus)]',
- 'hover:bg-[var(--surface-9)]',
- isHighlighted && 'bg-[var(--surface-9)]'
+ 'hover:bg-[var(--surface-5)]',
+ isHighlighted && 'bg-[var(--surface-5)]'
)}
onMouseEnter={() => setHighlightedIndex(index)}
onMouseDown={(e) => {
@@ -339,8 +339,8 @@ export function AutocompleteSearch({
data-index={index}
className={cn(
'w-full rounded-[6px] px-3 py-2 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-focus)]',
- 'hover:bg-[var(--surface-9)]',
- index === highlightedIndex && 'bg-[var(--surface-9)]'
+ 'hover:bg-[var(--surface-5)]',
+ index === highlightedIndex && 'bg-[var(--surface-5)]'
)}
onMouseEnter={() => setHighlightedIndex(index)}
onMouseDown={(e) => {
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/index.ts b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/index.ts
index a18f450876..2884924bb2 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/index.ts
@@ -1,4 +1,3 @@
-export { Controls } from './components/controls'
export { NotificationSettings } from './components/notifications'
export { AutocompleteSearch } from './components/search'
export { LogsToolbar } from './logs-toolbar'
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx
index a84c69ac44..9bb8c9778a 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx
@@ -302,7 +302,7 @@ export function LogsToolbar({
{/* More options popover */}
-
+
@@ -339,27 +339,36 @@ export function LogsToolbar({
{/* Live button */}
Live
{/* View mode toggle */}
onViewModeChange(isDashboardView ? 'logs' : 'dashboard')}
>
Logs
Dashboard
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts
index 1997309fe5..852b0e9959 100644
--- a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts
+++ b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts
@@ -5,108 +5,57 @@ import { getIntegrationMetadata } from '@/lib/logs/get-trigger-options'
import { getBlock } from '@/blocks/registry'
const CORE_TRIGGER_TYPES = ['manual', 'api', 'schedule', 'chat', 'webhook'] as const
-const RUNNING_COLOR = '#22c55e' as const
-const PENDING_COLOR = '#f59e0b' as const
+/** Possible execution status values for workflow logs */
export type LogStatus = 'error' | 'pending' | 'running' | 'info'
-/**
- * Checks if a hex color is gray/neutral (low saturation) or too light/dark
- */
-export function isGrayOrNeutral(hex: string): boolean {
- const r = Number.parseInt(hex.slice(1, 3), 16)
- const g = Number.parseInt(hex.slice(3, 5), 16)
- const b = Number.parseInt(hex.slice(5, 7), 16)
-
- const max = Math.max(r, g, b)
- const min = Math.min(r, g, b)
- const lightness = (max + min) / 2 / 255
-
- const delta = max - min
- const saturation = delta === 0 ? 0 : delta / (1 - Math.abs(2 * lightness - 1)) / 255
-
- return saturation < 0.2 || lightness > 0.8 || lightness < 0.25
-}
-
-/**
- * Converts a hex color to a background variant with appropriate opacity
- */
-export function hexToBackground(hex: string): string {
- const r = Number.parseInt(hex.slice(1, 3), 16)
- const g = Number.parseInt(hex.slice(3, 5), 16)
- const b = Number.parseInt(hex.slice(5, 7), 16)
- return `rgba(${r}, ${g}, ${b}, 0.2)`
+/** Configuration mapping log status to Badge variant and display label */
+const STATUS_VARIANT_MAP: Record<
+ LogStatus,
+ { variant: React.ComponentProps
['variant']; label: string }
+> = {
+ error: { variant: 'red', label: 'Error' },
+ pending: { variant: 'amber', label: 'Pending' },
+ running: { variant: 'green', label: 'Running' },
+ info: { variant: 'gray', label: 'Info' },
}
-/**
- * Lightens a hex color to make it more vibrant for text
- */
-export function lightenColor(hex: string, percent = 30): string {
- const r = Number.parseInt(hex.slice(1, 3), 16)
- const g = Number.parseInt(hex.slice(3, 5), 16)
- const b = Number.parseInt(hex.slice(5, 7), 16)
-
- const newR = Math.min(255, Math.round(r + (255 - r) * (percent / 100)))
- const newG = Math.min(255, Math.round(g + (255 - g) * (percent / 100)))
- const newB = Math.min(255, Math.round(b + (255 - b) * (percent / 100)))
-
- return `#${newR.toString(16).padStart(2, '0')}${newG.toString(16).padStart(2, '0')}${newB.toString(16).padStart(2, '0')}`
+/** Configuration mapping core trigger types to Badge color variants */
+const TRIGGER_VARIANT_MAP: Record['variant']> = {
+ manual: 'gray-secondary',
+ api: 'blue',
+ schedule: 'teal',
+ chat: 'purple',
+ webhook: 'orange',
}
interface StatusBadgeProps {
+ /** The execution status to display */
status: LogStatus
}
/**
- * Displays a styled badge for a log execution status
+ * Renders a colored badge indicating log execution status.
+ * @param props - Component props containing the status
+ * @returns A Badge with dot indicator and status label
*/
export const StatusBadge = React.memo(({ status }: StatusBadgeProps) => {
- const config = {
- error: {
- bg: 'var(--terminal-status-error-bg)',
- color: 'var(--text-error)',
- label: 'Error',
- },
- pending: {
- bg: hexToBackground(PENDING_COLOR),
- color: lightenColor(PENDING_COLOR, 65),
- label: 'Pending',
- },
- running: {
- bg: hexToBackground(RUNNING_COLOR),
- color: lightenColor(RUNNING_COLOR, 65),
- label: 'Running',
- },
- info: {
- bg: 'var(--terminal-status-info-bg)',
- color: 'var(--terminal-status-info-color)',
- label: 'Info',
- },
- }[status]
-
- return React.createElement(
- 'div',
- {
- className:
- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]',
- style: { backgroundColor: config.bg, color: config.color },
- },
- React.createElement('div', {
- className: 'h-[6px] w-[6px] rounded-[2px]',
- style: { backgroundColor: config.color },
- }),
- config.label
- )
+ const config = STATUS_VARIANT_MAP[status]
+ return React.createElement(Badge, { variant: config.variant, dot: true }, config.label)
})
StatusBadge.displayName = 'StatusBadge'
interface TriggerBadgeProps {
+ /** The trigger type identifier (e.g., 'manual', 'api', or integration block type) */
trigger: string
}
/**
- * Displays a styled badge for a workflow trigger type
+ * Renders a colored badge indicating the workflow trigger type.
+ * Core triggers display with their designated colors; integrations show with icons.
+ * @param props - Component props containing the trigger type
+ * @returns A Badge with appropriate styling for the trigger type
*/
export const TriggerBadge = React.memo(({ trigger }: TriggerBadgeProps) => {
const metadata = getIntegrationMetadata(trigger)
@@ -114,37 +63,20 @@ export const TriggerBadge = React.memo(({ trigger }: TriggerBadgeProps) => {
const block = isIntegration ? getBlock(trigger) : null
const IconComponent = block?.icon
- const isUnknownIntegration = isIntegration && trigger !== 'generic' && !block
- if (
- trigger === 'manual' ||
- trigger === 'generic' ||
- isUnknownIntegration ||
- isGrayOrNeutral(metadata.color)
- ) {
+ const coreVariant = TRIGGER_VARIANT_MAP[trigger]
+ if (coreVariant) {
+ return React.createElement(Badge, { variant: coreVariant }, metadata.label)
+ }
+
+ if (IconComponent) {
return React.createElement(
Badge,
- {
- variant: 'default',
- className:
- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]',
- },
- IconComponent && React.createElement(IconComponent, { className: 'h-[12px] w-[12px]' }),
+ { variant: 'gray-secondary', icon: IconComponent },
metadata.label
)
}
- const textColor = lightenColor(metadata.color, 65)
-
- return React.createElement(
- 'div',
- {
- className:
- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]',
- style: { backgroundColor: hexToBackground(metadata.color), color: textColor },
- },
- IconComponent && React.createElement(IconComponent, { className: 'h-[12px] w-[12px]' }),
- metadata.label
- )
+ return React.createElement(Badge, { variant: 'gray-secondary' }, metadata.label)
})
TriggerBadge.displayName = 'TriggerBadge'
diff --git a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx
index 5199252d00..529dcb6b0b 100644
--- a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx
@@ -29,19 +29,19 @@ export function TemplateCardSkeleton({ className }: { className?: string }) {
return (
-
+
-
+
{Array.from({ length: 3 }).map((_, index) => (
))}
@@ -49,14 +49,14 @@ export function TemplateCardSkeleton({ className }: { className?: string }) {
@@ -202,7 +202,7 @@ function TemplateCardInner({
@@ -223,12 +223,14 @@ function TemplateCardInner({
cursorStyle='pointer'
/>
) : (
-
+
)}
-
{title}
+
+ {title}
+
{blockTypes.length > 4 ? (
@@ -251,10 +253,12 @@ function TemplateCardInner({
)
})}
- +{blockTypes.length - 3}
+
+ +{blockTypes.length - 3}
+
>
) : (
@@ -286,24 +290,26 @@ function TemplateCardInner({
) : (
-
-
+
+
)}
- {author}
+
+ {author}
+
{isVerified && }
-
+
{usageCount}
diff --git a/apps/sim/app/workspace/[workspaceId]/templates/templates.tsx b/apps/sim/app/workspace/[workspaceId]/templates/templates.tsx
index 54f75ff22d..e21ddf305a 100644
--- a/apps/sim/app/workspace/[workspaceId]/templates/templates.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/templates/templates.tsx
@@ -186,7 +186,7 @@ export default function Templates({
-
+
(null)
const timeoutRef = useRef
(null)
const abortControllerRef = useRef(null)
+ const preventZoomRef = usePreventZoom()
// File upload hook
const {
@@ -784,7 +788,8 @@ export function Chat() {
return (
{/* File thumbnails */}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/chat-message/chat-message.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/chat-message/chat-message.tsx
index ae9c5759ee..a669650216 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/chat-message/chat-message.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/chat-message/chat-message.tsx
@@ -156,7 +156,7 @@ export function ChatMessage({ message }: ChatMessageProps) {
)}
{formattedContent && !formattedContent.startsWith('Uploaded') && (
-
+
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx
index 22ccc5b9ae..e23cc92f0d 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/command-list/command-list.tsx
@@ -8,6 +8,7 @@ import { Button } from '@/components/emcn'
import { AgentIcon } from '@/components/icons'
import { cn } from '@/lib/core/utils/cn'
import { createLogger } from '@/lib/logs/console/logger'
+import { usePreventZoom } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import { useSearchModalStore } from '@/stores/search-modal/store'
const logger = createLogger('WorkflowCommandList')
@@ -58,6 +59,7 @@ export function CommandList() {
const params = useParams()
const router = useRouter()
const { open: openSearchModal } = useSearchModalStore()
+ const preventZoomRef = usePreventZoom()
const workspaceId = params.workspaceId as string | undefined
@@ -171,6 +173,7 @@ export function CommandList() {
return (
{
const viewport = useViewport()
const session = useSession()
const currentUserId = session.data?.user?.id
+ const preventZoomRef = usePreventZoom()
const cursors = useMemo
(() => {
return presenceUsers
@@ -41,7 +43,7 @@ const CursorsComponent = () => {
}
return (
-
+
{cursors.map(({ id, name, cursor, color }) => {
const x = cursor.x * viewport.zoom + viewport.x
const y = cursor.y * viewport.zoom + viewport.y
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx
index 570b2edc04..3935fcefeb 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/diff-controls/diff-controls.tsx
@@ -3,6 +3,7 @@ import clsx from 'clsx'
import { Eye, EyeOff } from 'lucide-react'
import { Button } from '@/components/emcn'
import { createLogger } from '@/lib/logs/console/logger'
+import { usePreventZoom } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import { useCopilotStore } from '@/stores/panel/copilot/store'
import { useTerminalStore } from '@/stores/terminal'
import { useWorkflowDiffStore } from '@/stores/workflow-diff'
@@ -308,6 +309,8 @@ export const DiffControls = memo(function DiffControls() {
})
}, [clearPreviewYaml, updatePreviewToolCallState, rejectChanges])
+ const preventZoomRef = usePreventZoom()
+
// Don't show anything if no diff is available or diff is not ready
if (!hasActiveDiff || !isDiffReady) {
return null
@@ -315,6 +318,7 @@ export const DiffControls = memo(function DiffControls() {
return (
Accept
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx
index fb7f292697..249962aeb6 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/error/index.tsx
@@ -3,6 +3,7 @@
import { Component, type ReactNode, useEffect } from 'react'
import { createLogger } from '@/lib/logs/console/logger'
import { Panel } from '@/app/workspace/[workspaceId]/w/[workflowId]/components'
+import { usePreventZoom } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import { Sidebar } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar'
const logger = createLogger('ErrorBoundary')
@@ -23,12 +24,13 @@ export function ErrorUI({
onReset,
fullScreen = false,
}: ErrorUIProps) {
+ const preventZoomRef = usePreventZoom()
const containerClass = fullScreen
? 'flex flex-col w-full h-screen bg-[var(--surface-1)]'
: 'flex flex-col w-full h-full bg-[var(--surface-1)]'
return (
-
+
{/* Sidebar */}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts
index 948fc180cf..123cab3b1a 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts
@@ -4,7 +4,6 @@ export { DiffControls } from './diff-controls/diff-controls'
export { ErrorBoundary } from './error/index'
export { Notifications } from './notifications/notifications'
export { Panel } from './panel/panel'
-export { SkeletonLoading } from './skeleton-loading/skeleton-loading'
export { SubflowNodeComponent } from './subflows/subflow-node'
export { Terminal } from './terminal/terminal'
export { WandPromptBar } from './wand-prompt-bar/wand-prompt-bar'
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx
index 4ca430d854..655cf84f9b 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/note-block/note-block.tsx
@@ -27,6 +27,21 @@ function extractFieldValue(rawValue: unknown): string | undefined {
return undefined
}
+/**
+ * Extract YouTube video ID from various YouTube URL formats
+ */
+function getYouTubeVideoId(url: string): string | null {
+ const patterns = [
+ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
+ /youtube\.com\/watch\?.*v=([a-zA-Z0-9_-]{11})/,
+ ]
+ for (const pattern of patterns) {
+ const match = url.match(pattern)
+ if (match) return match[1]
+ }
+ return null
+}
+
/**
* Compact markdown renderer for note blocks with tight spacing
*/
@@ -36,39 +51,41 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
remarkPlugins={[remarkGfm]}
components={{
p: ({ children }: any) => (
-
{children}
+
+ {children}
+
),
h1: ({ children }: any) => (
-
+
{children}
),
h2: ({ children }: any) => (
-
+
{children}
),
h3: ({ children }: any) => (
-
+
{children}
),
h4: ({ children }: any) => (
-
+
{children}
),
ul: ({ children }: any) => (
-
+
),
ol: ({ children }: any) => (
-
+
{children}
),
- li: ({ children }: any) => {children} ,
+ li: ({ children }: any) => {children} ,
code: ({ inline, className, children, ...props }: any) => {
const isInline = inline || !className?.includes('language-')
@@ -76,7 +93,7 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
return (
{children}
@@ -92,22 +109,51 @@ const NoteMarkdown = memo(function NoteMarkdown({ content }: { content: string }
)
},
- a: ({ href, children }: any) => (
-
- {children}
-
- ),
+ a: ({ href, children }: any) => {
+ const videoId = href ? getYouTubeVideoId(href) : null
+ if (videoId) {
+ return (
+
+
+ {children}
+
+
+ VIDEO
+
+
+ )
+ }
+ return (
+
+ {children}
+
+ )
+ },
strong: ({ children }: any) => (
{children}
),
em: ({ children }: any) => {children} ,
blockquote: ({ children }: any) => (
-
+
{children}
),
@@ -135,28 +181,16 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps {
+ const content = useMemo(() => {
if (data.isPreview && data.subBlockValues) {
- const extractedPreviewFormat = extractFieldValue(data.subBlockValues.format)
- const extractedPreviewContent = extractFieldValue(data.subBlockValues.content)
- return {
- format: typeof extractedPreviewFormat === 'string' ? extractedPreviewFormat : 'plain',
- content: typeof extractedPreviewContent === 'string' ? extractedPreviewContent : '',
- }
- }
-
- const format = extractFieldValue(storedValues?.format)
- const content = extractFieldValue(storedValues?.content)
-
- return {
- format: typeof format === 'string' ? format : 'plain',
- content: typeof content === 'string' ? content : '',
+ const extractedContent = extractFieldValue(data.subBlockValues.content)
+ return typeof extractedContent === 'string' ? extractedContent : ''
}
+ const storedContent = extractFieldValue(storedValues?.content)
+ return typeof storedContent === 'string' ? storedContent : ''
}, [data.isPreview, data.subBlockValues, storedValues])
- const content = noteValues.content ?? ''
const isEmpty = content.trim().length === 0
- const showMarkdown = noteValues.format === 'markdown' && !isEmpty
const userPermissions = useUserPermissionsContext()
@@ -182,7 +216,7 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps
@@ -194,15 +228,12 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps
-
-
-
-
+
{name}
@@ -210,14 +241,12 @@ export const NoteBlock = memo(function NoteBlock({ id, data }: NodeProps
-
+
{isEmpty ? (
-
Add a note...
- ) : showMarkdown ? (
-
+
Add note...
) : (
-
{content}
+
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx
index 410f877507..44f20d96ef 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx
@@ -1,17 +1,18 @@
-import { memo, useCallback } from 'react'
+import { memo, useCallback, useMemo } from 'react'
import clsx from 'clsx'
import { X } from 'lucide-react'
-import { useParams } from 'next/navigation'
import { Button } from '@/components/emcn'
import { createLogger } from '@/lib/logs/console/logger'
import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils'
+import { usePreventZoom } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
import {
type NotificationAction,
openCopilotWithMessage,
useNotificationStore,
} from '@/stores/notifications'
import { useTerminalStore } from '@/stores/terminal'
+import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
const logger = createLogger('Notifications')
const MAX_VISIBLE_NOTIFICATIONS = 4
@@ -22,15 +23,18 @@ const MAX_VISIBLE_NOTIFICATIONS = 4
* Shows both global notifications and workflow-specific notifications
*/
export const Notifications = memo(function Notifications() {
- const params = useParams()
- const workflowId = params.workflowId as string
+ const activeWorkflowId = useWorkflowRegistry((state) => state.activeWorkflowId)
- const notifications = useNotificationStore((state) =>
- state.notifications.filter((n) => !n.workflowId || n.workflowId === workflowId)
- )
+ const allNotifications = useNotificationStore((state) => state.notifications)
const removeNotification = useNotificationStore((state) => state.removeNotification)
const clearNotifications = useNotificationStore((state) => state.clearNotifications)
- const visibleNotifications = notifications.slice(0, MAX_VISIBLE_NOTIFICATIONS)
+
+ const visibleNotifications = useMemo(() => {
+ if (!activeWorkflowId) return []
+ return allNotifications
+ .filter((n) => !n.workflowId || n.workflowId === activeWorkflowId)
+ .slice(0, MAX_VISIBLE_NOTIFICATIONS)
+ }, [allNotifications, activeWorkflowId])
const isTerminalResizing = useTerminalStore((state) => state.isResizing)
/**
@@ -84,7 +88,7 @@ export const Notifications = memo(function Notifications() {
{
id: 'clear-notifications',
handler: () => {
- clearNotifications(workflowId)
+ clearNotifications(activeWorkflowId ?? undefined)
},
overrides: {
allowInEditable: false,
@@ -93,12 +97,15 @@ export const Notifications = memo(function Notifications() {
])
)
+ const preventZoomRef = usePreventZoom()
+
if (visibleNotifications.length === 0) {
return null
}
return (
0 ? '-mt-[78px]' : ''
+ className={`relative h-[80px] w-[240px] overflow-hidden rounded-[4px] border bg-[var(--surface-2)] transition-transform duration-200 ${
+ index > 0 ? '-mt-[80px]' : ''
}`}
>
@@ -137,19 +144,17 @@ export const Notifications = memo(function Notifications() {
{notification.message}
{hasAction && (
-
- executeAction(notification.id, notification.action!)}
- className='w-full px-[8px] py-[4px] font-medium text-[12px]'
- >
- {notification.action!.type === 'copilot'
- ? 'Fix in Copilot'
- : notification.action!.type === 'refresh'
- ? 'Refresh'
- : 'Take action'}
-
-
+
executeAction(notification.id, notification.action!)}
+ className='w-full px-[8px] py-[4px] font-medium text-[12px]'
+ >
+ {notification.action!.type === 'copilot'
+ ? 'Fix in Copilot'
+ : notification.action!.type === 'refresh'
+ ? 'Refresh'
+ : 'Take action'}
+
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx
index 982cf8662d..3132b49176 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx
@@ -137,29 +137,29 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
() => ({
// Paragraph
p: ({ children }: React.HTMLAttributes
) => (
-
+
{children}
),
// Headings
h1: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
h2: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
h3: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
h4: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
@@ -167,7 +167,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
// Lists
ul: ({ children }: React.HTMLAttributes) => (
{children}
@@ -175,7 +175,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
),
ol: ({ children }: React.HTMLAttributes) => (
{children}
@@ -186,7 +186,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
ordered,
}: React.LiHTMLAttributes & { ordered?: boolean }) => (
{children}
@@ -256,14 +256,14 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
: 'javascript'
return (
-
-
-
+
+
+
{language === 'code' ? viewerLanguage : language}
{showCopySuccess ? (
@@ -293,7 +293,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
if (inline) {
return (
{children}
@@ -309,35 +309,33 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
// Bold text
strong: ({ children }: React.HTMLAttributes) => (
-
- {children}
-
+ {children}
),
// Bold text (alternative)
b: ({ children }: React.HTMLAttributes) => (
- {children}
+ {children}
),
// Italic text
em: ({ children }: React.HTMLAttributes) => (
- {children}
+ {children}
),
// Italic text (alternative)
i: ({ children }: React.HTMLAttributes) => (
- {children}
+ {children}
),
// Blockquotes
blockquote: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
// Horizontal rule
- hr: () => ,
+ hr: () => ,
// Links
a: ({ href, children, ...props }: React.AnchorHTMLAttributes) => (
@@ -349,29 +347,31 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
// Tables
table: ({ children }: React.TableHTMLAttributes) => (
-
+
),
thead: ({ children }: React.HTMLAttributes) => (
- {children}
+
+ {children}
+
),
tbody: ({ children }: React.HTMLAttributes) => (
- {children}
+ {children}
),
tr: ({ children }: React.HTMLAttributes) => (
-
+
{children}
),
th: ({ children }: React.ThHTMLAttributes) => (
-
+
{children}
),
td: ({ children }: React.TdHTMLAttributes) => (
-
+
{children}
),
@@ -390,7 +390,7 @@ export default function CopilotMarkdownRenderer({ content }: CopilotMarkdownRend
)
return (
-
+
{content}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx
index 92bc338c8b..a647c50f03 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/thinking-block.tsx
@@ -36,8 +36,8 @@ interface ShimmerOverlayTextProps {
function ShimmerOverlayText({ label, value, active = false }: ShimmerOverlayTextProps) {
return (
- {label}
- {value}
+ {label}
+ {value}
{active ? (
{isExpanded && (
-
-
+
+
{content}
{isStreaming && (
-
+
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx
index 8a865cfbf0..11b59c369e 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx
@@ -108,6 +108,8 @@ const CopilotMessage: FC = memo(
const {
showRestoreConfirmation,
showCheckpointDiscardModal,
+ isReverting,
+ isProcessingDiscard,
pendingEditRef,
setShowCheckpointDiscardModal,
handleRevertToCheckpoint,
@@ -265,30 +267,35 @@ const CopilotMessage: FC = memo(
{/* Inline Checkpoint Discard Confirmation - shown below input in edit mode */}
{showCheckpointDiscardModal && (
-
-
+
+
Continue from a previous message?
-
+
- Cancel
- (Esc)
+ Cancel
- Revert
+ {isProcessingDiscard ? 'Reverting...' : 'Revert'}
Continue
@@ -312,11 +319,11 @@ const CopilotMessage: FC
= memo(
onClick={handleMessageClick}
onMouseEnter={() => setIsHoveringMessage(true)}
onMouseLeave={() => setIsHoveringMessage(false)}
- className='group relative w-full cursor-pointer rounded-[4px] border border-[var(--surface-11)] bg-[var(--surface-6)] px-[6px] py-[6px] transition-all duration-200 hover:border-[var(--surface-14)] hover:bg-[var(--surface-9)] dark:bg-[var(--surface-9)] dark:hover:border-[var(--surface-13)] dark:hover:bg-[var(--surface-11)]'
+ className='group relative w-full cursor-pointer rounded-[4px] border border-[var(--border-1)] bg-[var(--surface-5)] px-[6px] py-[6px] transition-all duration-200 hover:border-[var(--surface-6)] hover:bg-[var(--surface-5)] dark:bg-[var(--surface-5)] dark:hover:border-[var(--surface-6)] dark:hover:bg-[var(--border-1)]'
>
{(() => {
const text = message.content || ''
@@ -358,7 +365,7 @@ const CopilotMessage: FC
= memo(
{/* Gradient fade when truncated - applies to entire message box */}
{!isExpanded && needsExpansion && (
-
+
)}
{/* Abort button when hovering and response is generating (only on last user message) */}
@@ -369,7 +376,7 @@ const CopilotMessage: FC = memo(
e.stopPropagation()
abortMessage()
}}
- className='h-[20px] w-[20px] rounded-full bg-[#C0C0C0] p-0 transition-colors hover:bg-[#D0D0D0] dark:bg-[#C0C0C0] dark:hover:bg-[#D0D0D0]'
+ className='h-[20px] w-[20px] rounded-full bg-[var(--c-C0C0C0)] p-0 transition-colors hover:bg-[var(--c-D0D0D0)]'
title='Stop generation'
>
= memo(
{/* Inline Restore Checkpoint Confirmation */}
{showRestoreConfirmation && (
-
-
+
+
Revert to checkpoint? This will restore your workflow to the state saved at this
checkpoint.{' '}
-
- This action cannot be undone.
-
+ This action cannot be undone.
-
+
- Cancel
- (Esc)
+ Cancel
- Revert
+ {isReverting ? 'Reverting...' : 'Revert'}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/hooks/use-checkpoint-management.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/hooks/use-checkpoint-management.ts
index 07c67775d5..edf0e5eacb 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/hooks/use-checkpoint-management.ts
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/hooks/use-checkpoint-management.ts
@@ -26,6 +26,8 @@ export function useCheckpointManagement(
) {
const [showRestoreConfirmation, setShowRestoreConfirmation] = useState(false)
const [showCheckpointDiscardModal, setShowCheckpointDiscardModal] = useState(false)
+ const [isReverting, setIsReverting] = useState(false)
+ const [isProcessingDiscard, setIsProcessingDiscard] = useState(false)
const pendingEditRef = useRef<{
message: string
fileAttachments?: any[]
@@ -48,6 +50,7 @@ export function useCheckpointManagement(
const handleConfirmRevert = useCallback(async () => {
if (messageCheckpoints.length > 0) {
const latestCheckpoint = messageCheckpoints[0]
+ setIsReverting(true)
try {
await revertToCheckpoint(latestCheckpoint.id)
@@ -100,6 +103,8 @@ export function useCheckpointManagement(
logger.error('Failed to revert to checkpoint:', error)
setShowRestoreConfirmation(false)
onRevertModeChange?.(false)
+ } finally {
+ setIsReverting(false)
}
}
}, [
@@ -125,50 +130,55 @@ export function useCheckpointManagement(
* Reverts to checkpoint then proceeds with pending edit
*/
const handleContinueAndRevert = useCallback(async () => {
- if (messageCheckpoints.length > 0) {
- const latestCheckpoint = messageCheckpoints[0]
- try {
- await revertToCheckpoint(latestCheckpoint.id)
+ setIsProcessingDiscard(true)
+ try {
+ if (messageCheckpoints.length > 0) {
+ const latestCheckpoint = messageCheckpoints[0]
+ try {
+ await revertToCheckpoint(latestCheckpoint.id)
- const { messageCheckpoints: currentCheckpoints } = useCopilotStore.getState()
- const updatedCheckpoints = {
- ...currentCheckpoints,
- [message.id]: messageCheckpoints.slice(1),
- }
- useCopilotStore.setState({ messageCheckpoints: updatedCheckpoints })
+ const { messageCheckpoints: currentCheckpoints } = useCopilotStore.getState()
+ const updatedCheckpoints = {
+ ...currentCheckpoints,
+ [message.id]: messageCheckpoints.slice(1),
+ }
+ useCopilotStore.setState({ messageCheckpoints: updatedCheckpoints })
- logger.info('Reverted to checkpoint before editing message', {
- messageId: message.id,
- checkpointId: latestCheckpoint.id,
- })
- } catch (error) {
- logger.error('Failed to revert to checkpoint:', error)
+ logger.info('Reverted to checkpoint before editing message', {
+ messageId: message.id,
+ checkpointId: latestCheckpoint.id,
+ })
+ } catch (error) {
+ logger.error('Failed to revert to checkpoint:', error)
+ }
}
- }
- setShowCheckpointDiscardModal(false)
+ setShowCheckpointDiscardModal(false)
- const { sendMessage } = useCopilotStore.getState()
- if (pendingEditRef.current) {
- const { message: msg, fileAttachments, contexts } = pendingEditRef.current
- const editIndex = messages.findIndex((m) => m.id === message.id)
- if (editIndex !== -1) {
- const truncatedMessages = messages.slice(0, editIndex)
- const updatedMessage = {
- ...message,
- content: msg,
- fileAttachments: fileAttachments || message.fileAttachments,
- contexts: contexts || (message as any).contexts,
- }
- useCopilotStore.setState({ messages: [...truncatedMessages, updatedMessage] })
+ const { sendMessage } = useCopilotStore.getState()
+ if (pendingEditRef.current) {
+ const { message: msg, fileAttachments, contexts } = pendingEditRef.current
+ const editIndex = messages.findIndex((m) => m.id === message.id)
+ if (editIndex !== -1) {
+ const truncatedMessages = messages.slice(0, editIndex)
+ const updatedMessage = {
+ ...message,
+ content: msg,
+ fileAttachments: fileAttachments || message.fileAttachments,
+ contexts: contexts || (message as any).contexts,
+ }
+ useCopilotStore.setState({ messages: [...truncatedMessages, updatedMessage] })
- await sendMessage(msg, {
- fileAttachments: fileAttachments || message.fileAttachments,
- contexts: contexts || (message as any).contexts,
- messageId: message.id,
- })
+ await sendMessage(msg, {
+ fileAttachments: fileAttachments || message.fileAttachments,
+ contexts: contexts || (message as any).contexts,
+ messageId: message.id,
+ })
+ }
+ pendingEditRef.current = null
}
- pendingEditRef.current = null
+ } finally {
+ setIsProcessingDiscard(false)
}
}, [messageCheckpoints, revertToCheckpoint, message, messages])
@@ -252,6 +262,8 @@ export function useCheckpointManagement(
// State
showRestoreConfirmation,
showCheckpointDiscardModal,
+ isReverting,
+ isProcessingDiscard,
pendingEditRef,
// Operations
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/plan-mode-section/plan-mode-section.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/plan-mode-section/plan-mode-section.tsx
index ec59e62373..e718a0f99f 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/plan-mode-section/plan-mode-section.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/plan-mode-section/plan-mode-section.tsx
@@ -35,9 +35,9 @@ import CopilotMarkdownRenderer from '@/app/workspace/[workspaceId]/w/[workflowId
/**
* Shared border and background styles
*/
-const SURFACE_5 = 'bg-[var(--surface-5)]'
-const SURFACE_9 = 'bg-[var(--surface-9)]'
-const BORDER_STRONG = 'border-[var(--border-strong)]'
+const SURFACE_5 = 'bg-[var(--surface-4)]'
+const SURFACE_9 = 'bg-[var(--surface-5)]'
+const BORDER_STRONG = 'border-[var(--border-1)]'
export interface PlanModeSectionProps {
/**
@@ -184,7 +184,7 @@ const PlanModeSection: React.FC
= ({
style={{ height: `${height}px` }}
>
{/* Header with build/edit/save/clear buttons */}
-
+
Workflow Plan
@@ -265,7 +265,7 @@ const PlanModeSection: React.FC
= ({
className={cn(
'group flex h-[20px] w-full cursor-ns-resize items-center justify-center border-t',
BORDER_STRONG,
- 'transition-colors hover:bg-[var(--surface-9)]',
+ 'transition-colors hover:bg-[var(--surface-5)]',
isResizing && SURFACE_9
)}
onMouseDown={handleResizeStart}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx
index 8eafe62168..8c865f1c21 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx
@@ -66,7 +66,7 @@ export const TodoList = memo(function TodoList({
return (
@@ -92,7 +92,7 @@ export const TodoList = memo(function TodoList({
{/* Progress bar */}
-
+
{todo.executing ? (
@@ -133,7 +133,7 @@ export const TodoList = memo(function TodoList({
'mt-0.5 flex h-4 w-4 flex-shrink-0 items-center justify-center rounded border transition-all',
todo.completed
? 'border-[var(--brand-400)] bg-[var(--brand-400)]'
- : 'border-[#707070]'
+ : 'border-[var(--text-muted)]'
)}
>
{todo.completed ?
: null}
@@ -143,7 +143,9 @@ export const TodoList = memo(function TodoList({
{todo.content}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx
index 0c61ea0b8a..3df44fe0ce 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx
@@ -1,7 +1,6 @@
'use client'
import { useEffect, useRef, useState } from 'react'
-import { Loader2 } from 'lucide-react'
import { Button, Code } from '@/components/emcn'
import { ClientToolCallState } from '@/lib/copilot/tools/client/base-tool'
import { getClientTool } from '@/lib/copilot/tools/client/manager'
@@ -141,13 +140,11 @@ function ShimmerOverlayText({
}: ShimmerOverlayTextProps) {
const [actionVerb, remainder] = splitActionVerb(text)
- // Special tools: use gradient for entire text
+ // Special tools: use tertiary-2 color for entire text with shimmer
if (isSpecial) {
return (
-
- {text}
-
+ {text}
{active ? (
{actionVerb ? (
<>
- {actionVerb}
- {remainder}
+
+ {actionVerb}
+
+
+ {remainder}
+
>
) : (
{text}
@@ -504,13 +505,11 @@ function RunSkipButtons({
// Standardized buttons for all interrupt tools: Allow, Always Allow, Skip
return (
-
- {isProcessing ? : null}
- Allow
+
+ {isProcessing ? 'Allowing...' : 'Allow'}
- {isProcessing ? : null}
- Always Allow
+ {isProcessing ? 'Allowing...' : 'Always Allow'}
Skip
@@ -606,11 +605,11 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
const url = editedParams.url || ''
const method = (editedParams.method || '').toUpperCase()
return (
-
+
-
-
+
+
Method
@@ -619,8 +618,8 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
-
-
+
+
+
-
-
+
+
Name
@@ -682,8 +681,8 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
{normalizedEntries.length === 0 ? (
-
-
+
+
No variables provided
@@ -691,9 +690,9 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
normalizedEntries.map(([originalKey, name, value]) => (
-
+
@@ -755,7 +754,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
}
setEditedParams({ ...editedParams, variables: newVariables })
}}
- className='w-full bg-transparent font-mono text-muted-foreground text-xs outline-none focus:text-foreground'
+ className='w-full bg-transparent font-mono text-[var(--text-muted)] text-xs outline-none focus:text-[var(--text-primary)]'
/>
@@ -771,24 +770,24 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
if (toolCall.name === 'set_global_workflow_variables') {
const ops = Array.isArray(editedParams.operations) ? (editedParams.operations as any[]) : []
return (
-
-
-
+
+
+
Name
-
+
Type
-
{ops.length === 0 ? (
-
+
No operations provided
) : (
-
+
{ops.map((op, idx) => (
@@ -800,11 +799,11 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
newOps[idx] = { ...op, name: e.target.value }
setEditedParams({ ...editedParams, operations: newOps })
}}
- className='w-full bg-transparent font-season text-amber-800 text-xs outline-none dark:text-amber-200'
+ className='w-full bg-transparent font-season text-[var(--text-primary)] text-xs outline-none'
/>
-
+
{String(op.type || '')}
@@ -818,10 +817,10 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
newOps[idx] = { ...op, value: e.target.value }
setEditedParams({ ...editedParams, operations: newOps })
}}
- className='w-full bg-transparent font-[470] font-mono text-amber-700 text-xs outline-none focus:text-amber-800 dark:text-amber-300 dark:focus:text-amber-200'
+ className='w-full bg-transparent font-[470] font-mono text-[var(--text-muted)] text-xs outline-none focus:text-[var(--text-primary)]'
/>
) : (
-
+
—
)}
@@ -864,11 +863,11 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
const inputEntries = Object.entries(safeInputs)
return (
-
+
-
-
+
+
Input
@@ -878,8 +877,8 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
{inputEntries.length === 0 ? (
-
-
+
+
No inputs provided
@@ -887,11 +886,13 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
inputEntries.map(([key, value]) => (
-
+
- {key}
+
+ {key}
+
@@ -926,7 +927,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
setEditedParams({ ...editedParams, [key]: e.target.value })
}
}}
- className='w-full bg-transparent font-mono text-muted-foreground text-xs outline-none focus:text-foreground'
+ className='w-full bg-transparent font-mono text-[var(--text-muted)] text-xs outline-none focus:text-[var(--text-primary)]'
/>
@@ -959,7 +960,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
text={displayName}
active={isLoadingState}
isSpecial={isSpecial}
- className='font-[470] font-season text-[#3a3d41] text-sm dark:text-[#939393]'
+ className='font-[470] font-season text-[var(--text-secondary)] text-sm dark:text-[var(--text-muted)]'
/>
{renderPendingDetails()}
@@ -1010,7 +1011,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
text={displayName}
active={isLoadingState}
isSpecial={false}
- className='font-[470] font-season text-[#939393] text-sm dark:text-[#939393]'
+ className='font-[470] font-season text-[var(--text-muted)] text-sm'
/>
{code && (
@@ -1062,7 +1063,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
text={displayName}
active={isLoadingState}
isSpecial={isSpecial}
- className='font-[470] font-season text-[#3a3d41] text-sm dark:text-[#939393]'
+ className='font-[470] font-season text-[var(--text-secondary)] text-sm dark:text-[var(--text-muted)]'
/>
{isExpandableTool && expanded && {renderPendingDetails()}
}
@@ -1104,7 +1105,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
onStateChange?.('background')
} catch {}
}}
- variant='primary'
+ variant='tertiary'
title='Move to Background'
>
Move to Background
@@ -1135,7 +1136,7 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
onStateChange?.('background')
} catch {}
}}
- variant='primary'
+ variant='tertiary'
title='Wake'
>
Wake
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/attached-files-display/attached-files-display.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/attached-files-display/attached-files-display.tsx
index a240cabc9c..9968487f40 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/attached-files-display/attached-files-display.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/attached-files-display/attached-files-display.tsx
@@ -71,7 +71,7 @@ export function AttachedFilesDisplay({
{files.map((file) => (
onFileClick(file)}
>
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/context-usage-indicator/context-usage-indicator.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/context-usage-indicator/context-usage-indicator.tsx
index 0b245389a1..26b00f89ef 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/context-usage-indicator/context-usage-indicator.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/context-usage-indicator/context-usage-indicator.tsx
@@ -29,9 +29,9 @@ export function ContextUsageIndicator({
const offset = circumference - (percentage / 100) * circumference
const color = useMemo(() => {
- if (percentage >= 90) return '#dc2626'
- if (percentage >= 75) return '#d97706'
- return '#6b7280'
+ if (percentage >= 90) return 'var(--text-error)'
+ if (percentage >= 75) return 'var(--warning)'
+ return 'var(--text-muted)'
}, [percentage])
const displayPercentage = useMemo(() => {
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/mention-menu/mention-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/mention-menu/mention-menu.tsx
index 47e455dcb8..5ba95d91fc 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/mention-menu/mention-menu.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/components/mention-menu/mention-menu.tsx
@@ -29,7 +29,7 @@ function formatTimestamp(iso: string): string {
/**
* Common text styling for loading and empty states
*/
-const STATE_TEXT_CLASSES = 'px-[8px] py-[8px] text-[#868686] text-[12px] dark:text-[#868686]'
+const STATE_TEXT_CLASSES = 'px-[8px] py-[8px] text-[12px] text-[var(--text-muted)]'
/**
* Loading state component for mention folders
@@ -541,9 +541,7 @@ export function MentionMenu({
active={index === submenuActiveIndex}
>
{tpl.name}
-
- {tpl.stars}
-
+
{tpl.stars}
))
)}
@@ -745,9 +743,7 @@ export function MentionMenu({
mentionData.templatesList.map((tpl) => (
insertTemplateMention(tpl)}>
{tpl.name}
-
- {tpl.stars}
-
+ {tpl.stars}
))
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/user-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/user-input.tsx
index e222fec62e..54e12c5df3 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/user-input.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/user-input.tsx
@@ -619,7 +619,7 @@ const UserInput = forwardRef
(
(
{/* Highlight overlay - must have identical flow as textarea */}
{renderOverlayContent()}
@@ -760,8 +760,8 @@ const UserInput = forwardRef
(
className={cn(
'h-[20px] w-[20px] rounded-full p-0 transition-colors',
!isAborting
- ? 'bg-[#C0C0C0] hover:bg-[#D0D0D0] dark:bg-[#C0C0C0] dark:hover:bg-[#D0D0D0]'
- : 'bg-[#C0C0C0] dark:bg-[#C0C0C0]'
+ ? 'bg-[var(--c-C0C0C0)] hover:bg-[var(--c-D0D0D0)]'
+ : 'bg-[var(--c-C0C0C0)]'
)}
title='Stop generation'
>
@@ -787,8 +787,8 @@ const UserInput = forwardRef(
className={cn(
'h-[22px] w-[22px] rounded-full p-0 transition-colors',
canSubmit
- ? 'bg-[#C0C0C0] hover:bg-[#D0D0D0] dark:bg-[#C0C0C0] dark:hover:bg-[#D0D0D0]'
- : 'bg-[#C0C0C0] dark:bg-[#C0C0C0]'
+ ? 'bg-[var(--c-C0C0C0)] hover:bg-[var(--c-D0D0D0)]'
+ : 'bg-[var(--c-C0C0C0)]'
)}
>
{isLoading ? (
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 b6050a2276..b412e2aa0d 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
@@ -398,7 +398,7 @@ export const Copilot = forwardRef(({ panelWidth }, ref
className='flex h-full flex-col overflow-hidden'
>
{/* Header */}
-
+
{currentChat?.title || 'New Chat'}
@@ -418,7 +418,7 @@ export const Copilot = forwardRef
(({ panelWidth }, ref
) : groupedChats.length === 0 ? (
-
+
No chats yet
) : (
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/api/api.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/api/api.tsx
index 577e37ba70..3f10bf62b6 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/api/api.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/api/api.tsx
@@ -478,7 +478,7 @@ console.log(limits);`
code={info.endpoint}
language='javascript'
wrapText
- className='!min-h-0 rounded-[4px] border border-[var(--border-strong)]'
+ className='!min-h-0 rounded-[4px] border border-[var(--border-1)]'
/>
*/}
@@ -534,7 +534,7 @@ console.log(limits);`
code={getSyncCommand()}
language={LANGUAGE_SYNTAX[language]}
wrapText
- className='!min-h-0 rounded-[4px] border border-[var(--border-strong)]'
+ className='!min-h-0 rounded-[4px] border border-[var(--border-1)]'
/>
@@ -577,7 +577,7 @@ console.log(limits);`
code={getStreamCommand()}
language={LANGUAGE_SYNTAX[language]}
wrapText
- className='!min-h-0 rounded-[4px] border border-[var(--border-strong)]'
+ className='!min-h-0 rounded-[4px] border border-[var(--border-1)]'
/>
@@ -655,7 +655,7 @@ console.log(limits);`
code={getAsyncCommand()}
language={LANGUAGE_SYNTAX[language]}
wrapText
- className='!min-h-0 rounded-[4px] border border-[var(--border-strong)]'
+ className='!min-h-0 rounded-[4px] border border-[var(--border-1)]'
/>
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/chat/chat.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/chat/chat.tsx
index 5abaf5623d..1ea49931ea 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/chat/chat.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/chat/chat.tsx
@@ -394,7 +394,7 @@ export function ChatDeploy({
Delete Chat
-
+
Are you sure you want to delete this chat?{' '}
This will remove the chat at "{getEmailDomain()}/chat/{existingChat?.identifier}"
@@ -410,13 +410,7 @@ export function ChatDeploy({
>
Cancel
-
- {isDeleting && }
+
{isDeleting ? 'Deleting...' : 'Delete'}
@@ -507,11 +501,11 @@ function IdentifierInput({
-
+
{getDomainPrefix()}
@@ -787,7 +781,7 @@ function AuthSelector({
{authType === 'email' ? 'Allowed emails' : 'Allowed SSO emails'}
-
+
{invalidEmails.map((email, index) => (
{email}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx
index bf8c11d9d0..95a3febc13 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx
@@ -257,7 +257,7 @@ export function GeneralDeploy({
Load Deployment
-
+
Are you sure you want to load{' '}
{versionToLoadInfo?.name || `v${versionToLoad}`}
@@ -272,11 +272,7 @@ export function GeneralDeploy({
setShowLoadDialog(false)}>
Cancel
-
+
Load deployment
@@ -302,7 +298,7 @@ export function GeneralDeploy({
setShowPromoteDialog(false)}>
Cancel
-
+
Promote to live
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx
index c7ae555050..a6fe480330 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx
@@ -1,7 +1,6 @@
'use client'
-import React, { useEffect, useRef, useState } from 'react'
-import { Loader2 } from 'lucide-react'
+import { forwardRef, useEffect, useRef, useState } from 'react'
import {
Button,
Combobox,
@@ -364,7 +363,7 @@ export function TemplateDeploy({
{
try {
const event = new CustomEvent('open-settings', {
@@ -425,7 +424,7 @@ export function TemplateDeploy({
Delete Template
-
+
Are you sure you want to delete this template?{' '}
This action cannot be undone.
@@ -435,19 +434,11 @@ export function TemplateDeploy({
Cancel
- {deleteMutation.isPending ? (
- <>
-
- Deleting...
- >
- ) : (
- 'Delete'
- )}
+ {deleteMutation.isPending ? 'Deleting...' : 'Delete'}
@@ -463,7 +454,7 @@ export function TemplateDeploy({
* Hidden container for OG image capture.
* Lazy-rendered only when capturing - gets workflow state from store on mount.
*/
-const OGCaptureContainer = React.forwardRef((_, ref) => {
+const OGCaptureContainer = forwardRef((_, ref) => {
const blocks = useWorkflowStore((state) => state.blocks)
const edges = useWorkflowStore((state) => state.edges)
const loops = useWorkflowStore((state) => state.loops)
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx
index 84b3996fbb..6d65140631 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx
@@ -1,8 +1,8 @@
'use client'
import { useCallback, useEffect, useState } from 'react'
-import clsx from 'clsx'
import {
+ Badge,
Button,
Modal,
ModalBody,
@@ -630,7 +630,7 @@ export function DeployModal({
{chatExists && (
@@ -639,7 +639,7 @@ export function DeployModal({
)}
@@ -669,7 +669,7 @@ export function DeployModal({
{hasExistingTemplate && (
@@ -678,7 +678,7 @@ export function DeployModal({
)}
@@ -700,7 +700,7 @@ export function DeployModal({
Undeploy API
-
+
Are you sure you want to undeploy this workflow?{' '}
This will remove the API endpoint and make it unavailable to external users.
@@ -715,12 +715,7 @@ export function DeployModal({
>
Cancel
-
+
{isUndeploying ? 'Undeploying...' : 'Undeploy'}
@@ -736,29 +731,10 @@ interface StatusBadgeProps {
function StatusBadge({ isWarning }: StatusBadgeProps) {
const label = isWarning ? 'Update deployment' : 'Live'
-
return (
-
+
+ {label}
+
)
}
@@ -778,35 +754,10 @@ function TemplateStatusBadge({ status, views, stars }: TemplateStatusBadgeProps)
: null
return (
-
-
-
- {label}
-
- {statsText && (
-
- • {statsText}
-
- )}
-
+
+ {label}
+ {statsText && • {statsText} }
+
)
}
@@ -832,8 +783,8 @@ function GeneralFooter({
if (!isDeployed) {
return (
-
- {isSubmitting ? 'Deploying...' : 'Deploy API'}
+
+ {isSubmitting ? 'Deploying...' : 'Deploy'}
)
@@ -847,7 +798,7 @@ function GeneralFooter({
{isUndeploying ? 'Undeploying...' : 'Undeploy'}
{needsRedeployment && (
-
+
{isSubmitting ? 'Updating...' : 'Update'}
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx
index 7c2253351b..2d842ec541 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx
@@ -2,7 +2,7 @@
import { useCallback, useState } from 'react'
import { Loader2 } from 'lucide-react'
-import { Button, Rocket, Tooltip } from '@/components/emcn'
+import { Button, Tooltip } from '@/components/emcn'
import { DeployModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal'
import {
useChangeDetection,
@@ -113,17 +113,15 @@ export function Deploy({ activeWorkflowId, userPermissions, className }: DeployP
- {isDeploying ? (
-
- ) : (
-
- )}
- {changeDetected ? 'Update' : isDeployed ? 'Active' : 'Deploy'}
+ {isDeploying && }
+ {changeDetected ? 'Update' : isDeployed ? 'Live' : 'Deploy'}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item.tsx
index 44f881c62e..d6e315e1f7 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item.tsx
@@ -29,17 +29,6 @@ interface FieldItemProps {
onToggleExpand?: (path: string) => void
}
-/**
- * Tree layout constants shared with parent component
- */
-export const TREE_SPACING = {
- INDENT_PER_LEVEL: 20,
- BASE_INDENT: 20,
- VERTICAL_LINE_LEFT_OFFSET: 4,
- ITEM_GAP: 0,
- ITEM_HEIGHT: 25,
-} as const
-
/**
* Individual field item component with drag functionality
*/
@@ -52,8 +41,6 @@ export function FieldItem({
isExpanded,
onToggleExpand,
}: FieldItemProps) {
- const indent = TREE_SPACING.BASE_INDENT + level * TREE_SPACING.INDENT_PER_LEVEL
-
const handleDragStart = useCallback(
(e: React.DragEvent) => {
const normalizedBlockName = connection.name.replace(/\s+/g, '').toLowerCase()
@@ -91,25 +78,26 @@ export function FieldItem({
onDragStart={handleDragStart}
onClick={handleClick}
className={clsx(
- 'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[8px] text-[14px] hover:bg-[var(--border)] active:cursor-grabbing',
+ 'group flex h-[26px] cursor-grab items-center gap-[8px] rounded-[8px] px-[6px] text-[14px] hover:bg-[var(--surface-5)] active:cursor-grabbing',
hasChildren && 'cursor-pointer'
)}
- style={{ marginLeft: `${indent}px` }}
>
{field.name}
- {field.type}
+
+ {field.type}
+
{hasChildren && (
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/connection-blocks.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/connection-blocks.tsx
index 61a8cd91a7..556975bced 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/connection-blocks.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/connection-blocks.tsx
@@ -8,7 +8,6 @@ import { createLogger } from '@/lib/logs/console/logger'
import {
FieldItem,
type SchemaField,
- TREE_SPACING,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/connection-blocks/components/field-item/field-item'
import type { ConnectedBlock } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-block-connections'
import { useBlockOutputFields } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-block-output-fields'
@@ -24,43 +23,6 @@ interface ConnectionBlocksProps {
currentBlockId: string
}
-const TREE_STYLES = {
- LINE_COLOR: 'var(--border)',
- LINE_OFFSET: 4,
-} as const
-
-/**
- * Calculates total height of visible nested fields recursively
- */
-const calculateFieldsHeight = (
- fields: SchemaField[] | undefined,
- parentPath: string,
- connectionId: string,
- isExpanded: (connectionId: string, path: string) => boolean
-): number => {
- if (!fields || fields.length === 0) return 0
-
- let totalHeight = 0
-
- fields.forEach((field, index) => {
- const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name
- const expanded = isExpanded(connectionId, fieldPath)
-
- totalHeight += TREE_SPACING.ITEM_HEIGHT
-
- if (index < fields.length - 1) {
- totalHeight += TREE_SPACING.ITEM_GAP
- }
-
- if (expanded && field.children && field.children.length > 0) {
- totalHeight += TREE_SPACING.ITEM_GAP
- totalHeight += calculateFieldsHeight(field.children, fieldPath, connectionId, isExpanded)
- }
- })
-
- return totalHeight
-}
-
interface ConnectionItemProps {
connection: ConnectedBlock
isExpanded: boolean
@@ -123,13 +85,13 @@ function ConnectionItem({
draggable
onDragStart={(e) => onConnectionDragStart(e, connection)}
className={clsx(
- 'group flex h-[25px] cursor-grab items-center gap-[8px] rounded-[8px] px-[5.5px] text-[14px] hover:bg-[var(--border)] active:cursor-grabbing',
+ 'group flex h-[26px] cursor-grab items-center gap-[8px] rounded-[8px] px-[6px] text-[14px] hover:bg-[var(--surface-5)] active:cursor-grabbing',
hasFields && 'cursor-pointer'
)}
onClick={() => hasFields && onToggleExpand(connection.id)}
>
{Icon && (
@@ -137,7 +99,7 @@ function ConnectionItem({
className={clsx(
'text-white transition-transform duration-200',
hasFields && 'group-hover:scale-110',
- '!h-[10px] !w-[10px]'
+ '!h-[9px] !w-[9px]'
)}
/>
)}
@@ -145,7 +107,7 @@ function ConnectionItem({
{connection.name}
@@ -153,8 +115,8 @@ function ConnectionItem({
{hasFields && (
@@ -162,17 +124,8 @@ function ConnectionItem({
{isExpanded && hasFields && (
-
-
+
+
{renderFieldTree(fields, '', 0, connection)}
)}
@@ -311,18 +264,9 @@ export function ConnectionBlocks({ connections, currentBlockId }: ConnectionBloc
onToggleExpand={(p) => toggleFieldExpansion(connection.id, p)}
/>
{hasChildren && expanded && (
-
-
-
{renderFieldTree(field.children!, fieldPath, level + 1, connection)}
+
+
+ {renderFieldTree(field.children!, fieldPath, level + 1, connection)}
)}
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 657011e3d5..839a3334ff 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
@@ -285,6 +285,7 @@ export function ComboBox({
overlayContent={overlayContent}
inputRef={ref as React.RefObject
}
filterOptions
+ searchable={config.searchable}
className={cn('allow-scroll overflow-x-auto', selectedOptionIcon && 'pl-[28px]')}
inputProps={{
onDrop: onDrop as (e: React.DragEvent) => void,
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx
index 7dd19a0497..af1eb7acb7 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx
@@ -709,14 +709,14 @@ export function ConditionInput({
{conditionalBlocks.map((block, index) => (
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx
index 2744a2b23b..23f43e0d1d 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx
@@ -26,15 +26,15 @@ export interface OAuthRequiredModalProps {
}
const SCOPE_DESCRIPTIONS: Record = {
- 'https://www.googleapis.com/auth/gmail.send': 'Send emails on your behalf',
- 'https://www.googleapis.com/auth/gmail.labels': 'View and manage your email labels',
- 'https://www.googleapis.com/auth/gmail.modify': 'View and manage your email messages',
- 'https://www.googleapis.com/auth/drive.file': 'View and manage your Google Drive files',
- 'https://www.googleapis.com/auth/drive': 'Full access to all your Google Drive files',
- 'https://www.googleapis.com/auth/calendar': 'View and manage your calendar',
- 'https://www.googleapis.com/auth/userinfo.email': 'View your email address',
- 'https://www.googleapis.com/auth/userinfo.profile': 'View your basic profile info',
- 'https://www.googleapis.com/auth/forms.responses.readonly': 'View responses to your Google Forms',
+ 'https://www.googleapis.com/auth/gmail.send': 'Send emails',
+ 'https://www.googleapis.com/auth/gmail.labels': 'View and manage email labels',
+ 'https://www.googleapis.com/auth/gmail.modify': 'View and manage email messages',
+ 'https://www.googleapis.com/auth/drive.file': 'View and manage Google Drive files',
+ 'https://www.googleapis.com/auth/drive': 'Access all Google Drive files',
+ 'https://www.googleapis.com/auth/calendar': 'View and manage calendar',
+ 'https://www.googleapis.com/auth/userinfo.email': 'View email address',
+ 'https://www.googleapis.com/auth/userinfo.profile': 'View basic profile info',
+ 'https://www.googleapis.com/auth/forms.responses.readonly': 'View responses to Google Forms',
'https://www.googleapis.com/auth/ediscovery': 'Access Google Vault for eDiscovery',
'https://www.googleapis.com/auth/devstorage.read_only': 'Read files from Google Cloud Storage',
'https://www.googleapis.com/auth/admin.directory.group': 'Manage Google Workspace groups',
@@ -66,50 +66,50 @@ const SCOPE_DESCRIPTIONS: Record = {
'write:label:confluence': 'Add and remove labels',
'search:confluence': 'Search Confluence content',
'readonly:content.attachment:confluence': 'View attachments',
- 'read:me': 'Read your profile information',
- 'database.read': 'Read your database',
- 'database.write': 'Write to your database',
- 'projects.read': 'Read your projects',
- offline_access: 'Access your account when you are not using the application',
- repo: 'Access your repositories',
+ 'read:me': 'Read profile information',
+ 'database.read': 'Read database',
+ 'database.write': 'Write to database',
+ 'projects.read': 'Read projects',
+ offline_access: 'Access account when not using the application',
+ repo: 'Access repositories',
workflow: 'Manage repository workflows',
- 'read:user': 'Read your public user information',
- 'user:email': 'Access your email address',
- 'tweet.read': 'Read your tweets and timeline',
- 'tweet.write': 'Post tweets on your behalf',
- 'users.read': 'Read your profile information',
- 'offline.access': 'Access your account when you are not using the application',
- 'data.records:read': 'Read your records',
- 'data.records:write': 'Write to your records',
- 'webhook:manage': 'Manage your webhooks',
- 'page.read': 'Read your Notion pages',
- 'page.write': 'Write to your Notion pages',
- 'workspace.content': 'Read your Notion content',
- 'workspace.name': 'Read your Notion workspace name',
- 'workspace.read': 'Read your Notion workspace',
- 'workspace.write': 'Write to your Notion workspace',
- 'user.email:read': 'Read your email address',
- 'read:jira-user': 'Read your Jira user',
- 'read:jira-work': 'Read your Jira work',
- 'write:jira-work': 'Write to your Jira work',
+ 'read:user': 'Read public user information',
+ 'user:email': 'Access email address',
+ 'tweet.read': 'Read tweets and timeline',
+ 'tweet.write': 'Post tweets',
+ 'users.read': 'Read profile information',
+ 'offline.access': 'Access account when not using the application',
+ 'data.records:read': 'Read records',
+ 'data.records:write': 'Write to records',
+ 'webhook:manage': 'Manage webhooks',
+ 'page.read': 'Read Notion pages',
+ 'page.write': 'Write to Notion pages',
+ 'workspace.content': 'Read Notion content',
+ 'workspace.name': 'Read Notion workspace name',
+ 'workspace.read': 'Read Notion workspace',
+ 'workspace.write': 'Write to Notion workspace',
+ 'user.email:read': 'Read email address',
+ 'read:jira-user': 'Read Jira user',
+ 'read:jira-work': 'Read Jira work',
+ 'write:jira-work': 'Write to Jira work',
'manage:jira-webhook': 'Register and manage Jira webhooks',
'read:webhook:jira': 'View Jira webhooks',
'write:webhook:jira': 'Create and update Jira webhooks',
'delete:webhook:jira': 'Delete Jira webhooks',
- 'read:issue-event:jira': 'Read your Jira issue events',
- 'write:issue:jira': 'Write to your Jira issues',
- 'read:project:jira': 'Read your Jira projects',
- 'read:issue-type:jira': 'Read your Jira issue types',
- 'read:issue-meta:jira': 'Read your Jira issue meta',
- 'read:issue-security-level:jira': 'Read your Jira issue security level',
- 'read:issue.vote:jira': 'Read your Jira issue votes',
- 'read:issue.changelog:jira': 'Read your Jira issue changelog',
- 'read:avatar:jira': 'Read your Jira avatar',
- 'read:issue:jira': 'Read your Jira issues',
- 'read:status:jira': 'Read your Jira status',
- 'read:user:jira': 'Read your Jira user',
- 'read:field-configuration:jira': 'Read your Jira field configuration',
- 'read:issue-details:jira': 'Read your Jira issue details',
+ 'read:issue-event:jira': 'Read Jira issue events',
+ 'write:issue:jira': 'Write to Jira issues',
+ 'read:project:jira': 'Read Jira projects',
+ 'read:issue-type:jira': 'Read Jira issue types',
+ 'read:issue-meta:jira': 'Read Jira issue meta',
+ 'read:issue-security-level:jira': 'Read Jira issue security level',
+ 'read:issue.vote:jira': 'Read Jira issue votes',
+ 'read:issue.changelog:jira': 'Read Jira issue changelog',
+ 'read:avatar:jira': 'Read Jira avatar',
+ 'read:issue:jira': 'Read Jira issues',
+ 'read:status:jira': 'Read Jira status',
+ 'read:user:jira': 'Read Jira user',
+ 'read:field-configuration:jira': 'Read Jira field configuration',
+ 'read:issue-details:jira': 'Read Jira issue details',
'read:field:jira': 'Read Jira field configurations',
'read:jql:jira': 'Use JQL to filter Jira issues',
'read:comment.property:jira': 'Read Jira comment properties',
@@ -125,57 +125,57 @@ const SCOPE_DESCRIPTIONS: Record = {
'delete:issue-worklog:jira': 'Delete worklog entries from Jira issues',
'write:issue-link:jira': 'Create links between Jira issues',
'delete:issue-link:jira': 'Delete links between Jira issues',
- 'User.Read': 'Read your Microsoft user',
- 'Chat.Read': 'Read your Microsoft chats',
- 'Chat.ReadWrite': 'Write to your Microsoft chats',
- 'Chat.ReadBasic': 'Read your Microsoft chats',
- 'ChatMessage.Send': 'Send chat messages on your behalf',
- 'Channel.ReadBasic.All': 'Read your Microsoft channels',
- 'ChannelMessage.Send': 'Write to your Microsoft channels',
- 'ChannelMessage.Read.All': 'Read your Microsoft channels',
- 'ChannelMessage.ReadWrite': 'Read and write to your Microsoft channels',
+ 'User.Read': 'Read Microsoft user',
+ 'Chat.Read': 'Read Microsoft chats',
+ 'Chat.ReadWrite': 'Write to Microsoft chats',
+ 'Chat.ReadBasic': 'Read Microsoft chats',
+ 'ChatMessage.Send': 'Send chat messages',
+ 'Channel.ReadBasic.All': 'Read Microsoft channels',
+ 'ChannelMessage.Send': 'Write to Microsoft channels',
+ 'ChannelMessage.Read.All': 'Read Microsoft channels',
+ 'ChannelMessage.ReadWrite': 'Read and write to Microsoft channels',
'ChannelMember.Read.All': 'Read team channel members',
- 'Group.Read.All': 'Read your Microsoft groups',
- 'Group.ReadWrite.All': 'Write to your Microsoft groups',
- 'Team.ReadBasic.All': 'Read your Microsoft teams',
+ 'Group.Read.All': 'Read Microsoft groups',
+ 'Group.ReadWrite.All': 'Write to Microsoft groups',
+ 'Team.ReadBasic.All': 'Read Microsoft teams',
'TeamMember.Read.All': 'Read team members',
- 'Mail.ReadWrite': 'Write to your Microsoft emails',
- 'Mail.ReadBasic': 'Read your Microsoft emails',
- 'Mail.Read': 'Read your Microsoft emails',
- 'Mail.Send': 'Send emails on your behalf',
- 'Files.Read': 'Read your OneDrive files',
- 'Files.ReadWrite': 'Read and write your OneDrive files',
- 'Tasks.ReadWrite': 'Read and manage your Planner tasks',
+ 'Mail.ReadWrite': 'Write to Microsoft emails',
+ 'Mail.ReadBasic': 'Read Microsoft emails',
+ 'Mail.Read': 'Read Microsoft emails',
+ 'Mail.Send': 'Send emails',
+ 'Files.Read': 'Read OneDrive files',
+ 'Files.ReadWrite': 'Read and write OneDrive files',
+ 'Tasks.ReadWrite': 'Read and manage Planner tasks',
'Sites.Read.All': 'Read Sharepoint sites',
'Sites.ReadWrite.All': 'Read and write Sharepoint sites',
'Sites.Manage.All': 'Manage Sharepoint sites',
openid: 'Standard authentication',
- profile: 'Access your profile information',
- email: 'Access your email address',
- identify: 'Read your Discord user',
- bot: 'Read your Discord bot',
- 'messages.read': 'Read your Discord messages',
- guilds: 'Read your Discord guilds',
- 'guilds.members.read': 'Read your Discord guild members',
- identity: 'Access your Reddit identity',
- submit: 'Submit posts and comments on your behalf',
+ profile: 'Access profile information',
+ email: 'Access email address',
+ identify: 'Read Discord user',
+ bot: 'Read Discord bot',
+ 'messages.read': 'Read Discord messages',
+ guilds: 'Read Discord guilds',
+ 'guilds.members.read': 'Read Discord guild members',
+ identity: 'Access Reddit identity',
+ submit: 'Submit posts and comments',
vote: 'Vote on posts and comments',
save: 'Save and unsave posts and comments',
- edit: 'Edit your posts and comments',
+ edit: 'Edit posts and comments',
subscribe: 'Subscribe and unsubscribe from subreddits',
- history: 'Access your Reddit history',
- privatemessages: 'Access your inbox and send private messages',
- account: 'Update your account preferences and settings',
- mysubreddits: 'Access your subscribed and moderated subreddits',
+ history: 'Access Reddit history',
+ privatemessages: 'Access inbox and send private messages',
+ account: 'Update account preferences and settings',
+ mysubreddits: 'Access subscribed and moderated subreddits',
flair: 'Manage user and post flair',
report: 'Report posts and comments for rule violations',
- modposts: 'Approve, remove, and moderate posts in subreddits you moderate',
- modflair: 'Manage flair in subreddits you moderate',
+ modposts: 'Approve, remove, and moderate posts in moderated subreddits',
+ modflair: 'Manage flair in moderated subreddits',
modmail: 'Access and respond to moderator mail',
- login: 'Access your Wealthbox account',
- data: 'Access your Wealthbox data',
- read: 'Read access to your workspace',
- write: 'Write access to your Linear workspace',
+ login: 'Access Wealthbox account',
+ data: 'Access Wealthbox data',
+ read: 'Read access to workspace',
+ write: 'Write access to Linear workspace',
'channels:read': 'View public channels',
'channels:history': 'Read channel messages',
'groups:read': 'View private channels',
@@ -190,15 +190,15 @@ const SCOPE_DESCRIPTIONS: Record = {
'files:read': 'Download and read files',
'canvases:write': 'Create canvas documents',
'reactions:write': 'Add emoji reactions to messages',
- 'sites:read': 'View your Webflow sites',
+ 'sites:read': 'View Webflow sites',
'sites:write': 'Manage webhooks and site settings',
- 'cms:read': 'View your CMS content',
- 'cms:write': 'Manage your CMS content',
- 'crm.objects.contacts.read': 'Read your HubSpot contacts',
+ 'cms:read': 'View CMS content',
+ 'cms:write': 'Manage CMS content',
+ 'crm.objects.contacts.read': 'Read HubSpot contacts',
'crm.objects.contacts.write': 'Create and update HubSpot contacts',
- 'crm.objects.companies.read': 'Read your HubSpot companies',
+ 'crm.objects.companies.read': 'Read HubSpot companies',
'crm.objects.companies.write': 'Create and update HubSpot companies',
- 'crm.objects.deals.read': 'Read your HubSpot deals',
+ 'crm.objects.deals.read': 'Read HubSpot deals',
'crm.objects.deals.write': 'Create and update HubSpot deals',
'crm.objects.owners.read': 'Read HubSpot object owners',
'crm.objects.users.read': 'Read HubSpot users',
@@ -218,74 +218,74 @@ const SCOPE_DESCRIPTIONS: Record = {
'crm.lists.write': 'Create and update HubSpot lists',
tickets: 'Manage HubSpot tickets',
api: 'Access Salesforce API',
- refresh_token: 'Maintain long-term access to your Salesforce account',
- default: 'Access your Asana workspace',
- base: 'Basic access to your Pipedrive account',
- 'deals:read': 'Read your Pipedrive deals',
- 'deals:full': 'Full access to manage your Pipedrive deals',
- 'contacts:read': 'Read your Pipedrive contacts',
- 'contacts:full': 'Full access to manage your Pipedrive contacts',
- 'leads:read': 'Read your Pipedrive leads',
- 'leads:full': 'Full access to manage your Pipedrive leads',
- 'activities:read': 'Read your Pipedrive activities',
- 'activities:full': 'Full access to manage your Pipedrive activities',
- 'mail:read': 'Read your Pipedrive emails',
- 'mail:full': 'Full access to manage your Pipedrive emails',
- 'projects:read': 'Read your Pipedrive projects',
- 'projects:full': 'Full access to manage your Pipedrive projects',
- 'webhooks:read': 'Read your Pipedrive webhooks',
- 'webhooks:full': 'Full access to manage your Pipedrive webhooks',
- w_member_social: 'Access your LinkedIn profile',
+ refresh_token: 'Maintain long-term access to Salesforce account',
+ default: 'Access Asana workspace',
+ base: 'Basic access to Pipedrive account',
+ 'deals:read': 'Read Pipedrive deals',
+ 'deals:full': 'Full access to manage Pipedrive deals',
+ 'contacts:read': 'Read Pipedrive contacts',
+ 'contacts:full': 'Full access to manage Pipedrive contacts',
+ 'leads:read': 'Read Pipedrive leads',
+ 'leads:full': 'Full access to manage Pipedrive leads',
+ 'activities:read': 'Read Pipedrive activities',
+ 'activities:full': 'Full access to manage Pipedrive activities',
+ 'mail:read': 'Read Pipedrive emails',
+ 'mail:full': 'Full access to manage Pipedrive emails',
+ 'projects:read': 'Read Pipedrive projects',
+ 'projects:full': 'Full access to manage Pipedrive projects',
+ 'webhooks:read': 'Read Pipedrive webhooks',
+ 'webhooks:full': 'Full access to manage Pipedrive webhooks',
+ w_member_social: 'Access LinkedIn profile',
// Box scopes
- root_readwrite: 'Read and write all files and folders in your Box account',
- root_readonly: 'Read all files and folders in your Box account',
+ root_readwrite: 'Read and write all files and folders in Box account',
+ root_readonly: 'Read all files and folders in Box account',
// Shopify scopes (write_* implicitly includes read access)
- write_products: 'Read and manage your Shopify products',
- write_orders: 'Read and manage your Shopify orders',
- write_customers: 'Read and manage your Shopify customers',
- write_inventory: 'Read and manage your Shopify inventory levels',
- read_locations: 'View your store locations',
+ write_products: 'Read and manage Shopify products',
+ write_orders: 'Read and manage Shopify orders',
+ write_customers: 'Read and manage Shopify customers',
+ write_inventory: 'Read and manage Shopify inventory levels',
+ read_locations: 'View store locations',
write_merchant_managed_fulfillment_orders: 'Create fulfillments for orders',
// Zoom scopes
- 'user:read:user': 'View your Zoom profile information',
+ 'user:read:user': 'View Zoom profile information',
'meeting:write:meeting': 'Create Zoom meetings',
'meeting:read:meeting': 'View Zoom meeting details',
- 'meeting:read:list_meetings': 'List your Zoom meetings',
+ 'meeting:read:list_meetings': 'List Zoom meetings',
'meeting:update:meeting': 'Update Zoom meetings',
'meeting:delete:meeting': 'Delete Zoom meetings',
'meeting:read:invitation': 'View Zoom meeting invitations',
'meeting:read:list_past_participants': 'View past meeting participants',
- 'cloud_recording:read:list_user_recordings': 'List your Zoom cloud recordings',
+ 'cloud_recording:read:list_user_recordings': 'List Zoom cloud recordings',
'cloud_recording:read:list_recording_files': 'View recording files',
'cloud_recording:delete:recording_file': 'Delete cloud recordings',
// Dropbox scopes
- 'account_info.read': 'View your Dropbox account information',
+ 'account_info.read': 'View Dropbox account information',
'files.metadata.read': 'View file and folder names, sizes, and dates',
'files.metadata.write': 'Modify file and folder metadata',
- 'files.content.read': 'Download and read your Dropbox files',
- 'files.content.write': 'Upload, copy, move, and delete files in your Dropbox',
- 'sharing.read': 'View your shared files and folders',
+ 'files.content.read': 'Download and read Dropbox files',
+ 'files.content.write': 'Upload, copy, move, and delete files in Dropbox',
+ 'sharing.read': 'View shared files and folders',
'sharing.write': 'Share files and folders with others',
// WordPress.com scopes
- global: 'Full access to manage your WordPress.com sites, posts, pages, media, and settings',
+ global: 'Full access to manage WordPress.com sites, posts, pages, media, and settings',
// Spotify scopes
- 'user-read-private': 'View your Spotify account details',
- 'user-read-email': 'View your email address on Spotify',
- 'user-library-read': 'View your saved tracks and albums',
- 'user-library-modify': 'Save and remove tracks and albums from your library',
- 'playlist-read-private': 'View your private playlists',
- 'playlist-read-collaborative': 'View collaborative playlists you have access to',
- 'playlist-modify-public': 'Create and manage your public playlists',
- 'playlist-modify-private': 'Create and manage your private playlists',
- 'user-read-playback-state': 'View your current playback state',
- 'user-modify-playback-state': 'Control playback on your Spotify devices',
- 'user-read-currently-playing': 'View your currently playing track',
- 'user-read-recently-played': 'View your recently played tracks',
- 'user-top-read': 'View your top artists and tracks',
- 'user-follow-read': 'View artists and users you follow',
+ 'user-read-private': 'View Spotify account details',
+ 'user-read-email': 'View email address on Spotify',
+ 'user-library-read': 'View saved tracks and albums',
+ 'user-library-modify': 'Save and remove tracks and albums from library',
+ 'playlist-read-private': 'View private playlists',
+ 'playlist-read-collaborative': 'View collaborative playlists',
+ 'playlist-modify-public': 'Create and manage public playlists',
+ 'playlist-modify-private': 'Create and manage private playlists',
+ 'user-read-playback-state': 'View current playback state',
+ 'user-modify-playback-state': 'Control playback on Spotify devices',
+ 'user-read-currently-playing': 'View currently playing track',
+ 'user-read-recently-played': 'View recently played tracks',
+ 'user-top-read': 'View top artists and tracks',
+ 'user-follow-read': 'View followed artists and users',
'user-follow-modify': 'Follow and unfollow artists and users',
- 'user-read-playback-position': 'View your playback position in podcasts',
- 'ugc-image-upload': 'Upload images to your Spotify playlists',
+ 'user-read-playback-position': 'View playback position in podcasts',
+ 'ugc-image-upload': 'Upload images to Spotify playlists',
}
function getScopeDescription(scope: string): string {
@@ -380,7 +380,7 @@ export function OAuthRequiredModal({
-
+
@@ -394,22 +394,22 @@ export function OAuthRequiredModal({
{displayScopes.length > 0 && (
-
-
-
+
+
+
Permissions requested
{displayScopes.map((scope) => (
-