@@ -5,7 +5,18 @@ import Link from 'next/link';
55import { useParams } from 'next/navigation' ;
66import { graphql } from '@/gql' ;
77import { useQuery } from '@tanstack/react-query' ;
8- import { Button , Spinner , Tag , Text } from 'opub-ui' ;
8+ import {
9+ Accordion ,
10+ AccordionContent ,
11+ AccordionItem ,
12+ AccordionTrigger ,
13+ Button ,
14+ Dialog ,
15+ Spinner ,
16+ Table ,
17+ Tag ,
18+ Text ,
19+ } from 'opub-ui' ;
920
1021import { GraphQL } from '@/lib/api' ;
1122import { formatDate } from '@/lib/utils' ;
@@ -19,7 +30,11 @@ const datasetResourceQuery: any = graphql(`
1930 type
2031 name
2132 description
22-
33+ previewData {
34+ columns
35+ rows
36+ }
37+ previewEnabled
2338 schema {
2439 fieldName
2540 id
@@ -28,6 +43,7 @@ const datasetResourceQuery: any = graphql(`
2843 }
2944 fileDetails {
3045 format
46+ size
3147 }
3248 }
3349 }
@@ -78,6 +94,118 @@ const Resources = () => {
7894 } ) ;
7995 } , [ getResourceDetails . data ] ) ;
8096
97+ const generateColumnData = ( ) => {
98+ return [
99+ {
100+ accessorKey : 'schema' ,
101+ header : 'Columns' ,
102+ cell : ( { row } : any ) => {
103+ return (
104+ < Dialog >
105+ < Dialog . Trigger >
106+ < Button kind = "tertiary" > View All Columns</ Button >
107+ </ Dialog . Trigger >
108+ < Dialog . Content title = { 'Fields' } limitHeight >
109+ < Table
110+ columns = { [
111+ {
112+ accessorKey : 'name' ,
113+ header : 'Name of the Field' ,
114+ } ,
115+ {
116+ accessorKey : 'format' ,
117+ header : 'Format' ,
118+ } ,
119+ ] }
120+ rows = { row . original . schema . map ( ( item : any ) => ( {
121+ name : item . fieldName ,
122+ format : item . format ,
123+ } ) ) }
124+ />
125+ </ Dialog . Content >
126+ </ Dialog >
127+ ) ;
128+ } ,
129+ } ,
130+ {
131+ accessorKey : 'rowsLength' ,
132+ header : 'No.of Rows' ,
133+ cell : ( { row } : any ) => {
134+ return (
135+ < p >
136+ { row . original . rowsLength === 0
137+ ? 'NA'
138+ : `${ row . original . rowsLength } ` }
139+ </ p >
140+ ) ;
141+ } ,
142+ } ,
143+ {
144+ accessorKey : 'format' ,
145+ header : 'Format' ,
146+ } ,
147+ {
148+ accessorKey : 'size' ,
149+ header : 'Size' ,
150+ } ,
151+ {
152+ accessorKey : 'preview' ,
153+ header : 'Preview' ,
154+ cell : ( { row } : any ) => {
155+ const previewData = row . original . preview ;
156+
157+ // Generate columns dynamically from previewData.columns
158+ const previewColumns =
159+ previewData ?. columns ?. map ( ( column : string ) => ( {
160+ accessorKey : column ,
161+ header : column ,
162+ cell : ( { cell } : any ) => {
163+ const value = cell . getValue ( ) ;
164+ return < span > { value !== null ? value . toString ( ) : 'N/A' } </ span > ;
165+ } ,
166+ } ) ) || [ ] ;
167+
168+ // Transform rows data to match column structure
169+ const previewRows =
170+ previewData ?. rows ?. map ( ( row : any [ ] ) => {
171+ const rowData : Record < string , any > = { } ;
172+ previewData . columns . forEach ( ( column : string , index : number ) => {
173+ rowData [ column ] = row [ index ] ;
174+ } ) ;
175+ return rowData ;
176+ } ) || [ ] ;
177+
178+ return (
179+ < Dialog >
180+ < Dialog . Trigger >
181+ < Button kind = "tertiary" disabled = { ! previewData } >
182+ Preview
183+ </ Button >
184+ </ Dialog . Trigger >
185+ < Dialog . Content title = { 'Fields' } limitHeight large >
186+ { previewData && (
187+ < Table columns = { previewColumns } rows = { previewRows } />
188+ ) }
189+ </ Dialog . Content >
190+ </ Dialog >
191+ ) ;
192+ } ,
193+ } ,
194+ ] ;
195+ } ;
196+
197+ const generateTableData = ( data : any ) => {
198+ return [
199+ {
200+ schema : data ?. schema ,
201+ rowsLength : data ?. previewData ?. rows ?. length || 'Na' ,
202+ format : data ?. fileDetails ?. format || 'Na' ,
203+ size : Math . round ( data ?. fileDetails ?. size / 1024 ) . toFixed ( 2 ) + 'KB' ,
204+ preview : data ?. previewData ,
205+ } ,
206+ ] ;
207+ } ;
208+
81209 return (
82210 < div className = "w-full" >
83211 { getResourceDetails . isLoading ? (
@@ -90,51 +218,77 @@ const Resources = () => {
90218 < Text variant = "bodyLg" className = "mx-6 lg:mx-0" >
91219 Downloadable Resources
92220 </ Text >
93- < div className = "mx-6 mt-5 flex flex-col gap-8 bg-surfaceDefault p-6 lg:mx-0" >
221+ < div >
94222 { getResourceDetails . data ?. datasetResources . map (
95223 ( item : any , index : number ) => (
96224 < div
97225 key = { index }
98- className = "flex flex-wrap justify-between gap-4 "
226+ className = "mx-6 mt-5 flex flex-col gap-6 bg-surfaceDefault p-6 lg:mx-0 "
99227 >
100- < div className = "gap flex flex-col lg:w-4/5" >
101- < div className = "item flex items-center gap-2" >
102- < Text variant = "headingMd" > { item . name } </ Text >
103- < Tag > { item . fileDetails . format } </ Tag >
228+ < div className = "flex flex-wrap justify-between gap-4" >
229+ < div className = "gap flex flex-col lg:w-4/5" >
230+ < div className = "item flex items-center gap-2" >
231+ < Text variant = "headingMd" > { item . name } </ Text >
232+ { item . fileDetails ?. format && (
233+ < Tag > { item . fileDetails ?. format } </ Tag >
234+ ) }
235+ </ div >
236+ < div >
237+ < Text > Updated:</ Text >
238+ < Text > { formatDate ( item . modified ) } </ Text >
239+ </ div >
104240 </ div >
105241 < div >
106- < Text > Updated:</ Text >
107- < Text > { formatDate ( item . modified ) } </ Text >
108- </ div >
109- < div className = "flex flex-col" >
110- < div
111- ref = { ( el ) => ( descriptionRefs . current [ index ] = el ) }
112- className = { ! showMore [ index ] ? 'line-clamp-2' : '' }
242+ < Link
243+ href = { `${ process . env . NEXT_PUBLIC_BACKEND_URL } /api/download/resource/${ item . id } ` }
244+ target = "_blank"
245+ className = "flex justify-center"
113246 >
114- < Text > { item . description } </ Text >
115- </ div >
116- { isDescriptionLong [ index ] && (
117- < Button
118- className = "self-start p-2"
119- onClick = { ( ) => toggleShowMore ( index ) }
120- variant = "interactive"
121- size = "slim"
122- kind = "tertiary"
123- >
124- { showMore [ index ] ? 'Show less' : 'Show more' }
125- </ Button >
126- ) }
247+ < Button > Download</ Button >
248+ </ Link >
127249 </ div >
128250 </ div >
129- < div >
130- < Link
131- href = { `${ process . env . NEXT_PUBLIC_BACKEND_URL } /api/download/resource/${ item . id } ` }
132- target = "_blank"
133- className = "flex justify-center"
134- >
135- < Button > Download</ Button >
136- </ Link >
137- </ div >
251+ < Accordion type = "single" collapsible className = "w-full" >
252+ < AccordionItem value = "item-1" className = " border-none" >
253+ < div className = "flex flex-wrap items-center justify-between gap-4" >
254+ < div className = "flex flex-col lg:w-3/4" >
255+ < div
256+ ref = { ( el ) => ( descriptionRefs . current [ index ] = el ) }
257+ className = { ! showMore [ index ] ? 'line-clamp-2' : '' }
258+ >
259+ < Text > { item . description } </ Text >
260+ </ div >
261+ { isDescriptionLong [ index ] && (
262+ < Button
263+ className = "self-start p-2"
264+ onClick = { ( ) => toggleShowMore ( index ) }
265+ variant = "interactive"
266+ size = "slim"
267+ kind = "tertiary"
268+ >
269+ { showMore [ index ] ? 'Show less' : 'Show more' }
270+ </ Button >
271+ ) }
272+ </ div >
273+ < AccordionTrigger className = "flex w-full flex-wrap items-center gap-2 p-0 hover:no-underline" >
274+ View Details
275+ </ AccordionTrigger >
276+ </ div >
277+ < AccordionContent
278+ className = "flex w-full flex-col py-5"
279+ style = { {
280+ backgroundColor : 'var( --base-pure-white)' ,
281+ outline : '1px solid var( --base-pure-white)' ,
282+ } }
283+ >
284+ < Table
285+ columns = { generateColumnData ( ) }
286+ rows = { generateTableData ( item ) }
287+ hideFooter
288+ />
289+ </ AccordionContent >
290+ </ AccordionItem >
291+ </ Accordion >
138292 </ div >
139293 )
140294 ) }
0 commit comments