Skip to content

Commit 90fa6cc

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
improvement(ui): share field mode toggles
1 parent 85d3acd commit 90fa6cc

5 files changed

Lines changed: 81 additions & 124 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { ButtonHTMLAttributes } from 'react'
2+
import { cn, Tooltip } from '@sim/emcn'
3+
import { ArrowLeftRight } from '@sim/emcn/icons'
4+
5+
interface FieldModeToggleProps {
6+
label: string
7+
active: boolean
8+
disabled?: boolean
9+
onClick: ButtonHTMLAttributes<HTMLButtonElement>['onClick']
10+
}
11+
12+
/** Shared field-mode affordance; the caller owns the mode and its stored values. */
13+
export function FieldModeToggle({ label, active, disabled, onClick }: FieldModeToggleProps) {
14+
return (
15+
<Tooltip.Root>
16+
<Tooltip.Trigger asChild>
17+
<button
18+
type='button'
19+
className='flex size-[12px] shrink-0 items-center justify-center bg-transparent p-0 focus-visible:ring-2 focus-visible:ring-[color-mix(in_srgb,var(--text-muted)_30%,transparent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--surface-2)] disabled:cursor-not-allowed disabled:opacity-50'
20+
onClick={onClick}
21+
disabled={disabled}
22+
aria-label={label}
23+
>
24+
<ArrowLeftRight
25+
className={cn(
26+
'size-[12px]!',
27+
active ? 'text-[var(--text-primary)]' : 'text-[var(--text-secondary)]'
28+
)}
29+
/>
30+
</button>
31+
</Tooltip.Trigger>
32+
<Tooltip.Content side='top'>
33+
<p>{label}</p>
34+
</Tooltip.Content>
35+
</Tooltip.Root>
36+
)
37+
}

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

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import {
1414
Label,
1515
languages,
1616
OverflowText,
17-
Tooltip,
1817
} from '@sim/emcn'
19-
import { ArrowLeftRight, Plus, Trash } from '@sim/emcn/icons'
18+
import { Plus, Trash } from '@sim/emcn/icons'
2019
import Editor from 'react-simple-code-editor'
2120
import {
2221
createDefaultInputFormatField,
2322
isFileFieldType,
2423
parseInputFormatFiles,
2524
} from '@/lib/workflows/input-format'
25+
import { FieldModeToggle } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/field-mode-toggle/field-mode-toggle'
2626
import { FileUpload } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/file-upload/file-upload'
2727
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
2828
import {
@@ -166,32 +166,17 @@ export function FieldFormat({
166166
if (!canUseUploader) return null
167167
const label = mode === 'upload' ? 'Switch to JSON' : 'Switch to file uploader'
168168
return (
169-
<Tooltip.Root>
170-
<Tooltip.Trigger asChild>
171-
<button
172-
type='button'
173-
className='flex size-[12px] shrink-0 items-center justify-center bg-transparent p-0 disabled:cursor-not-allowed disabled:opacity-50'
174-
onClick={() =>
175-
setFileFieldModes((prev) => ({
176-
...prev,
177-
[field.id]: mode === 'upload' ? 'json' : 'upload',
178-
}))
179-
}
180-
disabled={isReadOnly}
181-
aria-label={label}
182-
>
183-
<ArrowLeftRight
184-
className={cn(
185-
'h-[12px]! w-[12px]!',
186-
mode === 'json' ? 'text-[var(--text-primary)]' : 'text-[var(--text-secondary)]'
187-
)}
188-
/>
189-
</button>
190-
</Tooltip.Trigger>
191-
<Tooltip.Content side='top'>
192-
<p>{label}</p>
193-
</Tooltip.Content>
194-
</Tooltip.Root>
169+
<FieldModeToggle
170+
active={mode === 'json'}
171+
label={label}
172+
disabled={isReadOnly}
173+
onClick={() =>
174+
setFileFieldModes((prev) => ({
175+
...prev,
176+
[field.id]: mode === 'upload' ? 'json' : 'upload',
177+
}))
178+
}
179+
/>
195180
)
196181
}
197182

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tool-input/components/tools/usage-control.tsx

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Combobox, cn, Label, Tooltip } from '@sim/emcn'
2-
import { ArrowLeftRight } from '@sim/emcn/icons'
1+
import { Combobox, Label } from '@sim/emcn'
32
import type { CanonicalMode } from '@/lib/workflows/subblocks/visibility'
43
import type { StoredTool } from '@/lib/workflows/tool-input/types'
4+
import { FieldModeToggle } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/field-mode-toggle/field-mode-toggle'
55
import { ShortInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/short-input'
66
import type { SubBlockConfig } from '@/blocks/types'
77

@@ -63,29 +63,12 @@ export function ToolUsageControl({
6363
<div className='flex items-center justify-between gap-1.5 pl-0.5'>
6464
<Label className='flex items-baseline gap-1.5 whitespace-nowrap'>Permission Mode</Label>
6565
<div className='flex min-w-0 flex-1 items-center justify-end gap-1.5'>
66-
<Tooltip.Root>
67-
<Tooltip.Trigger asChild>
68-
<button
69-
type='button'
70-
className='flex size-[12px] shrink-0 items-center justify-center bg-transparent p-0 disabled:cursor-not-allowed disabled:opacity-50'
71-
onClick={onModeToggle}
72-
disabled={disabled}
73-
aria-label={toggleLabel}
74-
>
75-
<ArrowLeftRight
76-
className={cn(
77-
'size-[12px]!',
78-
mode === 'advanced'
79-
? 'text-[var(--text-primary)]'
80-
: 'text-[var(--text-secondary)]'
81-
)}
82-
/>
83-
</button>
84-
</Tooltip.Trigger>
85-
<Tooltip.Content side='top'>
86-
<p>{toggleLabel}</p>
87-
</Tooltip.Content>
88-
</Tooltip.Root>
66+
<FieldModeToggle
67+
active={mode === 'advanced'}
68+
label={toggleLabel}
69+
onClick={onModeToggle}
70+
disabled={disabled}
71+
/>
8972
</div>
9073
</div>
9174
{mode === 'advanced' ? (

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

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import {
1010
Label,
1111
OverflowText,
1212
Textarea,
13-
Tooltip,
1413
} from '@sim/emcn'
15-
import { ArrowLeftRight, Plus, Trash } from '@sim/emcn/icons'
14+
import { Plus, Trash } from '@sim/emcn/icons'
1615
import { generateId } from '@sim/utils/id'
1716
import { useParams } from 'next/navigation'
17+
import { FieldModeToggle } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/field-mode-toggle/field-mode-toggle'
1818
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
1919
import {
2020
checkTagTrigger,
@@ -472,36 +472,17 @@ export function VariablesInput({
472472
<div className='flex items-center justify-between'>
473473
<Label className='text-small'>Value</Label>
474474
{assignment.type === 'boolean' && (
475-
<Tooltip.Root>
476-
<Tooltip.Trigger asChild>
477-
<button
478-
type='button'
479-
className='flex size-[12px] shrink-0 items-center justify-center bg-transparent p-0 disabled:cursor-not-allowed disabled:opacity-50'
480-
onClick={() =>
481-
setManualBooleanModes((prev) => ({
482-
...prev,
483-
[assignment.id]: !isManualBoolean,
484-
}))
485-
}
486-
disabled={isReadOnly}
487-
aria-label={
488-
isManualBoolean ? 'Switch to selector' : 'Switch to manual value'
489-
}
490-
>
491-
<ArrowLeftRight
492-
className={cn(
493-
'h-[12px]! w-[12px]!',
494-
isManualBoolean
495-
? 'text-[var(--text-primary)]'
496-
: 'text-[var(--text-secondary)]'
497-
)}
498-
/>
499-
</button>
500-
</Tooltip.Trigger>
501-
<Tooltip.Content side='top'>
502-
<p>{isManualBoolean ? 'Switch to selector' : 'Switch to manual value'}</p>
503-
</Tooltip.Content>
504-
</Tooltip.Root>
475+
<FieldModeToggle
476+
active={isManualBoolean}
477+
label={isManualBoolean ? 'Switch to selector' : 'Switch to manual value'}
478+
disabled={isReadOnly}
479+
onClick={() =>
480+
setManualBooleanModes((prev) => ({
481+
...prev,
482+
[assignment.id]: !isManualBoolean,
483+
}))
484+
}
485+
/>
505486
)}
506487
</div>
507488
{assignment.type === 'boolean' && !isManualBoolean ? (

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

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import { type JSX, type MouseEvent, memo, useCallback, useMemo, useRef, useState } from 'react'
22
import { Button, cn, Input, Label, Tooltip } from '@sim/emcn'
3-
import {
4-
ArrowLeftRight,
5-
ArrowUp,
6-
Check,
7-
Clipboard,
8-
SquareArrowUpRight,
9-
TriangleAlert,
10-
} from '@sim/emcn/icons'
3+
import { ArrowUp, Check, Clipboard, SquareArrowUpRight, TriangleAlert } from '@sim/emcn/icons'
114
import { isEqual } from 'es-toolkit'
125
import { useParams } from 'next/navigation'
136
import type { FilterRule, SortRule } from '@/lib/table/query-builder/constants'
@@ -54,6 +47,7 @@ import {
5447
WorkflowSelectorInput,
5548
WorkspaceFolderSelector,
5649
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components'
50+
import { FieldModeToggle } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/field-mode-toggle/field-mode-toggle'
5751
import { MODAL_REGISTRY } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/modal-registry'
5852
import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate'
5953
import type { SubBlockConfig } from '@/blocks/types'
@@ -377,37 +371,14 @@ const renderLabel = (
377371
</Tooltip.Root>
378372
)}
379373
{showCanonicalToggle && (
380-
<Tooltip.Root>
381-
<Tooltip.Trigger asChild>
382-
<button
383-
type='button'
384-
className='flex size-[12px] shrink-0 items-center justify-center bg-transparent p-0 disabled:cursor-not-allowed disabled:opacity-50'
385-
onClick={canonicalToggle?.onToggle}
386-
disabled={canonicalToggleDisabledResolved}
387-
aria-label={
388-
canonicalToggle?.mode === 'advanced'
389-
? 'Switch to selector'
390-
: 'Switch to manual ID'
391-
}
392-
>
393-
<ArrowLeftRight
394-
className={cn(
395-
'h-[12px]! w-[12px]!',
396-
canonicalToggle?.mode === 'advanced'
397-
? 'text-[var(--text-primary)]'
398-
: 'text-[var(--text-secondary)]'
399-
)}
400-
/>
401-
</button>
402-
</Tooltip.Trigger>
403-
<Tooltip.Content side='top'>
404-
<p>
405-
{canonicalToggle?.mode === 'advanced'
406-
? 'Switch to selector'
407-
: 'Switch to manual ID'}
408-
</p>
409-
</Tooltip.Content>
410-
</Tooltip.Root>
374+
<FieldModeToggle
375+
active={canonicalToggle?.mode === 'advanced'}
376+
label={
377+
canonicalToggle?.mode === 'advanced' ? 'Switch to selector' : 'Switch to manual ID'
378+
}
379+
disabled={canonicalToggleDisabledResolved}
380+
onClick={canonicalToggle?.onToggle}
381+
/>
411382
)}
412383
</div>
413384
</div>

0 commit comments

Comments
 (0)