11import React , { useState } from "react" ;
2- import { ChevronRight , ChevronDown , Hash , Type , Calendar , ToggleLeft } from "lucide-react" ;
2+ import {
3+ ChevronRight ,
4+ ChevronDown ,
5+ Hash ,
6+ Type ,
7+ Calendar ,
8+ ToggleLeft ,
9+ } from "lucide-react" ;
310import { type ColumnStats } from "@/store" ;
411
512interface ColumnNodeProps {
@@ -8,7 +15,12 @@ interface ColumnNodeProps {
815
916const getTypeIcon = ( type : string ) => {
1017 const upperType = type . toUpperCase ( ) ;
11- if ( upperType . includes ( "INT" ) || upperType . includes ( "DOUBLE" ) || upperType . includes ( "FLOAT" ) || upperType . includes ( "DECIMAL" ) ) {
18+ if (
19+ upperType . includes ( "INT" ) ||
20+ upperType . includes ( "DOUBLE" ) ||
21+ upperType . includes ( "FLOAT" ) ||
22+ upperType . includes ( "DECIMAL" )
23+ ) {
1224 return < Hash className = "w-3 h-3" /> ;
1325 } else if ( upperType . includes ( "DATE" ) || upperType . includes ( "TIME" ) ) {
1426 return < Calendar className = "w-3 h-3" /> ;
@@ -20,7 +32,12 @@ const getTypeIcon = (type: string) => {
2032
2133const getTypeColor = ( type : string ) => {
2234 const upperType = type . toUpperCase ( ) ;
23- if ( upperType . includes ( "INT" ) || upperType . includes ( "DOUBLE" ) || upperType . includes ( "FLOAT" ) || upperType . includes ( "DECIMAL" ) ) {
35+ if (
36+ upperType . includes ( "INT" ) ||
37+ upperType . includes ( "DOUBLE" ) ||
38+ upperType . includes ( "FLOAT" ) ||
39+ upperType . includes ( "DECIMAL" )
40+ ) {
2441 return "text-purple-500 bg-purple-500/10" ;
2542 } else if ( upperType . includes ( "DATE" ) || upperType . includes ( "TIME" ) ) {
2643 return "text-green-500 bg-green-500/10" ;
@@ -41,10 +58,10 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
4158
4259 // Safe parsing function that handles both string and number types
4360 const parseValue = ( value : any ) : number => {
44- if ( typeof value === ' number' ) return value ;
45- if ( typeof value === ' string' ) {
61+ if ( typeof value === " number" ) return value ;
62+ if ( typeof value === " string" ) {
4663 // Remove quotes if present
47- const cleaned = value . replace ( / " / g, '' ) ;
64+ const cleaned = value . replace ( / " / g, "" ) ;
4865 return parseFloat ( cleaned ) || 0 ;
4966 }
5067 return 0 ;
@@ -55,7 +72,8 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
5572 const uniqueCount = stats . approx_unique ? parseValue ( stats . approx_unique ) : 0 ;
5673 const totalCount = parseValue ( stats . count ) ;
5774
58- const isNumeric = stats . column_type . toUpperCase ( ) . includes ( "INT" ) ||
75+ const isNumeric =
76+ stats . column_type . toUpperCase ( ) . includes ( "INT" ) ||
5977 stats . column_type . toUpperCase ( ) . includes ( "DOUBLE" ) ||
6078 stats . column_type . toUpperCase ( ) . includes ( "FLOAT" ) ||
6179 stats . column_type . toUpperCase ( ) . includes ( "DECIMAL" ) ;
@@ -73,13 +91,19 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
7391 < ChevronRight className = "w-3 h-3 flex-shrink-0 text-muted-foreground" />
7492 ) }
7593
76- < div className = { `flex-shrink-0 p-1 rounded ${ getTypeColor ( stats . column_type ) } ` } >
94+ < div
95+ className = { `flex-shrink-0 p-1 rounded ${ getTypeColor (
96+ stats . column_type
97+ ) } `}
98+ >
7799 { getTypeIcon ( stats . column_type ) }
78100 </ div >
79101
80102 < div className = "flex-1 min-w-0" >
81103 < div className = "flex items-center gap-2" >
82- < span className = "text-xs font-medium truncate" > { stats . column_name } </ span >
104+ < span className = "text-xs font-medium truncate" >
105+ { stats . column_name }
106+ </ span >
83107 < span className = "text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-mono" >
84108 { stats . column_type }
85109 </ span >
@@ -91,7 +115,9 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
91115 < div className = "flex items-center gap-1" >
92116 < div className = "flex-1 h-1.5 bg-muted rounded-full overflow-hidden" >
93117 < div
94- className = { `h-full ${ getFillColor ( fillPercentage ) } transition-all` }
118+ className = { `h-full ${ getFillColor (
119+ fillPercentage
120+ ) } transition-all`}
95121 style = { { width : `${ fillPercentage } %` } }
96122 />
97123 </ div >
@@ -119,7 +145,9 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
119145 </ div >
120146 < div className = "h-2 bg-background rounded-full overflow-hidden" >
121147 < div
122- className = { `h-full ${ getFillColor ( fillPercentage ) } transition-all` }
148+ className = { `h-full ${ getFillColor (
149+ fillPercentage
150+ ) } transition-all`}
123151 style = { { width : `${ fillPercentage } %` } }
124152 />
125153 </ div >
@@ -137,11 +165,18 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
137165 </ div >
138166 < div className = "flex justify-between" >
139167 < span className = "text-muted-foreground" > Nulls:</ span >
140- < span className = "font-mono" > { ( ( nullPercentage / 100 ) * totalCount ) . toFixed ( 0 ) } </ span >
168+ < span className = "font-mono" >
169+ { ( ( nullPercentage / 100 ) * totalCount ) . toFixed ( 0 ) }
170+ </ span >
141171 </ div >
142172 < div className = "flex justify-between" >
143173 < span className = "text-muted-foreground" > Cardinality:</ span >
144- < span className = "font-mono" > { ( ( uniqueCount / totalCount ) * 100 ) . toFixed ( 1 ) } %</ span >
174+ < span className = "font-mono" >
175+ { isNaN ( ( uniqueCount / totalCount ) * 100 )
176+ ? "0.0"
177+ : ( ( uniqueCount / totalCount ) * 100 ) . toFixed ( 1 ) }
178+ %
179+ </ span >
145180 </ div >
146181 </ div >
147182
@@ -152,20 +187,32 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
152187 < div className = "space-y-1 text-[10px]" >
153188 < div className = "flex justify-between" >
154189 < span className = "text-muted-foreground" > Min:</ span >
155- < span className = "font-mono" > { parseValue ( stats . min ! ) . toLocaleString ( ) } </ span >
190+ < span className = "font-mono" >
191+ { parseValue ( stats . min ! ) . toLocaleString ( ) }
192+ </ span >
156193 </ div >
157194 < div className = "flex justify-between" >
158195 < span className = "text-muted-foreground" > Max:</ span >
159- < span className = "font-mono" > { parseValue ( stats . max ! ) . toLocaleString ( ) } </ span >
196+ < span className = "font-mono" >
197+ { parseValue ( stats . max ! ) . toLocaleString ( ) }
198+ </ span >
160199 </ div >
161200 < div className = "flex justify-between" >
162201 < span className = "text-muted-foreground" > Avg:</ span >
163- < span className = "font-mono" > { parseValue ( stats . avg ) . toLocaleString ( undefined , { maximumFractionDigits : 2 } ) } </ span >
202+ < span className = "font-mono" >
203+ { parseValue ( stats . avg ) . toLocaleString ( undefined , {
204+ maximumFractionDigits : 2 ,
205+ } ) }
206+ </ span >
164207 </ div >
165208 { stats . std && (
166209 < div className = "flex justify-between" >
167210 < span className = "text-muted-foreground" > Std Dev:</ span >
168- < span className = "font-mono" > { parseValue ( stats . std ) . toLocaleString ( undefined , { maximumFractionDigits : 2 } ) } </ span >
211+ < span className = "font-mono" >
212+ { parseValue ( stats . std ) . toLocaleString ( undefined , {
213+ maximumFractionDigits : 2 ,
214+ } ) }
215+ </ span >
169216 </ div >
170217 ) }
171218 </ div >
@@ -174,18 +221,26 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
174221 < >
175222 < div className = "border-t border-border/50 my-1" />
176223 < div className = "space-y-1 text-[10px]" >
177- < div className = "text-[9px] text-muted-foreground font-medium mb-1" > Quartiles</ div >
224+ < div className = "text-[9px] text-muted-foreground font-medium mb-1" >
225+ Quartiles
226+ </ div >
178227 < div className = "flex justify-between" >
179228 < span className = "text-muted-foreground" > Q1 (25%):</ span >
180- < span className = "font-mono text-[9px]" > { parseValue ( stats . q25 ) . toLocaleString ( ) } </ span >
229+ < span className = "font-mono text-[9px]" >
230+ { parseValue ( stats . q25 ) . toLocaleString ( ) }
231+ </ span >
181232 </ div >
182233 < div className = "flex justify-between" >
183234 < span className = "text-muted-foreground" > Q2 (50%):</ span >
184- < span className = "font-mono text-[9px]" > { parseValue ( stats . q50 ) . toLocaleString ( ) } </ span >
235+ < span className = "font-mono text-[9px]" >
236+ { parseValue ( stats . q50 ) . toLocaleString ( ) }
237+ </ span >
185238 </ div >
186239 < div className = "flex justify-between" >
187240 < span className = "text-muted-foreground" > Q3 (75%):</ span >
188- < span className = "font-mono text-[9px]" > { parseValue ( stats . q75 ) . toLocaleString ( ) } </ span >
241+ < span className = "font-mono text-[9px]" >
242+ { parseValue ( stats . q75 ) . toLocaleString ( ) }
243+ </ span >
189244 </ div >
190245 </ div >
191246 </ >
@@ -199,12 +254,26 @@ export const ColumnNode: React.FC<ColumnNodeProps> = ({ stats }) => {
199254 < div className = "border-t border-border/50 my-1" />
200255 < div className = "space-y-1 text-[10px]" >
201256 < div className = "flex justify-between gap-2" >
202- < span className = "text-muted-foreground flex-shrink-0" > Min:</ span >
203- < span className = "font-mono truncate text-right" title = { stats . min } > { stats . min } </ span >
257+ < span className = "text-muted-foreground flex-shrink-0" >
258+ Min:
259+ </ span >
260+ < span
261+ className = "font-mono truncate text-right"
262+ title = { stats . min }
263+ >
264+ { stats . min }
265+ </ span >
204266 </ div >
205267 < div className = "flex justify-between gap-2" >
206- < span className = "text-muted-foreground flex-shrink-0" > Max:</ span >
207- < span className = "font-mono truncate text-right" title = { stats . max } > { stats . max } </ span >
268+ < span className = "text-muted-foreground flex-shrink-0" >
269+ Max:
270+ </ span >
271+ < span
272+ className = "font-mono truncate text-right"
273+ title = { stats . max }
274+ >
275+ { stats . max }
276+ </ span >
208277 </ div >
209278 </ div >
210279 </ >
0 commit comments