1
1
"use client" ;
2
2
import { useState , useEffect } from "react" ;
3
- import { Combobox } from "@headlessui/react" ;
3
+ import { Combobox , Tab } from "@headlessui/react" ;
4
4
import useSWR from "swr" ;
5
5
import { DatabaseIcon } from "./DatabaseIcon" ;
6
6
import { HostListing , fetcher , BASE_URL } from "./api" ;
7
7
import { useClientOnly } from "./hooks/useClientOnly" ;
8
+ import { GraphUpload } from "./GraphUpload" ;
8
9
9
10
/**
10
11
* Dropdown to select a host graph from a list of available graphs.
@@ -25,13 +26,22 @@ export function GraphForm({
25
26
const { data, error, isLoading } = useSWR < { hosts : HostListing [ ] } > ( `${ BASE_URL } /providers/hostlist` , fetcher ) ;
26
27
const [ selectedGraph , setSelectedGraph ] = useState < HostListing | undefined > ( startValue ) ;
27
28
const [ query , setQuery ] = useState ( "" ) ;
29
+ const [ selectedTab , setSelectedTab ] = useState ( 0 ) ;
28
30
const isClient = useClientOnly ( ) ;
29
31
30
32
// Update selectedGraph when startValue changes
31
33
useEffect ( ( ) => {
32
34
setSelectedGraph ( startValue ) ;
33
35
} , [ startValue ] ) ;
34
36
37
+ const handleGraphUploaded = ( uploadedGraph : HostListing ) => {
38
+ if ( onGraphChange ) {
39
+ onGraphChange ( uploadedGraph ) ;
40
+ }
41
+ setSelectedGraph ( uploadedGraph ) ;
42
+ setSelectedTab ( 0 ) ; // Switch back to "Browse Graphs" tab to show the selection
43
+ } ;
44
+
35
45
// Simple loading/error handling.
36
46
// Note that if the host cannot be reached, this is likely the first place
37
47
// that the user will see an error message.
@@ -53,48 +63,89 @@ export function GraphForm({
53
63
< h2 className = "text-xl font-mono" > Host Graph</ h2 >
54
64
< hr className = "my-2" />
55
65
56
- { /* Database Host Selection */ }
57
- < div className = "flex flex-row gap-2 items-center" >
58
- < DatabaseIcon />
59
- < div className = "flow-col w-full" >
60
- < Combobox
61
- onChange = { ( v ) => {
62
- if ( onGraphChange ) {
63
- onGraphChange ( v ) ;
64
- }
65
- setSelectedGraph ( v ) ;
66
- } }
67
- value = { selectedGraph }
66
+ < Tab . Group selectedIndex = { selectedTab } onChange = { setSelectedTab } >
67
+ < Tab . List className = "flex space-x-1 rounded-xl bg-blue-900/20 p-1" >
68
+ < Tab
69
+ className = { ( { selected } ) =>
70
+ `w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700 ring-white/60 ring-offset-2 ring-offset-blue-400 focus:outline-none focus:ring-2 ${
71
+ selected
72
+ ? "bg-white text-blue-700 shadow"
73
+ : "text-blue-100 hover:bg-white/[0.12] hover:text-white"
74
+ } `
75
+ }
76
+ >
77
+ Browse Graphs
78
+ </ Tab >
79
+ < Tab
80
+ className = { ( { selected } ) =>
81
+ `w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700 ring-white/60 ring-offset-2 ring-offset-blue-400 focus:outline-none focus:ring-2 ${
82
+ selected
83
+ ? "bg-white text-blue-700 shadow"
84
+ : "text-blue-100 hover:bg-white/[0.12] hover:text-white"
85
+ } `
86
+ }
68
87
>
69
- < div className = "relative" >
70
- < Combobox . Input
71
- onChange = { ( event ) => setQuery ( event . target . value ) }
72
- className = "w-full p-4 rounded-lg shadow-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent font-bold dark:bg-gray-900 dark:text-gray-200"
73
- placeholder = "Start typing or press the down arrow to choose a host graph..."
74
- displayValue = { ( graph : HostListing ) => graph ?. name }
75
- />
76
- < Combobox . Options className = "p-3 rounded-lg shadow-lg border overflow-y-scroll max-h-64 absolute w-full" >
77
- { filteredGraphs . map ( ( graph ) => (
78
- < Combobox . Option
79
- key = { graph . id }
80
- value = { graph }
81
- className = { ( { active } ) => `${
82
- active
83
- ? "text-white bg-blue-400 dark:bg-blue-400 dark:text-white"
84
- : "text-gray-900 dark:text-gray-200"
88
+ Upload Graph
89
+ </ Tab >
90
+ </ Tab . List >
91
+ < Tab . Panels className = "mt-4" >
92
+ < Tab . Panel className = "rounded-xl bg-white/5 p-3" >
93
+ { /* Database Host Selection */ }
94
+ < div className = "flex flex-row gap-2 items-center" >
95
+ < DatabaseIcon />
96
+ < div className = "flow-col w-full" >
97
+ < Combobox
98
+ onChange = { ( v ) => {
99
+ if ( onGraphChange ) {
100
+ onGraphChange ( v ) ;
85
101
}
86
- cursor-default select-none relative py-2 pl-10 pr-4 hover:bg-blue-400 hover:text-white flex items-center justify-between text-sm
87
- ` }
88
- >
89
- < b className = "font-bold" > { graph . name } </ b > { " " }
90
- < div className = "text-xs inline font-mono ml-4" > { graph . id } </ div >
91
- </ Combobox . Option >
92
- ) ) }
93
- </ Combobox . Options >
102
+ setSelectedGraph ( v ) ;
103
+ } }
104
+ value = { selectedGraph }
105
+ >
106
+ < div className = "relative" >
107
+ < Combobox . Input
108
+ onChange = { ( event ) => setQuery ( event . target . value ) }
109
+ className = "w-full p-4 rounded-lg shadow-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent font-bold dark:bg-gray-900 dark:text-gray-200"
110
+ placeholder = "Start typing or press the down arrow to choose a host graph..."
111
+ displayValue = { ( graph : HostListing ) => graph ?. name }
112
+ />
113
+ { /* Show indicator for uploaded graphs */ }
114
+ { selectedGraph && ! data . hosts . some ( ( host ) => host . id === selectedGraph . id ) && (
115
+ < div className = "absolute right-3 top-1/2 transform -translate-y-1/2" >
116
+ < span className = "inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200" >
117
+ Uploaded
118
+ </ span >
119
+ </ div >
120
+ ) }
121
+ < Combobox . Options className = "p-3 rounded-lg shadow-lg border overflow-y-scroll max-h-64 absolute w-full z-10 bg-white dark:bg-gray-800" >
122
+ { filteredGraphs . map ( ( graph ) => (
123
+ < Combobox . Option
124
+ key = { graph . id }
125
+ value = { graph }
126
+ className = { ( { active } ) => `${
127
+ active
128
+ ? "text-white bg-blue-400 dark:bg-blue-400 dark:text-white"
129
+ : "text-gray-900 dark:text-gray-200"
130
+ }
131
+ cursor-default select-none relative py-2 pl-10 pr-4 hover:bg-blue-400 hover:text-white flex items-center justify-between text-sm
132
+ ` }
133
+ >
134
+ < b className = "font-bold" > { graph . name } </ b > { " " }
135
+ < div className = "text-xs inline font-mono ml-4" > { graph . id } </ div >
136
+ </ Combobox . Option >
137
+ ) ) }
138
+ </ Combobox . Options >
139
+ </ div >
140
+ </ Combobox >
141
+ </ div >
94
142
</ div >
95
- </ Combobox >
96
- </ div >
97
- </ div >
143
+ </ Tab . Panel >
144
+ < Tab . Panel className = "rounded-xl bg-white/5 p-3" >
145
+ < GraphUpload onGraphUploaded = { handleGraphUploaded } />
146
+ </ Tab . Panel >
147
+ </ Tab . Panels >
148
+ </ Tab . Group >
98
149
</ div >
99
150
) ;
100
151
}
0 commit comments