Skip to content

Commit fa47e6c

Browse files
authored
accept all, validate later (#511)
1 parent dcfa9ce commit fa47e6c

2 files changed

Lines changed: 90 additions & 3 deletions

File tree

src/components/ui/MainPanel/LocalNetCDF.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,40 @@
11
"use client";
2-
import React, {ChangeEvent} from 'react'
2+
import React, {ChangeEvent, useState} from 'react'
33
import { Input } from '../input'
44
import { useGlobalStore, useZarrStore } from '@/utils/GlobalStates';
55
import { NetCDF4 } from '@earthyscience/netcdf4-wasm';
6-
6+
import {
7+
Alert,
8+
AlertDescription,
9+
AlertTitle,
10+
} from '@/components/ui/alert';
711

812
interface LocalNCType {
913
setShowLocal: React.Dispatch<React.SetStateAction<boolean>>;
1014
setOpenVariables: React.Dispatch<React.SetStateAction<boolean>>;
1115
}
1216

17+
const NETCDF_EXT_REGEX = /\.(nc|netcdf|nc3|nc4)$/i;
18+
1319
const LocalNetCDF = ({ setOpenVariables}:LocalNCType) => {
1420
const {setStatus } = useGlobalStore.getState()
1521
const {ncModule} = useZarrStore.getState()
22+
const [ncError, setError] = useState<string | null>(null);
1623

1724
const handleFileSelect = async (event: ChangeEvent<HTMLInputElement>) => {
25+
setError(null);
1826
const files = event.target.files;
1927
if (!files || files.length === 0) {
2028
setStatus(null)
2129
return;
2230
}
2331
const file = files[0]
32+
// Manual validation (iOS-safe)
33+
if (!NETCDF_EXT_REGEX.test(file.name)) {
34+
setError('Please select a valid NetCDF (.nc, .netcdf, .nc3, .nc4) file.');
35+
return;
36+
}
37+
2438
if (ncModule) ncModule.close();
2539
setStatus("Loading...")
2640
const data = await NetCDF4.fromBlobLazy(file)
@@ -47,9 +61,16 @@ const LocalNetCDF = ({ setOpenVariables}:LocalNCType) => {
4761
<Input type="file" id="filepicker"
4862
className='hover:drop-shadow-md hover:scale-[102%]'
4963
style={{width:'200px', cursor:'pointer'}}
50-
accept='.nc, .netcdf, .nc3, .nc4'
5164
onChange={handleFileSelect}
5265
/>
66+
{ncError && (
67+
<Alert variant="destructive" className='border-0 mt-1'>
68+
<AlertTitle>Hey!</AlertTitle>
69+
<AlertDescription>
70+
{ncError}
71+
</AlertDescription>
72+
</Alert>
73+
)}
5374
</div>
5475
)
5576
}

src/components/ui/alert.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as React from "react"
2+
import { cva, type VariantProps } from "class-variance-authority"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
const alertVariants = cva(
7+
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8+
{
9+
variants: {
10+
variant: {
11+
default: "bg-card text-card-foreground",
12+
destructive:
13+
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
14+
},
15+
},
16+
defaultVariants: {
17+
variant: "default",
18+
},
19+
}
20+
)
21+
22+
function Alert({
23+
className,
24+
variant,
25+
...props
26+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27+
return (
28+
<div
29+
data-slot="alert"
30+
role="alert"
31+
className={cn(alertVariants({ variant }), className)}
32+
{...props}
33+
/>
34+
)
35+
}
36+
37+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38+
return (
39+
<div
40+
data-slot="alert-title"
41+
className={cn(
42+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43+
className
44+
)}
45+
{...props}
46+
/>
47+
)
48+
}
49+
50+
function AlertDescription({
51+
className,
52+
...props
53+
}: React.ComponentProps<"div">) {
54+
return (
55+
<div
56+
data-slot="alert-description"
57+
className={cn(
58+
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
59+
className
60+
)}
61+
{...props}
62+
/>
63+
)
64+
}
65+
66+
export { Alert, AlertTitle, AlertDescription }

0 commit comments

Comments
 (0)