Skip to content

Commit 214528a

Browse files
authored
feat: Add graph uploads, wth expiry (#47)
* feat: Add graph uploads, wth expiry * feat: Working graph uploads
1 parent 51d8738 commit 214528a

File tree

12 files changed

+989
-42
lines changed

12 files changed

+989
-42
lines changed

motifstudio-web/src/app/GraphForm.tsx

Lines changed: 91 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"use client";
22
import { useState, useEffect } from "react";
3-
import { Combobox } from "@headlessui/react";
3+
import { Combobox, Tab } from "@headlessui/react";
44
import useSWR from "swr";
55
import { DatabaseIcon } from "./DatabaseIcon";
66
import { HostListing, fetcher, BASE_URL } from "./api";
77
import { useClientOnly } from "./hooks/useClientOnly";
8+
import { GraphUpload } from "./GraphUpload";
89

910
/**
1011
* Dropdown to select a host graph from a list of available graphs.
@@ -25,13 +26,22 @@ export function GraphForm({
2526
const { data, error, isLoading } = useSWR<{ hosts: HostListing[] }>(`${BASE_URL}/providers/hostlist`, fetcher);
2627
const [selectedGraph, setSelectedGraph] = useState<HostListing | undefined>(startValue);
2728
const [query, setQuery] = useState("");
29+
const [selectedTab, setSelectedTab] = useState(0);
2830
const isClient = useClientOnly();
2931

3032
// Update selectedGraph when startValue changes
3133
useEffect(() => {
3234
setSelectedGraph(startValue);
3335
}, [startValue]);
3436

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+
3545
// Simple loading/error handling.
3646
// Note that if the host cannot be reached, this is likely the first place
3747
// that the user will see an error message.
@@ -53,48 +63,89 @@ export function GraphForm({
5363
<h2 className="text-xl font-mono">Host Graph</h2>
5464
<hr className="my-2" />
5565

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+
}
6887
>
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);
85101
}
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>
94142
</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>
98149
</div>
99150
);
100151
}

0 commit comments

Comments
 (0)