Skip to content

Commit 93b83ba

Browse files
committed
feat(secrets): allow admins to view and edit workspace secret values
1 parent a591d7c commit 93b83ba

File tree

1 file changed

+45
-29
lines changed

1 file changed

+45
-29
lines changed

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

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,11 @@ interface WorkspaceVariableRowProps {
127127
renamingKey: string | null
128128
pendingKeyValue: string
129129
hasCredential: boolean
130-
isAdmin: boolean
130+
canEdit: boolean
131131
onRenameStart: (key: string) => void
132132
onPendingKeyChange: (value: string) => void
133133
onRenameEnd: (key: string, value: string) => void
134+
onValueChange: (key: string, value: string) => void
134135
onDelete: (key: string) => void
135136
onViewDetails: (envKey: string) => void
136137
}
@@ -141,17 +142,18 @@ function WorkspaceVariableRow({
141142
renamingKey,
142143
pendingKeyValue,
143144
hasCredential,
144-
isAdmin,
145+
canEdit,
145146
onRenameStart,
146147
onPendingKeyChange,
147148
onRenameEnd,
149+
onValueChange,
148150
onDelete,
149151
onViewDetails,
150152
}: WorkspaceVariableRowProps) {
151153
const [valueFocused, setValueFocused] = useState(false)
152154

153155
const maskedValueStyle =
154-
isAdmin && !valueFocused ? ({ WebkitTextSecurity: 'disc' } as React.CSSProperties) : undefined
156+
canEdit && !valueFocused ? ({ WebkitTextSecurity: 'disc' } as React.CSSProperties) : undefined
155157

156158
return (
157159
<div className='contents'>
@@ -167,18 +169,24 @@ function WorkspaceVariableRow({
167169
autoCapitalize='off'
168170
spellCheck='false'
169171
readOnly
170-
onFocus={(e) => e.target.removeAttribute('readOnly')}
172+
onFocus={(e) => {
173+
if (canEdit) e.target.removeAttribute('readOnly')
174+
}}
171175
className='h-9'
172176
/>
173177
<div />
174178
<EmcnInput
175-
value={isAdmin ? value : value ? '\u2022'.repeat(value.length) : ''}
179+
value={canEdit ? value : value ? '\u2022'.repeat(value.length) : ''}
180+
onChange={(e) => onValueChange(envKey, e.target.value)}
176181
readOnly
177-
onFocus={() => {
178-
if (isAdmin) setValueFocused(true)
182+
onFocus={(e) => {
183+
if (canEdit) {
184+
setValueFocused(true)
185+
e.target.removeAttribute('readOnly')
186+
}
179187
}}
180188
onBlur={() => {
181-
if (isAdmin) setValueFocused(false)
189+
if (canEdit) setValueFocused(false)
182190
}}
183191
autoComplete='off'
184192
autoCorrect='off'
@@ -195,14 +203,16 @@ function WorkspaceVariableRow({
195203
>
196204
Details
197205
</Button>
198-
<Tooltip.Root>
199-
<Tooltip.Trigger asChild>
200-
<Button variant='ghost' onClick={() => onDelete(envKey)} className='h-9 w-9'>
201-
<Trash />
202-
</Button>
203-
</Tooltip.Trigger>
204-
<Tooltip.Content>Delete secret</Tooltip.Content>
205-
</Tooltip.Root>
206+
{canEdit && (
207+
<Tooltip.Root>
208+
<Tooltip.Trigger asChild>
209+
<Button variant='ghost' onClick={() => onDelete(envKey)} className='h-9 w-9'>
210+
<Trash />
211+
</Button>
212+
</Tooltip.Trigger>
213+
<Tooltip.Content>Delete secret</Tooltip.Content>
214+
</Tooltip.Root>
215+
)}
206216
</div>
207217
)
208218
}
@@ -316,7 +326,7 @@ export function CredentialsManager() {
316326
const { data: workspacePermissions } = useWorkspacePermissionsQuery(workspaceId || null)
317327
const queryClient = useQueryClient()
318328

319-
const isAdmin = useMemo(() => {
329+
const isWorkspaceAdmin = useMemo(() => {
320330
const userId = session?.user?.id
321331
if (!userId || !workspacePermissions?.users) return false
322332
const currentUser = workspacePermissions.users.find((user) => user.userId === userId)
@@ -791,6 +801,10 @@ export function CredentialsManager() {
791801
[pendingKeyValue, renamingKey]
792802
)
793803

804+
const handleWorkspaceValueChange = useCallback((key: string, value: string) => {
805+
setWorkspaceVars((prev) => ({ ...prev, [key]: value }))
806+
}, [])
807+
794808
const handleDeleteWorkspaceVar = useCallback((key: string) => {
795809
setWorkspaceVars((prev) => {
796810
const next = { ...prev }
@@ -1536,25 +1550,27 @@ export function CredentialsManager() {
15361550
renamingKey={renamingKey}
15371551
pendingKeyValue={pendingKeyValue}
15381552
hasCredential={envKeyToCredential.has(key)}
1539-
isAdmin={isAdmin}
1553+
canEdit={isWorkspaceAdmin}
15401554
onRenameStart={setRenamingKey}
15411555
onPendingKeyChange={setPendingKeyValue}
15421556
onRenameEnd={handleWorkspaceKeyRename}
1557+
onValueChange={handleWorkspaceValueChange}
15431558
onDelete={handleDeleteWorkspaceVar}
15441559
onViewDetails={(envKey) => handleViewDetails(envKey, 'env_workspace')}
15451560
/>
15461561
))}
1547-
{(searchTerm.trim()
1548-
? filteredNewWorkspaceRows
1549-
: newWorkspaceRows.map((row, index) => ({ row, originalIndex: index }))
1550-
).map(({ row, originalIndex }) => (
1551-
<NewWorkspaceVariableRow
1552-
key={row.id || originalIndex}
1553-
envVar={row}
1554-
index={originalIndex}
1555-
onUpdate={updateNewWorkspaceRow}
1556-
/>
1557-
))}
1562+
{isWorkspaceAdmin &&
1563+
(searchTerm.trim()
1564+
? filteredNewWorkspaceRows
1565+
: newWorkspaceRows.map((row, index) => ({ row, originalIndex: index }))
1566+
).map(({ row, originalIndex }) => (
1567+
<NewWorkspaceVariableRow
1568+
key={row.id || originalIndex}
1569+
envVar={row}
1570+
index={originalIndex}
1571+
onUpdate={updateNewWorkspaceRow}
1572+
/>
1573+
))}
15581574
<div className={`${COL_SPAN_ALL} h-[8px]`} />
15591575
</>
15601576
)}

0 commit comments

Comments
 (0)