Skip to content

Commit f58e6a2

Browse files
authored
Merge pull request #4 from shiftstack/hover
hover help icon which explains what the input means
2 parents df1ba06 + e7f481b commit f58e6a2

File tree

1 file changed

+194
-17
lines changed

1 file changed

+194
-17
lines changed

src/App.jsx

Lines changed: 194 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
import './App.css'
22
import React, { useState } from "react";
33

4+
// Reusable input with tooltip component
5+
const InputWithTooltip = ({ type, name, placeholder, value, onChange, required, tooltip, className = "" }) => {
6+
const [showTooltip, setShowTooltip] = useState(false);
7+
8+
return (
9+
<div className="relative w-full mb-3">
10+
<div className="flex items-center">
11+
<input
12+
type={type || "text"}
13+
name={name}
14+
placeholder={placeholder}
15+
value={value}
16+
onChange={onChange}
17+
className={`w-full p-2 border rounded ${className}`}
18+
required={required}
19+
/>
20+
<div
21+
className="ml-2 text-gray-500 cursor-help"
22+
onMouseEnter={() => setShowTooltip(true)}
23+
onMouseLeave={() => setShowTooltip(false)}
24+
>
25+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
26+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
27+
</svg>
28+
</div>
29+
</div>
30+
{showTooltip && (
31+
<div className="absolute right-0 z-10 p-2 mt-1 text-sm bg-gray-800 text-white rounded shadow-lg w-64">
32+
{tooltip}
33+
</div>
34+
)}
35+
</div>
36+
);
37+
};
38+
439
export default function HcpCliAssistant() {
540
const steps = [
641
"Cluster Details",
@@ -167,27 +202,143 @@ export default function HcpCliAssistant() {
167202
) : (
168203
<div className="space-y-4">
169204
{step === 0 && <>
170-
<input type="text" name="name" placeholder="Cluster Name (required). Example: test" value={form.name} onChange={handleChange} className="w-full p-2 border rounded" required />
171-
<input type="text" name="baseDomain" placeholder="Base Domain (required). Example: mydomain.com" value={form.baseDomain} onChange={handleChange} className="w-full p-2 border rounded" required />
172-
<input type="number" name="nodePoolReplicas" placeholder="Node Pool Replicas (required)" value={form.nodePoolReplicas} onChange={handleChange} className="w-full p-2 border rounded" required />
173-
<input type="text" name="pullSecret" placeholder="Pull Secret path (required). Example: /path/to/pull-secret" value={form.pullSecret} onChange={handleChange} className="w-full p-2 border rounded" required />
174-
<input type="text" name="sshKey" placeholder="SSH Key path (required). Example: /path/to/id_rsa.pub" value={form.sshKey} onChange={handleChange} className="w-full p-2 border rounded" required />
205+
<InputWithTooltip
206+
name="name"
207+
placeholder="Cluster Name (required). Example: test"
208+
value={form.name}
209+
onChange={handleChange}
210+
required
211+
tooltip="A unique name for your HyperShift cluster. This will be used to identify your cluster in the HyperShift control plane."
212+
/>
213+
<InputWithTooltip
214+
name="baseDomain"
215+
placeholder="Base Domain (required). Example: mydomain.com"
216+
value={form.baseDomain}
217+
onChange={handleChange}
218+
required
219+
tooltip="The base domain of your cluster. This domain will be used to create DNS records for your cluster."
220+
/>
221+
<InputWithTooltip
222+
type="number"
223+
name="nodePoolReplicas"
224+
placeholder="Node Pool Replicas (required)"
225+
value={form.nodePoolReplicas}
226+
onChange={handleChange}
227+
required
228+
tooltip="The number of worker nodes to create in your cluster's default node pool."
229+
/>
230+
<InputWithTooltip
231+
name="pullSecret"
232+
placeholder="Pull Secret path (required). Example: /path/to/pull-secret"
233+
value={form.pullSecret}
234+
onChange={handleChange}
235+
required
236+
tooltip="Path to the pull secret file. This is required to pull container images from the Red Hat registry."
237+
/>
238+
<InputWithTooltip
239+
name="sshKey"
240+
placeholder="SSH Key path (required). Example: /path/to/id_rsa.pub"
241+
value={form.sshKey}
242+
onChange={handleChange}
243+
required
244+
tooltip="Path to your SSH public key file. This key will be added to the authorized_keys on all nodes."
245+
/>
175246
</>}
176-
{step === 1 && <><label className="block"><input type="checkbox" name="osCloudSet" checked={form.osCloudSet} onChange={handleChange} className="mr-2" />OS_CLOUD is set in the environment</label>{!form.osCloudSet && (
177-
<>
178-
<input type="text" name="openstackCredentialsFile" placeholder="OpenStack Credentials File (optional). Example: /path/to/clouds.yaml" value={form.openstackCredentialsFile} onChange={handleChange} className="w-full p-2 border rounded" />
179-
</>
180-
)}
181-
<input type="text" name="openstackCloud" placeholder="OpenStack Cloud (optional). Default: openstack" value={form.openstackCloud} onChange={handleChange} className="w-full p-2 border rounded" />
182-
<input type="text" name="openstackCaCertFile" placeholder="OpenStack CA Certificate File (optional). Example: /path/to/ca.cert" value={form.openstackCaCertFile} onChange={handleChange} className="w-full p-2 border rounded" /></>}
247+
{step === 1 && <>
248+
<label className="block">
249+
<input
250+
type="checkbox"
251+
name="osCloudSet"
252+
checked={form.osCloudSet}
253+
onChange={handleChange}
254+
className="mr-2"
255+
/>
256+
OS_CLOUD is set in the environment
257+
<span
258+
className="ml-2 text-gray-500 cursor-help relative inline-block"
259+
onMouseEnter={(e) => e.target.querySelector('div').style.display = 'block'}
260+
onMouseLeave={(e) => e.target.querySelector('div').style.display = 'none'}
261+
>
262+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 inline-block" viewBox="0 0 20 20" fill="currentColor">
263+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
264+
</svg>
265+
<div className="absolute right-0 z-10 p-2 mt-1 text-sm bg-gray-800 text-white rounded shadow-lg w-64" style={{display: 'none'}}>
266+
Check this if you have the OS_CLOUD environment variable set. Otherwise, you'll need to provide a credentials file.
267+
</div>
268+
</span>
269+
</label>
270+
271+
{!form.osCloudSet && (
272+
<InputWithTooltip
273+
name="openstackCredentialsFile"
274+
placeholder="OpenStack Credentials File (optional). Example: /path/to/clouds.yaml"
275+
value={form.openstackCredentialsFile}
276+
onChange={handleChange}
277+
tooltip="Path to your OpenStack clouds.yaml file containing your authentication credentials."
278+
/>
279+
)}
280+
281+
<InputWithTooltip
282+
name="openstackCloud"
283+
placeholder="OpenStack Cloud (optional). Default: openstack"
284+
value={form.openstackCloud}
285+
onChange={handleChange}
286+
tooltip="The named cloud to use from your clouds.yaml file if you have multiple clouds defined."
287+
/>
288+
289+
<InputWithTooltip
290+
name="openstackCaCertFile"
291+
placeholder="OpenStack CA Certificate File (optional). Example: /path/to/ca.cert"
292+
value={form.openstackCaCertFile}
293+
onChange={handleChange}
294+
tooltip="Path to a CA certificate file if your OpenStack environment uses a self-signed certificate."
295+
/>
296+
</>}
297+
183298
{step === 2 && (
184299
<>
185-
<input type="text" name="externalNetworkId" placeholder="External Network ID (optional). Example: 64f629fd-f75b-4e66-96ad-94f6f2125ba4" value={form.externalNetworkId} onChange={handleChange} className="w-full p-2 border rounded" />
186-
<input type="text" name="ingressFloatingIp" placeholder="Ingress Floating IP (optional). Example: 192.168.100.7" value={form.ingressFloatingIp} onChange={handleChange} className="w-full p-2 border rounded" />
187-
<input type="text" name="dnsNameservers" placeholder="DNS Nameservers (optional). Example: 1.1.1.1,8.8.8.8" value={form.dnsNameservers} onChange={handleChange} className="w-full p-2 border rounded" />
300+
<InputWithTooltip
301+
name="externalNetworkId"
302+
placeholder="External Network ID (optional). Example: 64f629fd-f75b-4e66-96ad-94f6f2125ba4"
303+
value={form.externalNetworkId}
304+
onChange={handleChange}
305+
tooltip="The ID of the external network that will be used for floating IPs. If not provided, the installer will attempt to discover it."
306+
/>
188307

308+
<InputWithTooltip
309+
name="ingressFloatingIp"
310+
placeholder="Ingress Floating IP (optional). Example: 192.168.100.7"
311+
value={form.ingressFloatingIp}
312+
onChange={handleChange}
313+
tooltip="A pre-allocated floating IP to use for cluster ingress. If not provided, a new floating IP will be allocated."
314+
/>
315+
316+
<InputWithTooltip
317+
name="dnsNameservers"
318+
placeholder="DNS Nameservers (optional). Example: 1.1.1.1,8.8.8.8"
319+
value={form.dnsNameservers}
320+
onChange={handleChange}
321+
tooltip="Comma-separated list of DNS nameservers to use for the cluster's subnet."
322+
/>
323+
324+
{/* Additional ports section remains the same */}
189325
<div className="mt-4">
190-
<h3 className="font-semibold mb-2">Additional Nodepool Ports (optional)</h3>
326+
<h3 className="font-semibold mb-2">
327+
Additional Nodepool Ports (optional)
328+
<span
329+
className="ml-2 text-gray-500 cursor-help relative inline-block"
330+
onMouseEnter={(e) => e.target.querySelector('div').style.display = 'block'}
331+
onMouseLeave={(e) => e.target.querySelector('div').style.display = 'none'}
332+
>
333+
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 inline-block" viewBox="0 0 20 20" fill="currentColor">
334+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
335+
</svg>
336+
<div className="absolute right-0 z-10 p-2 mt-1 text-sm bg-gray-800 text-white rounded shadow-lg w-64" style={{display: 'none'}}>
337+
Configure additional network ports for the nodes in your cluster. Useful for multi-network setups or SR-IOV configurations.
338+
</div>
339+
</span>
340+
</h3>
341+
191342
{form.additionalPorts && JSON.parse(form.additionalPorts).map((port, index) => (
192343
<div key={index} className="p-3 border rounded mb-2">
193344
<div className="flex items-center justify-between mb-2">
@@ -294,7 +445,33 @@ export default function HcpCliAssistant() {
294445
</div>
295446
</>
296447
)}
297-
{step === 3 && <><input type="text" name="nodeFlavor" placeholder="Flavor name for the Nodepool (Required)" value={form.nodeFlavor} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="text" name="nodeAZ" placeholder="Nova Availability Zone (optional)" value={form.nodeAZ} onChange={handleChange} className="w-full p-2 border rounded" /><input type="text" name="nodeImageName" placeholder="Glance Image Name (optional)" value={form.nodeImageName} onChange={handleChange} className="w-full p-2 border rounded" /></>}
448+
449+
{step === 3 && <>
450+
<InputWithTooltip
451+
name="nodeFlavor"
452+
placeholder="Flavor name for the Nodepool (Required)"
453+
value={form.nodeFlavor}
454+
onChange={handleChange}
455+
required
456+
tooltip="The OpenStack flavor (instance type) to use for the worker nodes in your cluster."
457+
/>
458+
459+
<InputWithTooltip
460+
name="nodeAZ"
461+
placeholder="Nova Availability Zone (optional)"
462+
value={form.nodeAZ}
463+
onChange={handleChange}
464+
tooltip="The availability zone where worker nodes will be created. If not specified, the default AZ will be used."
465+
/>
466+
467+
<InputWithTooltip
468+
name="nodeImageName"
469+
placeholder="Glance Image Name (optional)"
470+
value={form.nodeImageName}
471+
onChange={handleChange}
472+
tooltip="The name of the RHCOS image in Glance to use for the worker nodes. If not specified, the installer will use the latest available RHCOS image."
473+
/>
474+
</>}
298475
</div>
299476
)}
300477

0 commit comments

Comments
 (0)