diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/credentials/credentials-manager.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/credentials/credentials-manager.tsx
index f5ab9a349..27fa9240a 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/credentials/credentials-manager.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/credentials/credentials-manager.tsx
@@ -2,7 +2,7 @@
import { createElement, useEffect, useMemo, useState } from 'react'
import { createLogger } from '@sim/logger'
-import { Plus, Search, Trash2 } from 'lucide-react'
+import { Plus, Search, Share2, Trash2 } from 'lucide-react'
import { useParams } from 'next/navigation'
import {
Badge,
@@ -18,6 +18,7 @@ import {
ModalFooter,
ModalHeader,
Textarea,
+ Tooltip,
} from '@/components/emcn'
import { Skeleton } from '@/components/ui'
import { useSession } from '@/lib/auth/auth-client'
@@ -720,6 +721,58 @@ export function CredentialsManager() {
}
}
+ const [isPromoting, setIsPromoting] = useState(false)
+
+ const handlePromoteToWorkspace = async () => {
+ if (!selectedCredential || selectedCredential.type !== 'env_personal' || !workspaceId) return
+ const envKey = selectedCredential.envKey || ''
+ if (!envKey) return
+
+ setDetailsError(null)
+ setIsPromoting(true)
+
+ try {
+ const currentValue =
+ personalEnvironment[envKey]?.value || workspaceEnvironmentData?.personal?.[envKey] || ''
+
+ if (!currentValue) {
+ setDetailsError('Cannot promote: secret value is empty.')
+ setIsPromoting(false)
+ return
+ }
+
+ const workspaceVariables = workspaceEnvironmentData?.workspace ?? {}
+ await upsertWorkspaceEnvironment.mutateAsync({
+ workspaceId,
+ variables: { ...workspaceVariables, [envKey]: currentValue },
+ })
+
+ const response = await createCredential.mutateAsync({
+ workspaceId,
+ type: 'env_workspace',
+ envKey,
+ description: selectedCredential.description || undefined,
+ })
+
+ await deleteCredential.mutateAsync(selectedCredential.id)
+
+ const newCredentialId = response?.credential?.id
+ if (newCredentialId) {
+ setSelectedCredentialId(newCredentialId)
+ } else {
+ setSelectedCredentialId(null)
+ }
+
+ await refetchCredentials()
+ } catch (error: unknown) {
+ const message = error instanceof Error ? error.message : 'Failed to promote secret'
+ setDetailsError(message)
+ logger.error('Failed to promote personal secret to workspace', error)
+ } finally {
+ setIsPromoting(false)
+ }
+ }
+
const handleDisconnectSelectedCredential = async () => {
if (!selectedCredential || selectedCredential.type !== 'oauth' || !selectedCredential.accountId)
return
@@ -885,11 +938,25 @@ export function CredentialsManager() {
Disconnect account
)}
+ {selectedCredential.type === 'env_personal' && (
+
+
+
+
+ Promote to workspace secret
+
+ )}
{selectedCredential.type !== 'oauth' && (