Skip to content

Commit 0ede70e

Browse files
committed
Enhance UrlInputForm component to support file uploads; validate blob URLs and improve URL validation messages.
1 parent 49d698b commit 0ede70e

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

src/components/UrlInputForm.tsx

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from "react";
22
import { Input } from "@/components/ui/input";
33
import { Button } from "@/components/ui/button";
4-
import { LinkIcon, ArrowRightIcon, AlertCircleIcon } from "lucide-react";
4+
import { LinkIcon, ArrowRightIcon, AlertCircleIcon, UploadIcon } from "lucide-react";
55

66
interface UrlInputFormProps {
77
onSubmit: (url: string) => void;
@@ -15,15 +15,26 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
1515
// Validate if string is a valid URL
1616
const isValidUrl = (urlString: string): boolean => {
1717
try {
18-
new URL(urlString);
19-
return true;
18+
// Handle blob URLs (from file input)
19+
if (urlString.startsWith('blob:')) {
20+
return true;
21+
}
22+
23+
const url = new URL(urlString);
24+
// Allow http, https, and file protocols
25+
return url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'file:';
2026
} catch (err) {
2127
return false;
2228
}
2329
};
2430

2531
// Validate if URL points to a YAML file
2632
const isYamlFile = (urlString: string): boolean => {
33+
// For blob URLs, we trust the file input's accept attribute
34+
if (urlString.startsWith('blob:')) {
35+
return true;
36+
}
37+
2738
const lowerUrl = urlString.toLowerCase();
2839
return lowerUrl.endsWith('.yml') || lowerUrl.endsWith('.yaml');
2940
};
@@ -34,7 +45,7 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
3445
}
3546

3647
if (!isValidUrl(urlString)) {
37-
return "Please enter a valid URL";
48+
return "Please enter a valid URL (http, https, or file://)";
3849
}
3950

4051
if (!isYamlFile(urlString)) {
@@ -44,6 +55,19 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
4455
return null;
4556
};
4657

58+
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
59+
const file = e.target.files?.[0];
60+
if (file) {
61+
// Revoke previous blob URL if it exists
62+
if (url.startsWith('blob:')) {
63+
URL.revokeObjectURL(url);
64+
}
65+
const fileUrl = URL.createObjectURL(file);
66+
setUrl(fileUrl);
67+
setError(null);
68+
}
69+
};
70+
4771
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
4872
e.preventDefault();
4973

@@ -59,6 +83,12 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
5983

6084
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
6185
const newUrl = e.target.value;
86+
87+
// Revoke previous blob URL if it exists and user is changing to a different URL
88+
if (url.startsWith('blob:') && newUrl !== url) {
89+
URL.revokeObjectURL(url);
90+
}
91+
6292
setUrl(newUrl);
6393

6494
// Clear error when user starts typing again
@@ -76,7 +106,8 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
76106
<div className="w-full">
77107
<form onSubmit={handleSubmit} className="space-y-4">
78108
<div className="space-y-2">
79-
<div className="relative flex items-center">
109+
<div className=" flex items-center">
110+
<div className="relative flex-1">
80111
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
81112
<LinkIcon className="h-5 w-5 text-muted-foreground" />
82113
</div>
@@ -85,11 +116,21 @@ const UrlInputForm = ({ onSubmit }: UrlInputFormProps) => {
85116
value={url}
86117
onChange={handleUrlChange}
87118
placeholder="Enter YAML file URL"
88-
className={`pl-10 pr-4 py-6 text-base rounded-l-md rounded-r-none border-r-0 ${
119+
className={`pl-10 pr-4 py-6 text-base rounded-l-md rounded-r-none border-r-0 bg-white ${
89120
error ? 'border-red-500 focus-visible:ring-red-500' : ''
90121
}`}
91122
required
92123
/>
124+
<label className="h-full aspect-square flex items-center justify-center cursor-pointer bg-white absolute right-0 top-0 border border-input border-l-0 border-r-0">
125+
<input
126+
type="file"
127+
accept=".yml,.yaml"
128+
onChange={handleFileChange}
129+
className="hidden"
130+
/>
131+
<UploadIcon className="h-4 w-4 text-muted-foreground" />
132+
</label>
133+
</div>
93134
<Button
94135
type="submit"
95136
className="py-6 px-6 rounded-l-none text-base font-medium flex items-center justify-center gap-2 transition-all h-[50px]"

0 commit comments

Comments
 (0)