Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/sim/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
--panel-width: 244px;
--toolbar-triggers-height: 300px;
--editor-connections-height: 200px;
--terminal-height: 145px;
--terminal-height: 196px;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: editing globals.css violates project policy - terminal height styling should be moved to local terminal component file

Suggested change
--terminal-height: 196px;
--terminal-height: 145px;

Context Used: Context from dashboard - Avoid editing the globals.css file unless absolutely necessary. Move style changes to local componen... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/app/globals.css
Line: 14:14

Comment:
**logic:** editing `globals.css` violates project policy - terminal height styling should be moved to local terminal component file

```suggestion
  --terminal-height: 145px;
```

**Context Used:** Context from `dashboard` - Avoid editing the globals.css file unless absolutely necessary. Move style changes to local componen... ([source](https://app.greptile.com/review/custom-context?memory=c3b5e4b0-6580-4307-83aa-ba28f105b3c4))

How can I resolve this? If you propose a fix, please make it concise.

}

.sidebar-container {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ export function Chat() {

return (
<div
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] bg-[var(--surface-1)] px-[10px] pt-[2px] pb-[8px]'
className='fixed z-30 flex flex-col overflow-hidden rounded-[6px] border border-[var(--border)] bg-[var(--surface-1)] px-[10px] pt-[2px] pb-[8px]'
style={{
left: `${actualPosition.x}px`,
top: `${actualPosition.y}px`,
Expand Down Expand Up @@ -619,6 +619,7 @@ export function Chat() {
side='bottom'
align='end'
sideOffset={8}
maxHeight={100}
style={{ width: '110px', minWidth: '110px' }}
>
<PopoverScrollArea>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,36 +288,41 @@ export function OutputSelect({
<PopoverContent
ref={popoverRef}
side='bottom'
align='start'
align='end'
sideOffset={4}
maxHeight={280}
maxHeight={140}
maxWidth={140}
minWidth={140}
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}
>
<PopoverScrollArea className='space-y-[2px]'>
{Object.entries(groupedOutputs).map(([blockName, outputs]) => (
<div key={blockName}>
<PopoverSection>{blockName}</PopoverSection>
{outputs.map((output) => (
<PopoverItem
key={output.id}
active={isSelectedValue(output)}
onClick={() => handleOutputSelection(output.label)}
>
<div
className='flex h-[14px] w-[14px] flex-shrink-0 items-center justify-center rounded'
style={{
backgroundColor: getOutputColor(output.blockId, output.blockType),
}}

<div className='flex flex-col gap-[2px]'>
{outputs.map((output) => (
<PopoverItem
key={output.id}
active={isSelectedValue(output)}
onClick={() => handleOutputSelection(output.label)}
>
<span className='font-bold text-[10px] text-white'>
{blockName.charAt(0).toUpperCase()}
</span>
</div>
<span className='min-w-0 flex-1 truncate'>{output.path}</span>
{isSelectedValue(output) && <Check className='h-3 w-3 flex-shrink-0' />}
</PopoverItem>
))}
<div
className='flex h-[14px] w-[14px] flex-shrink-0 items-center justify-center rounded'
style={{
backgroundColor: getOutputColor(output.blockId, output.blockType),
}}
>
<span className='font-bold text-[10px] text-white'>
{blockName.charAt(0).toUpperCase()}
</span>
</div>
<span className='min-w-0 flex-1 truncate'>{output.path}</span>
{isSelectedValue(output) && <Check className='h-3 w-3 flex-shrink-0' />}
</PopoverItem>
))}
</div>
</div>
))}
</PopoverScrollArea>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { useOutputPanelResize, useTerminalFilters, useTerminalResize } from './h
*/
const MIN_HEIGHT = 30
const NEAR_MIN_THRESHOLD = 40
const DEFAULT_EXPANDED_HEIGHT = 300
const DEFAULT_EXPANDED_HEIGHT = 196

/**
* Column width constants - numeric values for calculations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useParams } from 'next/navigation'
import { Handle, type NodeProps, Position } from 'reactflow'
import { Handle, type NodeProps, Position, useUpdateNodeInternals } from 'reactflow'
import { Badge } from '@/components/emcn/components/badge/badge'
import { Tooltip } from '@/components/emcn/components/tooltip/tooltip'
import { getEnv, isTruthy } from '@/lib/env'
Expand Down Expand Up @@ -689,6 +689,16 @@ export const WorkflowBlock = memo(function WorkflowBlock({
],
})

/**
* Notify React Flow when handle orientation changes so it can recalculate edge paths.
* This is necessary because toggling handles doesn't change block dimensions,
* so useBlockDimensions won't trigger updateNodeInternals.
*/
const updateNodeInternals = useUpdateNodeInternals()
useEffect(() => {
updateNodeInternals(id)
}, [horizontalHandles, id, updateNodeInternals])

const showWebhookIndicator = (isStarterBlock || isWebhookTriggerBlock) && isWebhookConfigured
const shouldShowScheduleBadge =
type === 'schedule' && !isLoadingScheduleInfo && scheduleInfo !== null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ export function UsageIndicator({ onClick }: UsageIndicatorProps) {

if (isLoading) {
return (
<div className='flex flex-shrink-0 flex-col gap-[10px] border-t px-[13.5px] pt-[10px] pb-[8px] dark:border-[var(--border)]'>
<div className='flex flex-shrink-0 flex-col gap-[8px] border-t pt-[12px] pr-[13.5px] pb-[10px] pl-[12px] dark:border-[var(--border)]'>
{/* Top row skeleton */}
<div className='flex items-center justify-between'>
<Skeleton className='h-[16px] w-[120px] rounded-[4px]' />
<Skeleton className='h-[16px] w-[50px] rounded-[4px]' />
<div className='flex items-center gap-[6px]'>
<Skeleton className='h-[14px] w-[40px] rounded-[4px]' />
<Skeleton className='h-[14px] w-[70px] rounded-[4px]' />
</div>
<Skeleton className='h-[12px] w-[50px] rounded-[4px]' />
</div>

{/* Pills skeleton */}
Expand Down Expand Up @@ -121,25 +124,25 @@ export function UsageIndicator({ onClick }: UsageIndicatorProps) {
}

return (
<div className='flex flex-shrink-0 flex-col gap-[10px] border-t px-[13.5px] pt-[8px] pb-[8px] dark:border-[var(--border)]'>
<div className='flex flex-shrink-0 flex-col gap-[8px] border-t px-[13.5px] pt-[8px] pb-[10px] dark:border-[var(--border)]'>
{/* Top row */}
<div className='flex items-center justify-between'>
<div className='flex items-center gap-[6px]'>
<span className='font-medium text-[#FFFFFF] text-[12px]'>{PLAN_NAMES[planType]}</span>
<div className='h-[14px] w-[1.5px] bg-[#4A4A4A]' />
<div className='h-[14px] w-[1.5px] bg-[var(--divider)]' />
<div className='flex items-center gap-[4px]'>
{isBlocked ? (
<>
<span className='font-medium text-[#B1B1B1] text-[12px]'>Over</span>
<span className='font-medium text-[#B1B1B1] text-[12px]'>limit</span>
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>Over</span>
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>limit</span>
</>
) : (
<>
<span className='font-medium text-[#B1B1B1] text-[12px] tabular-nums'>
<span className='font-medium text-[12px] text-[var(--text-tertiary)] tabular-nums'>
${usage.current.toFixed(2)}
</span>
<span className='font-medium text-[#B1B1B1] text-[12px]'>/</span>
<span className='font-medium text-[#B1B1B1] text-[12px] tabular-nums'>
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>/</span>
<span className='font-medium text-[12px] text-[var(--text-tertiary)] tabular-nums'>
${usage.limit}
</span>
</>
Expand All @@ -149,7 +152,7 @@ export function UsageIndicator({ onClick }: UsageIndicatorProps) {
{showUpgradeButton && (
<Button
variant='ghost'
className='!h-auto !px-1 !py-0 -mx-1 mt-[-2px] text-[#D4D4D4]'
className='!h-auto !px-1 !py-0 -mx-1 mt-[-2px] text-[var(--text-secondary)]'
onClick={handleClick}
>
Upgrade
Expand Down
40 changes: 31 additions & 9 deletions apps/sim/components/emcn/components/popover/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,15 @@ export interface PopoverContentProps
* Maximum height for the popover content in pixels
*/
maxHeight?: number
/**
* Maximum width for the popover content in pixels.
* When provided, Popover will also enable default truncation for inner text and section headers.
*/
maxWidth?: number
/**
* Minimum width for the popover content in pixels
*/
minWidth?: number
/**
* Preferred side to display the popover
* @default 'bottom'
Expand Down Expand Up @@ -249,6 +258,8 @@ const PopoverContent = React.forwardRef<
style,
children,
maxHeight,
maxWidth,
minWidth,
side = 'bottom',
align = 'start',
sideOffset,
Expand All @@ -264,7 +275,11 @@ const PopoverContent = React.forwardRef<
// When present, we enable default text truncation behavior for inner flexible items,
// so callers don't need to manually pass 'truncate' to every label.
const hasUserWidthConstraint =
style?.minWidth !== undefined || style?.maxWidth !== undefined || style?.width !== undefined
maxWidth !== undefined ||
minWidth !== undefined ||
style?.minWidth !== undefined ||
style?.maxWidth !== undefined ||
style?.width !== undefined

return (
<PopoverPrimitive.Portal>
Expand All @@ -278,15 +293,21 @@ const PopoverContent = React.forwardRef<
sticky='partial'
{...restProps}
className={cn(
'z-[10000001] flex flex-col overflow-hidden rounded-[8px] bg-[var(--surface-3)] px-[5.5px] py-[5px] text-foreground outline-none dark:bg-[var(--surface-3)]',
// If width is constrained by the caller, ensure inner flexible text truncates by default.
hasUserWidthConstraint && '[&_.flex-1]:truncate',
className
'z-[10000001] flex flex-col overflow-auto rounded-[8px] bg-[var(--surface-3)] px-[5.5px] py-[5px] text-foreground outline-none dark:bg-[var(--surface-3)]',
// If width is constrained by the caller (prop or style), ensure inner flexible text truncates by default,
// and also truncate section headers.
hasUserWidthConstraint && '[&_.flex-1]:truncate [&_[data-popover-section]]:truncate',
)}
style={{
maxHeight: `${maxHeight || 400}px`,
maxWidth: 'calc(100vw - 16px)',
minWidth: '160px',
maxWidth: maxWidth !== undefined ? `${maxWidth}px` : 'calc(100vw - 16px)',
// Only enforce default min width when the user hasn't set width constraints
minWidth:
minWidth !== undefined
? `${minWidth}px`
: hasUserWidthConstraint
? undefined
: '160px',
...style,
}}
>
Expand Down Expand Up @@ -319,7 +340,7 @@ const PopoverScrollArea = React.forwardRef<HTMLDivElement, PopoverScrollAreaProp
({ className, ...props }, ref) => {
return (
<div
className={cn('min-h-0 flex-1 overflow-auto overscroll-contain', className)}
className={cn('min-h-0 overflow-auto overscroll-contain', className)}
ref={ref}
{...props}
/>
Expand Down Expand Up @@ -415,9 +436,10 @@ const PopoverSection = React.forwardRef<HTMLDivElement, PopoverSectionProps>(
return (
<div
className={cn(
'px-[6px] py-[4px] font-base text-[12px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]',
'min-w-0 px-[6px] py-[4px] font-base text-[12px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]',
className
)}
data-popover-section=''
ref={ref}
{...props}
/>
Expand Down
18 changes: 4 additions & 14 deletions apps/sim/stores/chat/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,21 @@ interface ChatState {
}

/**
* Calculate default center position based on available canvas space
* Calculate default position in top right of canvas, 32px from top and right of panel
*/
const calculateDefaultPosition = (): ChatPosition => {
if (typeof window === 'undefined') {
return { x: 100, y: 100 }
}

// Get current layout dimensions
const sidebarWidth = Number.parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--sidebar-width') || '0'
)
const panelWidth = Number.parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--panel-width') || '0'
)
const terminalHeight = Number.parseInt(
getComputedStyle(document.documentElement).getPropertyValue('--terminal-height') || '0'
)

// Calculate available space
const availableWidth = window.innerWidth - sidebarWidth - panelWidth
const availableHeight = window.innerHeight - terminalHeight

// Center in available space
const x = sidebarWidth + (availableWidth - DEFAULT_WIDTH) / 2
const y = (availableHeight - DEFAULT_HEIGHT) / 2
// Position in top right of canvas, 32px from top and 32px from right of panel
const x = window.innerWidth - panelWidth - 32 - DEFAULT_WIDTH
const y = 32

return { x, y }
}
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/stores/terminal/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface TerminalState {
* Note: Maximum height is enforced dynamically at 70% of viewport height in the resize hook
*/
const MIN_TERMINAL_HEIGHT = 30
export const DEFAULT_TERMINAL_HEIGHT = 145
export const DEFAULT_TERMINAL_HEIGHT = 196

/**
* Output panel width constraints
Expand Down
Loading