@@ -22,6 +22,13 @@ import {
2222 DialogClose ,
2323} from "../components/dialog" ;
2424import { Button } from "../components/button" ;
25+ import {
26+ Select ,
27+ SelectContent ,
28+ SelectItem ,
29+ SelectTrigger ,
30+ SelectValue ,
31+ } from "../components/select" ;
2532import {
2633 DropdownMenu ,
2734 DropdownMenuContent ,
@@ -39,12 +46,18 @@ import {
3946 CardStackHeader ,
4047} from "../components/card-stack" ;
4148import { Badge } from "../components/badge" ;
49+ import { cn } from "../lib/utils" ;
4250
4351type SecretStorageOption = {
4452 readonly label : string ;
4553 readonly value : string ;
4654} ;
4755
56+ type SecretScopeOption = {
57+ readonly label : string ;
58+ readonly value : ScopeId ;
59+ } ;
60+
4861const defaultStorageOptions : readonly SecretStorageOption [ ] = [
4962 { value : "auto" , label : "Auto" } ,
5063 { value : "keychain" , label : "Keychain" } ,
@@ -77,8 +90,9 @@ function AddSecretDialog(props: {
7790 onOpenChange : ( v : boolean ) => void ;
7891 description : string ;
7992 storageOptions : readonly SecretStorageOption [ ] ;
80- existingSecretIds : readonly string [ ] ;
93+ existingSecrets : readonly { readonly id : string ; readonly scopeId : ScopeId } [ ] ;
8194 scopeId : ScopeId ;
95+ scopeOptions : readonly SecretScopeOption [ ] ;
8296 prefill ?: SecretPrefill ;
8397} ) {
8498 return (
@@ -88,8 +102,9 @@ function AddSecretDialog(props: {
88102 key = "open"
89103 description = { props . description }
90104 storageOptions = { props . storageOptions }
91- existingSecretIds = { props . existingSecretIds }
105+ existingSecrets = { props . existingSecrets }
92106 scopeId = { props . scopeId }
107+ scopeOptions = { props . scopeOptions }
93108 prefill = { props . prefill }
94109 onClose = { ( ) => props . onOpenChange ( false ) }
95110 />
@@ -101,20 +116,31 @@ function AddSecretDialog(props: {
101116function AddSecretDialogContent ( props : {
102117 description : string ;
103118 storageOptions : readonly SecretStorageOption [ ] ;
104- existingSecretIds : readonly string [ ] ;
119+ existingSecrets : readonly { readonly id : string ; readonly scopeId : ScopeId } [ ] ;
105120 scopeId : ScopeId ;
121+ scopeOptions : readonly SecretScopeOption [ ] ;
106122 prefill ?: SecretPrefill ;
107123 onClose : ( ) => void ;
108124} ) {
109125 const initialProvider = props . prefill ?. provider ?? props . storageOptions [ 0 ] ?. value ?? "auto" ;
126+ const [ targetScope , setTargetScope ] = useState ( props . scopeId ) ;
127+ const existingSecretIds = useMemo (
128+ ( ) =>
129+ props . existingSecrets
130+ . filter ( ( secret ) => secret . scopeId === targetScope )
131+ . map ( ( secret ) => secret . id ) ,
132+ [ props . existingSecrets , targetScope ] ,
133+ ) ;
134+ const controlFieldClassName =
135+ "[&_[data-slot=field-label]]:h-5 [&_[data-slot=field-label]]:items-start [&_[data-slot=field-label]]:leading-none [&_[data-slot=input]]:h-9" ;
110136
111137 return (
112138 < SecretForm . Provider
113- existingSecretIds = { props . existingSecretIds }
139+ existingSecretIds = { existingSecretIds }
114140 suggestedName = { props . prefill ?. name }
115141 initialIdOverride = { props . prefill ?. secretId }
116142 initialProvider = { initialProvider }
117- scopeId = { props . scopeId }
143+ scopeId = { targetScope }
118144 onCreated = { props . onClose }
119145 >
120146 < DialogContent className = "sm:max-w-[440px]" >
@@ -126,11 +152,37 @@ function AddSecretDialogContent(props: {
126152 </ DialogHeader >
127153
128154 < div className = "grid gap-5 py-3" >
129- < div className = "grid grid-cols-2 gap-3" >
130- < SecretForm . NameField />
131- < SecretForm . IdField />
155+ < div className = "grid grid-cols-2 items-start gap-3" >
156+ < div className = { controlFieldClassName } >
157+ < SecretForm . NameField />
158+ </ div >
159+ < div className = { controlFieldClassName } >
160+ < SecretForm . IdField />
161+ </ div >
162+ </ div >
163+ < div className = "grid grid-cols-2 items-start gap-3" >
164+ < div className = { controlFieldClassName } >
165+ < SecretForm . ValueField />
166+ </ div >
167+ < div className = { cn ( "grid min-w-0 gap-3" , controlFieldClassName ) } >
168+ < label className = "h-5 text-sm font-medium leading-none" > Scope</ label >
169+ < Select
170+ value = { targetScope }
171+ onValueChange = { ( value ) => setTargetScope ( ScopeId . make ( value ) ) }
172+ >
173+ < SelectTrigger className = "h-9 w-full min-w-0 text-sm" >
174+ < SelectValue />
175+ </ SelectTrigger >
176+ < SelectContent >
177+ { props . scopeOptions . map ( ( option ) => (
178+ < SelectItem key = { option . value } value = { option . value } >
179+ { option . label }
180+ </ SelectItem >
181+ ) ) }
182+ </ SelectContent >
183+ </ Select >
184+ </ div >
132185 </ div >
133- < SecretForm . ValueField />
134186 < SecretForm . ProviderField options = { props . storageOptions } />
135187 < SecretForm . ErrorBanner />
136188 </ div >
@@ -273,12 +325,21 @@ export function SecretsPage(props: {
273325 const existingSecretIds = useMemo (
274326 ( ) =>
275327 AsyncResult . match ( secrets , {
276- onInitial : ( ) => [ ] as string [ ] ,
277- onFailure : ( ) => [ ] as string [ ] ,
278- onSuccess : ( { value } ) => value . map ( ( secret ) => secret . id ) ,
328+ onInitial : ( ) => [ ] as { readonly id : string ; readonly scopeId : ScopeId } [ ] ,
329+ onFailure : ( ) => [ ] as { readonly id : string ; readonly scopeId : ScopeId } [ ] ,
330+ onSuccess : ( { value } ) =>
331+ value . map ( ( secret ) => ( { id : secret . id , scopeId : secret . scopeId } ) ) ,
279332 } ) ,
280333 [ secrets ] ,
281334 ) ;
335+ const scopeOptions = useMemo (
336+ ( ) =>
337+ scopeStack . map ( ( entry , index ) => ( {
338+ value : entry . id ,
339+ label : index === 0 ? "Personal" : entry . name || "Organization" ,
340+ } ) ) ,
341+ [ scopeStack ] ,
342+ ) ;
282343 const doRemove = useAtomSet ( removeSecretOptimistic ( scopeId ) , {
283344 mode : "promiseExit" ,
284345 } ) ;
@@ -414,8 +475,9 @@ export function SecretsPage(props: {
414475 onOpenChange = { setAddOpen }
415476 description = { addSecretDescription }
416477 storageOptions = { storageOptions }
417- existingSecretIds = { existingSecretIds }
478+ existingSecrets = { existingSecretIds }
418479 scopeId = { formScopeId }
480+ scopeOptions = { scopeOptions }
419481 prefill = { props . prefill }
420482 />
421483 </ div >
0 commit comments