@@ -34,17 +34,44 @@ const emit = defineEmits<{
3434const { t } = useI18n ()
3535
3636// State
37- const selectedClient = ref (' claude-desktop ' )
37+ const selectedClient = ref (' ' )
3838const configContent = ref (' ' )
3939const isLoading = ref (false )
4040const isCopying = ref (false )
41+ const supportedClients = ref <string []>([])
42+ const isLoadingClients = ref (false )
43+
44+ // Load supported clients when modal opens
45+ watch (() => props .open , async (isOpen ) => {
46+ if (isOpen && supportedClients .value .length === 0 ) {
47+ await loadSupportedClients ()
48+ }
49+ })
4150
4251// Load configuration when client changes
4352watch (selectedClient , async (newClient ) => {
4453 if (newClient ) {
4554 await loadConfiguration (newClient )
4655 }
47- }, { immediate: true })
56+ })
57+
58+ // Load supported clients from API
59+ async function loadSupportedClients() {
60+ isLoadingClients .value = true
61+ try {
62+ const clients = await GatewayConfigService .getSupportedClients ()
63+ supportedClients .value = clients
64+ // Set first client as default if no client is selected
65+ if (! selectedClient .value && clients .length > 0 ) {
66+ selectedClient .value = clients [0 ]
67+ }
68+ } catch (error ) {
69+ const errorMessage = error instanceof Error ? error .message : ' Failed to load supported clients'
70+ toast .error (errorMessage )
71+ } finally {
72+ isLoadingClients .value = false
73+ }
74+ }
4875
4976// Load configuration from API
5077async function loadConfiguration(client : string ) {
@@ -61,6 +88,28 @@ async function loadConfiguration(client: string) {
6188 }
6289}
6390
91+ // Get display name for client (with fallback)
92+ function getClientDisplayName(client : string ): string {
93+ // Convert client name to camelCase for i18n key matching
94+ const clientKey = client .split (' -' ).map ((word , index ) => {
95+ if (index === 0 ) {
96+ return word .toLowerCase ()
97+ }
98+ return word .charAt (0 ).toUpperCase () + word .slice (1 ).toLowerCase ()
99+ }).join (' ' )
100+
101+ const translationKey = ` gatewayConfig.clients.${clientKey } `
102+ const translated = t (translationKey )
103+
104+ // If translation returns the key itself, it means translation doesn't exist
105+ // Fall back to a capitalized version of the client name
106+ if (translated === translationKey ) {
107+ return client .split (' -' ).map (word => word .charAt (0 ).toUpperCase () + word .slice (1 )).join (' ' )
108+ }
109+
110+ return translated
111+ }
112+
64113function handleClose() {
65114 emit (' update:open' , false )
66115}
@@ -73,15 +122,15 @@ async function handleCopyAndClose() {
73122 }
74123
75124 isCopying .value = true
76-
125+
77126 try {
78127 await navigator .clipboard .writeText (configContent .value )
79128 handleClose ()
80129 // Show success toast after modal closes
81130 setTimeout (() => {
82131 toast .success (t (' gatewayConfig.messages.copySuccess' ))
83132 }, 100 )
84- } catch ( error ) {
133+ } catch {
85134 toast .error (' Failed to copy configuration to clipboard' )
86135 } finally {
87136 isCopying .value = false
@@ -102,19 +151,53 @@ async function handleCopyAndClose() {
102151 </AlertDialogHeader >
103152
104153 <div class =" space-y-6" >
154+ <!-- Installation Step -->
155+ <div class =" space-y-3" >
156+ <label class =" text-sm font-medium" >First, install the DeployStack Gateway</label >
157+ <div class =" rounded-lg bg-gray-900 shadow-lg border border-gray-700 overflow-hidden" >
158+ <!-- Terminal Header -->
159+ <div class =" flex items-center justify-between bg-gray-800 px-4 py-2 border-b border-gray-600" >
160+ <div class =" flex items-center space-x-2" >
161+ <div class =" w-3 h-3 rounded-full bg-red-500" ></div >
162+ <div class =" w-3 h-3 rounded-full bg-yellow-500" ></div >
163+ <div class =" w-3 h-3 rounded-full bg-green-500" ></div >
164+ </div >
165+ <div class =" text-gray-400 text-sm font-mono" >
166+ ~/setup
167+ </div >
168+ <div class =" w-16" ></div >
169+ </div >
170+
171+ <!-- Terminal Body -->
172+ <div class =" p-4 bg-gray-900" >
173+ <div class =" font-mono text-sm" >
174+ <div class =" text-gray-300 mb-1" >
175+ <span class =" text-white" >$ </span ><span class =" text-yellow-300" >npm install -g @deploystack/gateway</span >
176+ </div >
177+ <div class =" text-gray-300 mb-3" >
178+ <span class =" text-white" >$ </span ><span class =" text-yellow-300" >deploystack login</span >
179+ </div >
180+ </div >
181+ </div >
182+ </div >
183+ </div >
184+
105185 <!-- Client Selection Dropdown -->
106186 <div class =" space-y-2" >
107187 <label class =" text-sm font-medium" >{{ t('gatewayConfig.modal.clientLabel') }}</label >
108- <Select v-model =" selectedClient" >
188+ <Select v-model =" selectedClient" :disabled = " isLoadingClients " >
109189 <SelectTrigger class =" w-full" >
110- <SelectValue :placeholder =" t('gatewayConfig.modal.selectPlaceholder')" />
190+ <SelectValue
191+ :placeholder =" isLoadingClients ? 'Loading clients...' : t('gatewayConfig.modal.selectPlaceholder')"
192+ />
111193 </SelectTrigger >
112194 <SelectContent >
113- <SelectItem value =" claude-desktop" >
114- {{ t('gatewayConfig.clients.claudeDesktop') }}
115- </SelectItem >
116- <SelectItem value =" cursor" >
117- {{ t('gatewayConfig.clients.cursor') }}
195+ <SelectItem
196+ v-for =" client in supportedClients"
197+ :key =" client"
198+ :value =" client"
199+ >
200+ {{ getClientDisplayName(client) }}
118201 </SelectItem >
119202 </SelectContent >
120203 </Select >
@@ -127,7 +210,7 @@ async function handleCopyAndClose() {
127210 v-model =" configContent"
128211 :placeholder =" isLoading ? t('gatewayConfig.modal.loading') : t('gatewayConfig.modal.configPlaceholder')"
129212 :disabled =" isLoading"
130- rows =" 12 "
213+ rows =" 8 "
131214 class =" font-mono text-sm"
132215 readonly
133216 />
@@ -138,11 +221,11 @@ async function handleCopyAndClose() {
138221 <Button @click =" handleClose" variant =" outline" >
139222 {{ t('actions.close') }}
140223 </Button >
141- <Button
142- @click =" handleCopyAndClose"
224+ <Button
225+ @click =" handleCopyAndClose"
143226 :loading =" isCopying"
144227 loading-text =" Copying..."
145- :disabled =" !configContent.trim() || isLoading"
228+ :disabled =" !configContent.trim() || isLoading || isLoadingClients "
146229 >
147230 {{ t('gatewayConfig.button.copyAndClose') }}
148231 </Button >
0 commit comments