Skip to content

Commit bd1fff7

Browse files
BillLeoutsakosvl346Bill Leoutsakos
andauthored
refactor(ui): share static API and MCP parameter cards (#8027)
* refactor(ui): share static API and MCP parameter cards * fix(ui): preserve specialized tiny action geometry * improvement(ui): reuse collapsible cards for MCP tools (#8170) Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local> --------- Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local>
1 parent c0b7e9e commit bd1fff7

20 files changed

Lines changed: 397 additions & 344 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/settings/components/mcp/mcp.tsx‎

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
'use client'
22

33
import { useEffect, useRef, useState } from 'react'
4-
import { Badge, Button, Chip, ChipConfirmModal, cn, Tooltip, toast } from '@sim/emcn'
4+
import {
5+
Badge,
6+
Chip,
7+
ChipConfirmModal,
8+
CollapsibleCard,
9+
cn,
10+
OverflowText,
11+
Tooltip,
12+
toast,
13+
} from '@sim/emcn'
514
import { ArrowLeft, ChevronDown, Plus } from '@sim/emcn/icons'
615
import { createLogger } from '@sim/logger'
716
import { getErrorMessage } from '@sim/utils/errors'
@@ -535,59 +544,53 @@ export function MCP() {
535544
const requiredParams = tool.inputSchema?.required || []
536545

537546
return (
538-
<div
547+
<CollapsibleCard
539548
key={tool.name}
540-
className='overflow-hidden rounded-md border border-[var(--border-1)] bg-[var(--surface-3)]'
541-
>
542-
<Button
543-
type='button'
544-
variant='ghost'
545-
onClick={() => hasParams && toggleToolExpanded(tool.name)}
546-
className={cn(
547-
'flex h-auto w-full items-start justify-between rounded-none px-2.5 py-2 text-left text-sm',
548-
hasParams && 'cursor-pointer hover-hover:bg-[var(--surface-4)]'
549-
)}
550-
disabled={!hasParams}
551-
>
552-
<div className='flex-1'>
553-
<div className='flex h-[16px] items-center gap-1.5'>
554-
<p className='text-[var(--text-primary)] text-sm leading-none'>
555-
{tool.name}
556-
</p>
557-
{issues.length > 0 && (
558-
<Tooltip.Root>
559-
<Tooltip.Trigger asChild>
560-
<div className='flex items-center'>
561-
<Badge variant={getIssueBadgeVariant(issues[0].issue)} size='sm'>
562-
{getIssueBadgeLabel(issues[0].issue)}
563-
</Badge>
564-
</div>
565-
</Tooltip.Trigger>
566-
<Tooltip.Content>
567-
Update in: {affectedWorkflows.join(', ')}
568-
</Tooltip.Content>
569-
</Tooltip.Root>
570-
)}
571-
</div>
549+
collapsed={!isExpanded || !hasParams}
550+
disabled={!hasParams}
551+
onToggleCollapse={() => toggleToolExpanded(tool.name)}
552+
title={
553+
<>
554+
<OverflowText
555+
label={tool.name}
556+
className='text-[var(--text-primary)]'
557+
focusTarget='nearest-interactive'
558+
/>
572559
{tool.description && (
573-
<p className='mt-1 text-[var(--text-tertiary)] text-sm'>
574-
{tool.description}
575-
</p>
560+
<span className='mt-1 block whitespace-normal'>{tool.description}</span>
576561
)}
577-
</div>
578-
{hasParams && (
579-
<ChevronDown
580-
className={cn(
581-
'mt-0.5 size-[14px] shrink-0 text-[var(--text-muted)] transition-transform duration-200',
582-
isExpanded && 'rotate-180'
583-
)}
584-
/>
585-
)}
586-
</Button>
587-
562+
</>
563+
}
564+
badge={
565+
<>
566+
{issues.length > 0 && (
567+
<Tooltip.Root>
568+
<Tooltip.Trigger asChild>
569+
<span className='flex shrink-0 items-center'>
570+
<Badge variant={getIssueBadgeVariant(issues[0].issue)} size='sm'>
571+
{getIssueBadgeLabel(issues[0].issue)}
572+
</Badge>
573+
</span>
574+
</Tooltip.Trigger>
575+
<Tooltip.Content>
576+
Update in: {affectedWorkflows.join(', ')}
577+
</Tooltip.Content>
578+
</Tooltip.Root>
579+
)}
580+
{hasParams && (
581+
<ChevronDown
582+
className={cn(
583+
'size-[14px] shrink-0 text-[var(--text-muted)] transition-transform duration-200',
584+
isExpanded && 'rotate-180'
585+
)}
586+
/>
587+
)}
588+
</>
589+
}
590+
>
588591
{isExpanded && hasParams && (
589-
<div className='border-[var(--border-1)] border-t bg-[var(--surface-2)] px-2.5 py-2'>
590-
<p className='mb-1.5 text-[var(--text-muted)] text-caption uppercase tracking-wide'>
592+
<>
593+
<p className='text-[var(--text-muted)] text-caption uppercase tracking-wide'>
591594
Parameters
592595
</p>
593596
<div className='flex flex-col gap-1.5'>
@@ -631,9 +634,9 @@ export function MCP() {
631634
}
632635
)}
633636
</div>
634-
</div>
637+
</>
635638
)}
636-
</div>
639+
</CollapsibleCard>
637640
)
638641
})}
639642
</div>

