Skip to content

Commit a1ee666

Browse files
chore: fix conflicts
1 parent 90971fb commit a1ee666

17 files changed

Lines changed: 998 additions & 227 deletions

File tree

apps/sim/app/_styles/globals.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,3 +991,7 @@ input[type="search"]::-ms-clear {
991991
.react-flow__node[data-parent-node-id] .react-flow__handle {
992992
z-index: 30;
993993
}
994+
995+
.react-flow__panel {
996+
margin: 0 !important;
997+
}

apps/sim/app/workspace/[workspaceId]/settings/components/credentials/credentials-manager.tsx

Lines changed: 135 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { Check, Clipboard, Key, Search } from 'lucide-react'
5+
import { Check, Clipboard, Info, Key, Search, Shield, UserPlus } from 'lucide-react'
66
import { useParams, useRouter } from 'next/navigation'
77
import {
88
Avatar,
@@ -1188,44 +1188,78 @@ export function CredentialsManager() {
11881188
</div>
11891189
)}
11901190

1191-
<div className='flex flex-col gap-1.5 border-[var(--border)] border-t pt-4'>
1192-
<Label>Members ({activeMembers.length})</Label>
1191+
<div className='flex flex-col gap-0 overflow-hidden rounded-lg border border-[var(--border)]'>
1192+
{/* Header */}
1193+
<div className='flex items-start gap-3 border-b border-[var(--border)] bg-[var(--surface-1)] px-4 py-3'>
1194+
<div className='flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md bg-[var(--surface-4)]'>
1195+
<Shield className='h-4 w-4 text-[var(--text-secondary)]' />
1196+
</div>
1197+
<div className='min-w-0 flex-1'>
1198+
<div className='flex items-center gap-2'>
1199+
<p className='font-medium text-[var(--text-primary)] text-sm'>
1200+
Access Control
1201+
</p>
1202+
<Badge variant='gray-secondary' size='sm'>
1203+
{activeMembers.length} {activeMembers.length === 1 ? 'member' : 'members'}
1204+
</Badge>
1205+
</div>
1206+
<p className='mt-0.5 text-[var(--text-tertiary)] text-caption'>
1207+
Only workspace members listed below can view and use this secret in their
1208+
workflows. Admins can manage access; members can only use the secret.
1209+
</p>
1210+
</div>
1211+
</div>
11931212

1213+
{/* Member list */}
11941214
{membersLoading ? (
1195-
<div className='flex flex-col gap-2'>
1196-
<Skeleton className='h-[44px] w-full rounded-lg' />
1197-
<Skeleton className='h-[44px] w-full rounded-lg' />
1215+
<div className='flex flex-col gap-0 px-4'>
1216+
<div className='flex items-center gap-3 py-3'>
1217+
<Skeleton className='h-8 w-8 rounded-full' />
1218+
<div className='flex-1'>
1219+
<Skeleton className='mb-1 h-3.5 w-[120px]' />
1220+
<Skeleton className='h-3 w-[180px]' />
1221+
</div>
1222+
<Skeleton className='h-7 w-[80px] rounded-md' />
1223+
</div>
1224+
<div className='flex items-center gap-3 border-t border-[var(--border)] py-3'>
1225+
<Skeleton className='h-8 w-8 rounded-full' />
1226+
<div className='flex-1'>
1227+
<Skeleton className='mb-1 h-3.5 w-[100px]' />
1228+
<Skeleton className='h-3 w-[160px]' />
1229+
</div>
1230+
<Skeleton className='h-7 w-[80px] rounded-md' />
1231+
</div>
11981232
</div>
11991233
) : (
1200-
<div className='flex flex-col gap-2'>
1201-
{activeMembers.map((member) => (
1234+
<div className='flex flex-col'>
1235+
{activeMembers.map((member, index) => (
12021236
<div
12031237
key={member.id}
1204-
className='grid grid-cols-[1fr_120px_72px] items-center gap-2'
1238+
className={`flex items-center gap-3 px-4 py-2.5 ${
1239+
index > 0 ? 'border-t border-[var(--border)]' : ''
1240+
}`}
12051241
>
1206-
<div className='flex min-w-0 items-center gap-2.5'>
1207-
<Avatar className='h-8 w-8 flex-shrink-0'>
1208-
<AvatarFallback
1209-
style={{
1210-
background: getUserColor(member.userId || member.userEmail || ''),
1211-
}}
1212-
className='border-0 text-small text-white'
1213-
>
1214-
{(member.userName || member.userEmail || '?').charAt(0).toUpperCase()}
1215-
</AvatarFallback>
1216-
</Avatar>
1217-
<div className='min-w-0'>
1218-
<p className='truncate font-medium text-[var(--text-primary)] text-sm'>
1219-
{member.userName || member.userEmail || member.userId}
1220-
</p>
1221-
<p className='truncate text-[var(--text-tertiary)] text-caption'>
1222-
{member.userEmail || member.userId}
1223-
</p>
1224-
</div>
1242+
<Avatar className='h-8 w-8 flex-shrink-0'>
1243+
<AvatarFallback
1244+
style={{
1245+
background: getUserColor(member.userId || member.userEmail || ''),
1246+
}}
1247+
className='border-0 text-small text-white'
1248+
>
1249+
{(member.userName || member.userEmail || '?').charAt(0).toUpperCase()}
1250+
</AvatarFallback>
1251+
</Avatar>
1252+
<div className='min-w-0 flex-1'>
1253+
<p className='truncate font-medium text-[var(--text-primary)] text-sm'>
1254+
{member.userName || member.userEmail || member.userId}
1255+
</p>
1256+
<p className='truncate text-[var(--text-tertiary)] text-caption'>
1257+
{member.userEmail || member.userId}
1258+
</p>
12251259
</div>
12261260

12271261
{isSelectedAdmin ? (
1228-
<>
1262+
<div className='flex flex-shrink-0 items-center gap-1.5'>
12291263
<Combobox
12301264
options={ROLE_OPTIONS.map((option) => ({
12311265
value: option.value,
@@ -1250,55 +1284,85 @@ export function CredentialsManager() {
12501284
variant='ghost'
12511285
onClick={() => handleRemoveMember(member.userId)}
12521286
disabled={member.role === 'admin' && adminMemberCount <= 1}
1253-
className='w-full justify-end'
1287+
className='h-7 px-2 text-[var(--text-tertiary)] text-caption hover-hover:text-[var(--text-error)]'
12541288
>
12551289
Remove
12561290
</Button>
1257-
</>
1291+
</div>
12581292
) : (
1259-
<>
1260-
<Badge variant='gray-secondary'>{member.role}</Badge>
1261-
<div />
1262-
</>
1293+
<Badge variant='gray-secondary' size='sm'>
1294+
{member.role === 'admin' ? 'Admin' : 'Member'}
1295+
</Badge>
12631296
)}
12641297
</div>
12651298
))}
1299+
1300+
{/* Add member row */}
12661301
{isSelectedAdmin && (
1267-
<div className='grid grid-cols-[1fr_120px_72px] items-center gap-2 border-[var(--border)] border-t pt-2'>
1268-
<Combobox
1269-
options={workspaceUserOptions}
1270-
value={
1271-
workspaceUserOptions.find((option) => option.value === memberUserId)
1272-
?.label || ''
1273-
}
1274-
selectedValue={memberUserId}
1275-
onChange={setMemberUserId}
1276-
placeholder='Add member...'
1277-
searchable
1278-
searchPlaceholder='Search members...'
1279-
size='sm'
1280-
/>
1281-
<Combobox
1282-
options={ROLE_OPTIONS.map((option) => ({
1283-
value: option.value,
1284-
label: option.label,
1285-
}))}
1286-
value={
1287-
ROLE_OPTIONS.find((option) => option.value === memberRole)?.label || ''
1288-
}
1289-
selectedValue={memberRole}
1290-
onChange={(value) => setMemberRole(value as WorkspaceCredentialRole)}
1291-
placeholder='Role'
1292-
size='sm'
1293-
/>
1294-
<Button
1295-
variant='ghost'
1296-
onClick={handleAddMember}
1297-
disabled={!memberUserId || upsertMember.isPending}
1298-
className='w-full justify-end'
1299-
>
1300-
Add
1301-
</Button>
1302+
<div className='flex flex-col gap-2 border-t border-[var(--border)] bg-[var(--surface-1)] px-4 py-3'>
1303+
<div className='flex items-center gap-1.5'>
1304+
<UserPlus className='h-3.5 w-3.5 text-[var(--text-tertiary)]' />
1305+
<p className='text-[var(--text-secondary)] text-caption font-medium'>
1306+
Grant access to a workspace member
1307+
</p>
1308+
</div>
1309+
<div className='flex items-center gap-2'>
1310+
<div className='flex-1'>
1311+
<Combobox
1312+
options={workspaceUserOptions}
1313+
value={
1314+
workspaceUserOptions.find((option) => option.value === memberUserId)
1315+
?.label || ''
1316+
}
1317+
selectedValue={memberUserId}
1318+
onChange={setMemberUserId}
1319+
placeholder='Select workspace member...'
1320+
searchable
1321+
searchPlaceholder='Search workspace members...'
1322+
emptyMessage='No workspace members available. Invite members to the workspace first.'
1323+
size='sm'
1324+
/>
1325+
</div>
1326+
<div className='w-[110px] flex-shrink-0'>
1327+
<Combobox
1328+
options={ROLE_OPTIONS.map((option) => ({
1329+
value: option.value,
1330+
label: option.label,
1331+
}))}
1332+
value={
1333+
ROLE_OPTIONS.find((option) => option.value === memberRole)?.label ||
1334+
''
1335+
}
1336+
selectedValue={memberRole}
1337+
onChange={(value) => setMemberRole(value as WorkspaceCredentialRole)}
1338+
placeholder='Role'
1339+
size='sm'
1340+
/>
1341+
</div>
1342+
<Button
1343+
variant='primary'
1344+
onClick={handleAddMember}
1345+
disabled={!memberUserId || upsertMember.isPending}
1346+
className='h-7 flex-shrink-0 px-3'
1347+
>
1348+
{upsertMember.isPending ? 'Adding...' : 'Add'}
1349+
</Button>
1350+
</div>
1351+
<p className='flex items-start gap-1 text-[var(--text-muted)] text-[11px]'>
1352+
<Info className='mt-0.5 h-3 w-3 flex-shrink-0' />
1353+
Only members of this workspace appear here. To add someone new, invite
1354+
them to the workspace first.
1355+
</p>
1356+
</div>
1357+
)}
1358+
1359+
{/* Non-admin notice */}
1360+
{!isSelectedAdmin && (
1361+
<div className='flex items-center gap-2 border-t border-[var(--border)] bg-[var(--surface-1)] px-4 py-2.5'>
1362+
<Info className='h-3.5 w-3.5 flex-shrink-0 text-[var(--text-muted)]' />
1363+
<p className='text-[var(--text-muted)] text-caption'>
1364+
Only admins of this secret can manage access control.
1365+
</p>
13021366
</div>
13031367
)}
13041368
</div>
@@ -1307,7 +1371,7 @@ export function CredentialsManager() {
13071371
</div>
13081372
</div>
13091373

1310-
<div className='mt-auto flex items-center justify-end border-[var(--border)] border-t pt-2.5'>
1374+
<div className='mt-auto flex items-center justify-end pt-2.5'>
13111375
<div className='flex items-center gap-2'>
13121376
<Button onClick={handleBackAttempt} variant='default'>
13131377
Back
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use client'
2+
3+
import { memo, useCallback, useRef, useState } from 'react'
4+
import { ArrowUp, Bot } from 'lucide-react'
5+
import { Button, Tooltip } from '@/components/emcn'
6+
import { cn } from '@/lib/core/utils/cn'
7+
import { usePanelStore } from '@/stores/panel'
8+
9+
const SEND_BUTTON_BASE = 'h-[28px] w-[28px] rounded-full border-0 p-0 transition-colors'
10+
const SEND_BUTTON_ACTIVE =
11+
'bg-[#383838] hover:bg-[#575757] dark:bg-[#E0E0E0] dark:hover:bg-[#CFCFCF]'
12+
const SEND_BUTTON_DISABLED = 'bg-[#808080] dark:bg-[#808080]'
13+
14+
/**
15+
* Floating copilot input that appears centered on the canvas when the panel
16+
* is collapsed. Provides a quick entry point to the copilot — on submit,
17+
* the message is forwarded to the panel store and the copilot tab opens.
18+
*/
19+
export const CopilotInput = memo(function CopilotInput() {
20+
const isPanelOpen = usePanelStore((s) => s.isPanelOpen)
21+
const setPendingCopilotMessage = usePanelStore((s) => s.setPendingCopilotMessage)
22+
23+
const [value, setValue] = useState('')
24+
const inputRef = useRef<HTMLInputElement>(null)
25+
26+
const canSubmit = value.trim().length > 0
27+
28+
const handleSubmit = useCallback(() => {
29+
const trimmed = value.trim()
30+
if (!trimmed) return
31+
setPendingCopilotMessage(trimmed)
32+
setValue('')
33+
if (inputRef.current) {
34+
inputRef.current.value = ''
35+
}
36+
}, [value, setPendingCopilotMessage])
37+
38+
const handleKeyDown = useCallback(
39+
(e: React.KeyboardEvent<HTMLInputElement>) => {
40+
if (e.key === 'Enter') {
41+
e.preventDefault()
42+
handleSubmit()
43+
}
44+
},
45+
[handleSubmit]
46+
)
47+
48+
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
49+
setValue(e.target.value)
50+
}, [])
51+
52+
if (isPanelOpen) return null
53+
54+
return (
55+
<div className='pointer-events-none absolute inset-x-0 bottom-6 z-10 flex justify-center'>
56+
<div className='pointer-events-auto flex h-[44px] w-full max-w-[520px] items-center gap-2 rounded-xl border border-[var(--border-1)] bg-[var(--white)] px-3 shadow-sm dark:bg-[var(--surface-4)]'>
57+
<Tooltip.Root>
58+
<Tooltip.Trigger asChild>
59+
<div className='flex h-5 w-5 flex-shrink-0 items-center justify-center'>
60+
<Bot className='h-4 w-4 text-[var(--text-muted)]' />
61+
</div>
62+
</Tooltip.Trigger>
63+
<Tooltip.Content side='top'>Ask the copilot</Tooltip.Content>
64+
</Tooltip.Root>
65+
<input
66+
ref={inputRef}
67+
type='text'
68+
value={value}
69+
onChange={handleChange}
70+
onKeyDown={handleKeyDown}
71+
placeholder='Ask copilot anything...'
72+
className='h-full min-w-0 flex-1 border-0 bg-transparent text-[14px] text-[var(--text-primary)] outline-none placeholder:text-[var(--text-subtle)] focus-visible:ring-0'
73+
autoComplete='off'
74+
autoCorrect='off'
75+
spellCheck={false}
76+
/>
77+
<Button
78+
variant='ghost'
79+
onClick={handleSubmit}
80+
disabled={!canSubmit}
81+
className={cn(
82+
SEND_BUTTON_BASE,
83+
canSubmit ? SEND_BUTTON_ACTIVE : SEND_BUTTON_DISABLED,
84+
'flex-shrink-0'
85+
)}
86+
aria-label='Send message'
87+
>
88+
<ArrowUp
89+
className='block h-[16px] w-[16px] text-white dark:text-black'
90+
strokeWidth={2.25}
91+
/>
92+
</Button>
93+
</div>
94+
</div>
95+
)
96+
})

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export { BlockMenu } from './block-menu'
22
export { CanvasMenu } from './canvas-menu'
33
export { CommandList } from './command-list/command-list'
4+
export { CopilotInput } from './copilot-input/copilot-input'
45
export { Cursors } from './cursors/cursors'
56
export { DiffControls } from './diff-controls/diff-controls'
67
export { ErrorBoundary } from './error/index'

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useEffect, useRef, useState } from 'react'
44
import clsx from 'clsx'
5-
import { FileText, MoreVertical, Pencil, RotateCcw, SendToBack } from 'lucide-react'
5+
import { MoreVertical, NotepadText, Pencil, RotateCcw, SendToBack } from 'lucide-react'
66
import {
77
Button,
88
Popover,
@@ -304,7 +304,7 @@ export function Versions({
304304
)}
305305
onClick={() => handleOpenDescriptionModal(v.version)}
306306
>
307-
<FileText className='h-3.5 w-3.5' />
307+
<NotepadText className='h-3.5 w-3.5' />
308308
</Button>
309309
</Tooltip.Trigger>
310310
<Tooltip.Content side='top' className='max-w-[240px]'>
@@ -329,10 +329,7 @@ export function Versions({
329329
<Pencil className='h-3 w-3' />
330330
<span>Rename</span>
331331
</PopoverItem>
332-
<PopoverItem onClick={() => handleOpenDescriptionModal(v.version)}>
333-
<FileText className='h-3 w-3' />
334-
<span>{v.description ? 'Edit description' : 'Add description'}</span>
335-
</PopoverItem>
332+
336333
{!v.isActive && (
337334
<PopoverItem onClick={() => handlePromote(v.version)}>
338335
<RotateCcw className='h-3 w-3' />

0 commit comments

Comments
 (0)