Skip to content

Commit 6b66c32

Browse files
committed
fix: fixed action bar on modal
1 parent 5b9b39c commit 6b66c32

File tree

2 files changed

+283
-277
lines changed

2 files changed

+283
-277
lines changed

client/src/components/CreateInstanceDialog.tsx

Lines changed: 126 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
3535
const queryClient = useQueryClient()
3636

3737
const createMutation = useMutation({
38-
mutationFn: (data: { name?: string; config?: string; gowa_version?: string }) =>
38+
mutationFn: (data: { name?: string; config?: string; gowa_version?: string }) =>
3939
apiClient.createInstance(data),
4040
onSuccess: () => {
4141
queryClient.invalidateQueries({ queryKey: ['instances'] })
@@ -61,11 +61,11 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
6161

6262
const validateForm = () => {
6363
const newErrors: {name?: string} = {}
64-
64+
6565
if (name.trim() && (name.trim().length < 1 || name.trim().length > 100)) {
6666
newErrors.name = 'Name must be between 1 and 100 characters'
6767
}
68-
68+
6969
setErrors(newErrors)
7070
return Object.keys(newErrors).length === 0
7171
}
@@ -81,156 +81,159 @@ export function CreateInstanceDialog({ open, onOpenChange }: CreateInstanceDialo
8181

8282
const handleSubmit = (e: React.FormEvent) => {
8383
e.preventDefault()
84-
84+
8585
if (!validateForm()) {
8686
return
8787
}
8888

8989
const data: { name?: string; config?: string; gowa_version?: string } = {}
90-
90+
9191
if (name.trim()) {
9292
data.name = name.trim()
9393
}
94-
94+
9595
data.gowa_version = version
96-
96+
9797
// Build configuration
9898
let finalConfig: InstanceConfig = {
9999
args: ['rest', '--port=PORT'],
100100
flags: flags
101101
}
102-
102+
103103
// Update the JSON view
104104
setJsonConfig(JSON.stringify(finalConfig, null, 2))
105-
105+
106106
data.config = JSON.stringify(finalConfig)
107107

108108
createMutation.mutate(data)
109109
}
110110

111111
return (
112112
<Dialog open={open} onOpenChange={onOpenChange}>
113-
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
114-
<DialogHeader>
115-
<DialogTitle>Create New Instance</DialogTitle>
116-
<DialogDescription>
117-
Create a new application instance. A random name will be generated if none is provided.
118-
</DialogDescription>
119-
</DialogHeader>
120-
121-
<form onSubmit={handleSubmit} className="space-y-4">
122-
<div className="space-y-2">
123-
<label htmlFor="name" className="text-sm font-medium text-gray-700">
124-
Name (optional)
125-
</label>
126-
<Input
127-
id="name"
128-
placeholder="Enter instance name..."
129-
value={name}
130-
onChange={(e) => setName(e.target.value)}
131-
className={errors.name ? 'border-red-500' : ''}
113+
<DialogContent className="sm:max-w-[600px] max-h-[90vh] flex flex-col">
114+
<div className="overflow-y-auto flex-1">
115+
<DialogHeader>
116+
<DialogTitle>Create New Instance</DialogTitle>
117+
<DialogDescription>
118+
Create a new application instance. A random name will be generated if none is provided.
119+
</DialogDescription>
120+
</DialogHeader>
121+
122+
<form onSubmit={handleSubmit} className="space-y-4" id="createForm">
123+
<div className="space-y-2">
124+
<label htmlFor="name" className="text-sm font-medium text-gray-700">
125+
Name (optional)
126+
</label>
127+
<Input
128+
id="name"
129+
placeholder="Enter instance name..."
130+
value={name}
131+
onChange={(e) => setName(e.target.value)}
132+
className={errors.name ? 'border-red-500' : ''}
133+
/>
134+
{errors.name && (
135+
<p className="text-sm text-red-600">{errors.name}</p>
136+
)}
137+
</div>
138+
139+
<VersionSelector
140+
value={version}
141+
onChange={setVersion}
142+
disabled={createMutation.isPending}
132143
/>
133-
{errors.name && (
134-
<p className="text-sm text-red-600">{errors.name}</p>
135-
)}
136-
</div>
137144

138-
<VersionSelector
139-
value={version}
140-
onChange={setVersion}
141-
disabled={createMutation.isPending}
142-
/>
143-
144-
{/* Collapsible Configuration Section */}
145-
<div className="space-y-3">
146-
<div className="border border-gray-200 rounded-md">
147-
<Button
148-
type="button"
149-
variant="ghost"
150-
size="sm"
151-
onClick={() => setShowConfiguration(!showConfiguration)}
152-
className="w-full flex items-center justify-between p-3 h-auto font-medium text-gray-700 hover:bg-gray-50"
153-
>
154-
<div className="flex items-center gap-2">
155-
<Settings className="h-4 w-4" />
156-
<span>Configuration</span>
157-
<span className="text-xs bg-gray-100 px-2 py-1 rounded text-gray-500">
158-
Optional
159-
</span>
160-
</div>
161-
{showConfiguration ? (
162-
<ChevronUp className="h-4 w-4" />
163-
) : (
164-
<ChevronDown className="h-4 w-4" />
165-
)}
166-
</Button>
167-
168-
{showConfiguration && (
169-
<div className="border-t border-gray-200 p-4 space-y-4">
170-
<div className="flex items-center justify-between">
171-
<span className="text-sm text-gray-600">
172-
Advanced GOWA settings
145+
{/* Collapsible Configuration Section */}
146+
<div className="space-y-3">
147+
<div className="rounded-md border border-gray-200">
148+
<Button
149+
type="button"
150+
variant="ghost"
151+
size="sm"
152+
onClick={() => setShowConfiguration(!showConfiguration)}
153+
className="flex justify-between items-center p-3 w-full h-auto font-medium text-gray-700 hover:bg-gray-50"
154+
>
155+
<div className="flex gap-2 items-center">
156+
<Settings className="w-4 h-4" />
157+
<span>Configuration</span>
158+
<span className="px-2 py-1 text-xs text-gray-500 bg-gray-100 rounded">
159+
Optional
173160
</span>
174-
<Button
175-
type="button"
176-
variant="ghost"
177-
size="sm"
178-
onClick={() => setShowJsonView(!showJsonView)}
179-
className="flex items-center gap-1 h-7 px-2 text-xs"
180-
>
181-
{showJsonView ? (
182-
<>
183-
<EyeOff className="h-3 w-3" />
184-
Hide JSON
185-
</>
186-
) : (
187-
<>
188-
<Eye className="h-3 w-3" />
189-
View JSON
190-
</>
191-
)}
192-
</Button>
193161
</div>
194-
195-
{showJsonView ? (
196-
<div className="space-y-2">
197-
<div className="flex items-center gap-2 mb-2">
198-
<Code className="h-4 w-4 text-gray-500" />
199-
<span className="text-xs text-gray-500">JSON Configuration (Read-only)</span>
200-
</div>
201-
<pre className="bg-gray-50 p-3 rounded-md overflow-x-auto text-xs font-mono border border-gray-200 max-h-96">
202-
{jsonConfig}
203-
</pre>
204-
<p className="text-xs text-gray-500 mt-1">
205-
This is the raw configuration that will be saved. Use the form above to make changes.
206-
</p>
207-
</div>
162+
{showConfiguration ? (
163+
<ChevronUp className="w-4 h-4" />
208164
) : (
209-
<div className="max-h-96 overflow-y-auto">
210-
<CliFlagsComponent flags={flags} onChange={setFlags} />
211-
</div>
165+
<ChevronDown className="w-4 h-4" />
212166
)}
213-
</div>
214-
)}
167+
</Button>
168+
169+
{showConfiguration && (
170+
<div className="p-4 space-y-4 border-t border-gray-200">
171+
<div className="flex justify-between items-center">
172+
<span className="text-sm text-gray-600">
173+
Advanced GOWA settings
174+
</span>
175+
<Button
176+
type="button"
177+
variant="ghost"
178+
size="sm"
179+
onClick={() => setShowJsonView(!showJsonView)}
180+
className="flex gap-1 items-center px-2 h-7 text-xs"
181+
>
182+
{showJsonView ? (
183+
<>
184+
<EyeOff className="w-3 h-3" />
185+
Hide JSON
186+
</>
187+
) : (
188+
<>
189+
<Eye className="w-3 h-3" />
190+
View JSON
191+
</>
192+
)}
193+
</Button>
194+
</div>
195+
196+
{showJsonView ? (
197+
<div className="space-y-2">
198+
<div className="flex gap-2 items-center mb-2">
199+
<Code className="w-4 h-4 text-gray-500" />
200+
<span className="text-xs text-gray-500">JSON Configuration (Read-only)</span>
201+
</div>
202+
<pre className="overflow-x-auto p-3 font-mono text-xs bg-gray-50 rounded-md border border-gray-200">
203+
{jsonConfig}
204+
</pre>
205+
<p className="mt-1 text-xs text-gray-500">
206+
This is the raw configuration that will be saved. Use the form above to make changes.
207+
</p>
208+
</div>
209+
) : (
210+
<div>
211+
<CliFlagsComponent flags={flags} onChange={setFlags} />
212+
</div>
213+
)}
214+
</div>
215+
)}
216+
</div>
215217
</div>
216-
</div>
217-
218-
<DialogFooter>
219-
<Button type="button" variant="outline" onClick={handleClose}>
220-
Cancel
221-
</Button>
222-
<Button
223-
type="submit"
224-
disabled={createMutation.isPending}
225-
>
226-
{createMutation.isPending && (
227-
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
228-
)}
229-
Create Instance
230-
</Button>
231-
</DialogFooter>
232-
</form>
218+
219+
</form>
220+
</div>
221+
<DialogFooter className="border-t">
222+
<Button type="button" variant="outline" onClick={handleClose}>
223+
Cancel
224+
</Button>
225+
<Button
226+
form="createForm"
227+
type="submit"
228+
disabled={createMutation.isPending}
229+
>
230+
{createMutation.isPending && (
231+
<Loader2 className="mr-2 w-4 h-4 animate-spin" />
232+
)}
233+
Create Instance
234+
</Button>
235+
</DialogFooter>
233236
</DialogContent>
234237
</Dialog>
235238
)
236-
}
239+
}

0 commit comments

Comments
 (0)