‎apps/sim/app/workspace/[workspaceId]/settings/components/workflow-mcp-servers/workflow-mcp-servers.tsx‎

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
ChipSelect,
1919
Code,
2020
type ComboboxOption,
21+
FieldCard,
2122
Label,
2223
useCopyToClipboard,
2324
} from '@sim/emcn'
@@ -713,36 +714,29 @@ function ServerDetailView({
713714
return hasParams ? (
714715
<div className='flex flex-col gap-2'>
715716
{Object.entries(properties).map(([name, prop]) => (
716-
<div
717+
<FieldCard
717718
key={name}
718-
className='overflow-hidden rounded-sm border border-[var(--border-1)]'
719+
title={name}
720+
badge={
721+
<Badge variant='type' size='sm'>
722+
{prop.type || 'any'}
723+
</Badge>
724+
}
719725
>
720-
<div className='flex items-center justify-between bg-[var(--surface-4)] px-2.5 py-[5px]'>
721-
<div className='flex min-w-0 flex-1 items-center gap-2'>
722-
<span className='block truncate text-[var(--text-tertiary)] text-base'>
723-
{name}
724-
</span>
725-
<Badge variant='type' size='sm'>
726-
{prop.type || 'any'}
727-
</Badge>
728-
</div>
729-
</div>
730-
<div className='rounded-b-[4px] border-[var(--border-1)] border-t bg-[var(--surface-2)] px-2.5 pt-1.5 pb-2.5'>
731-
<div className='flex flex-col gap-1.5'>
732-
<Label>Description</Label>
733-
<ChipInput
734-
value={editingParameterDescriptions[name] || ''}
735-
onChange={(e) =>
736-
setEditingParameterDescriptions((prev) => ({
737-
...prev,
738-
[name]: e.target.value,
739-
}))
740-
}
741-
placeholder={`Enter description for ${name}`}
742-
/>
743-
</div>
726+
<div className='flex flex-col gap-1.5'>
727+
<Label>Description</Label>
728+
<ChipInput
729+
value={editingParameterDescriptions[name] || ''}
730+
onChange={(e) =>
731+
setEditingParameterDescriptions((prev) => ({
732+
...prev,
733+
[name]: e.target.value,
734+
}))
735+
}
736+
placeholder={`Enter description for ${name}`}
737+
/>
744738
</div>
745-
</div>
739+
</FieldCard>
746740
))}
747741
</div>
748742
) : (

‎apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/data-row.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ export const DataRow = React.memo(function DataRow({
287287
{hasWorkflowColumns && (
288288
<Button
289289
type='button'
290-
variant='ghost'
291-
size='sm'
290+
variant='quiet'
291+
size='icon'
292292
aria-label={runningCount > 0 ? `Stop ${runningCount} running` : 'Run row'}
293293
title={runningCount > 0 ? `Stop ${runningCount} running` : 'Run row'}
294-
className='size-[20px] shrink-0 p-0 text-[var(--text-primary)] hover-hover:bg-[var(--surface-2)]'
294+
className='shrink-0'
295295
onClick={() => {
296296
if (runningCount > 0) {
297297
onStopRow(row.id)

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/components/api-info-modal.tsx‎

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
ChipModalField,
1414
ChipModalFooter,
1515
ChipModalHeader,
16+
FieldCard,
1617
Label,
1718
} from '@sim/emcn'
1819
import { getErrorMessage } from '@sim/utils/errors'
@@ -237,31 +238,24 @@ export function ApiInfoModal({ open, onOpenChange, workflowId }: ApiInfoModalPro
237238
<ChipModalField type='custom' title={`Parameters (${inputFormat.length})`}>
238239
<div className='flex flex-col gap-2'>
239240
{inputFormat.map((field) => (
240-
<div
241+
<FieldCard
241242
key={field.name}
242-
className='overflow-hidden rounded-sm border border-[var(--border-1)]'
243+
title={field.name}
244+
badge={
245+
<Badge variant='type' size='sm'>
246+
{field.type || 'string'}
247+
</Badge>
248+
}
243249
>
244-
<div className='flex items-center justify-between bg-[var(--surface-4)] px-2.5 py-[5px]'>
245-
<div className='flex min-w-0 flex-1 items-center gap-2'>
246-
<span className='block truncate text-[var(--text-tertiary)] text-sm'>
247-
{field.name}
248-
</span>
249-
<Badge variant='type' size='sm'>
250-
{field.type || 'string'}
251-
</Badge>
252-
</div>
250+
<div className='flex flex-col gap-1.5'>
251+
<Label className='text-small'>Description</Label>
252+
<ChipInput
253+
value={paramDescriptions[field.name] || ''}
254+
onChange={(e) => handleParamDescriptionChange(field.name, e.target.value)}
255+
placeholder={`Enter description for ${field.name}`}
256+
/>
253257
</div>
254-
<div className='rounded-b-[4px] border-[var(--border-1)] border-t bg-[var(--surface-2)] px-2.5 pt-1.5 pb-2.5'>
255-
<div className='flex flex-col gap-1.5'>
256-
<Label className='text-small'>Description</Label>
257-
<ChipInput
258-
value={paramDescriptions[field.name] || ''}
259-
onChange={(e) => handleParamDescriptionChange(field.name, e.target.value)}
260-
placeholder={`Enter description for ${field.name}`}
261-
/>
262-
</div>
263-
</div>
264-
</div>
258+
</FieldCard>
265259
))}
266260
</div>
267261
</ChipModalField>

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx‎

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
ChipInput,
99
ChipModalField,
1010
type ComboboxOption,
11+
FieldCard,
1112
Skeleton,
1213
} from '@sim/emcn'
1314
import { createLogger } from '@sim/logger'
@@ -578,38 +579,31 @@ export function McpDeploy({
578579
</p>
579580
<div className='flex flex-col gap-2'>
580581
{inputFormat.map((field) => (
581-
<div
582+
<FieldCard
582583
key={field.name}
583-
className='overflow-hidden rounded-sm border border-[var(--border-1)]'
584+
title={field.name}
585+
badge={
586+
<Badge variant='type' size='sm'>
587+
{field.type}
588+
</Badge>
589+
}
584590
>
585-
<div className='flex items-center justify-between bg-[var(--surface-4)] px-2.5 py-[5px]'>
586-
<div className='flex min-w-0 flex-1 items-center gap-2'>
587-
<span className='block truncate text-[var(--text-tertiary)] text-sm'>
588-
{field.name}
589-
</span>
590-
<Badge variant='type' size='sm'>
591-
{field.type}
592-
</Badge>
593-
</div>
594-
</div>
595-
<div className='rounded-b-[4px] border-[var(--border-1)] border-t bg-[var(--surface-2)] px-2.5 pt-1.5 pb-2.5'>
596-
<ChipModalField
597-
type='input'
598-
title='Description'
599-
flush
600-
value={
601-
parameterDescriptions[field.name] ?? startBlockDescriptions[field.name] ?? ''
602-
}
603-
onChange={(value) =>
604-
setParameterDescriptions((prev) => ({
605-
...prev,
606-
[field.name]: value,
607-
}))
608-
}
609-
placeholder={startBlockDescriptions[field.name] || `Describe ${field.name}`}
610-
/>
611-
</div>
612-
</div>
591+
<ChipModalField
592+
type='input'
593+
title='Description'
594+
flush
595+
value={
596+
parameterDescriptions[field.name] ?? startBlockDescriptions[field.name] ?? ''
597+
}
598+
onChange={(value) =>
599+
setParameterDescriptions((prev) => ({
600+
...prev,
601+
[field.name]: value,
602+
}))
603+
}
604+
placeholder={startBlockDescriptions[field.name] || `Describe ${field.name}`}
605+
/>
606+
</FieldCard>
613607
))}
614608
</div>
615609
</ChipModalField>

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/condition-input/condition-input.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ export function ConditionInput({
966966
disabled ||
967967
(!isRouterMode && isElseConditionTitle(block.title))
968968
}
969-
className='h-auto p-0'
969+
size='icon'
970970
>
971971
<Plus className='size-[14px]' />
972972
<span className='sr-only'>Add Block</span>
@@ -986,7 +986,7 @@ export function ConditionInput({
986986
disabled ||
987987
(!isRouterMode && isElseConditionTitle(block.title))
988988
}
989-
className='h-auto p-0'
989+
size='icon'
990990
>
991991
<ChevronUp className='size-[14px]' />
992992
<span className='sr-only'>Move Up</span>
@@ -1008,7 +1008,7 @@ export function ConditionInput({
10081008
isElseConditionTitle(conditionalBlocks[index + 1]?.title)) ||
10091009
(!isRouterMode && isElseConditionTitle(block.title))
10101010
}
1011-
className='h-auto p-0'
1011+
size='icon'
10121012
>
10131013
<ChevronDown className='size-[14px]' />
10141014
<span className='sr-only'>Move Down</span>
@@ -1025,7 +1025,7 @@ export function ConditionInput({
10251025
disabled={
10261026
isPreview || disabled || conditionalBlocks.length <= (isRouterMode ? 1 : 2)
10271027
}
1028-
className='h-auto p-0'
1028+
size='icon'
10291029
>
10301030
<Trash className='size-[14px]' />
10311031
<span className='sr-only'>Delete Block</span>

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/document-tag-entry/document-tag-entry.tsx‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,20 +257,15 @@ export function DocumentTagEntry({
257257

258258
const renderActions = (tag: DocumentTag) => (
259259
<>
260-
<Button
261-
variant='ghost'
262-
onClick={addTag}
263-
disabled={isReadOnly || !canAddMoreTags}
264-
className='h-auto p-0'
265-
>
260+
<Button variant='ghost' onClick={addTag} disabled={isReadOnly || !canAddMoreTags} size='icon'>
266261
<Plus className='size-[14px]' />
267262
<span className='sr-only'>Add Tag</span>
268263
</Button>
269264
<Button
270265
variant='ghost-destructive'
271266
onClick={() => removeTag(tag.id)}
272267
disabled={isReadOnly}
273-
className='h-auto p-0'
268+
size='icon'
274269
>
275270
<Trash className='size-[14px]' />
276271
<span className='sr-only'>Delete Tag</span>

0 commit comments

Comments
 (0)