@ltm-blueverse/alpha-semantic-hub 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Database, Plug, CheckCircle2, AlertCircle, Loader2, FileText, Globe,
|
|
4
|
-
Boxes, Cloud, Server, Play,
|
|
4
|
+
Boxes, Cloud, Server, Play, KeyRound, Save, Trash2, Lock,
|
|
5
5
|
} from "lucide-react";
|
|
6
6
|
|
|
7
7
|
type ConnField = {
|
|
@@ -47,7 +47,8 @@ function nestedSet(obj: Record<string, unknown>, path: string, value: unknown) {
|
|
|
47
47
|
export function IngestWorkspace() {
|
|
48
48
|
const [categories, setCategories] = useState<Category[]>([]);
|
|
49
49
|
const [active, setActive] = useState<Connector | null>(null);
|
|
50
|
-
const [
|
|
50
|
+
const [activeCategory, setActiveCategory] = useState<string>("");
|
|
51
|
+
const [search, setSearch] = useState("");
|
|
51
52
|
const [credentials, setCredentials] = useState<Credential[]>([]);
|
|
52
53
|
const [credentialId, setCredentialId] = useState("");
|
|
53
54
|
const [values, setValues] = useState<FieldValues>({});
|
|
@@ -80,7 +81,9 @@ export function IngestWorkspace() {
|
|
|
80
81
|
fetch("/api/ingest/sources").then((r) => r.json()).then((d) => {
|
|
81
82
|
const cats: Category[] = d.categories ?? [];
|
|
82
83
|
setCategories(cats);
|
|
83
|
-
const
|
|
84
|
+
const firstCat = cats[0];
|
|
85
|
+
if (firstCat) setActiveCategory((c) => c || firstCat.category);
|
|
86
|
+
const first = firstCat?.connectors[0];
|
|
84
87
|
if (first) setActive(first);
|
|
85
88
|
}).catch(() => {});
|
|
86
89
|
loadCredentials();
|
|
@@ -89,7 +92,6 @@ export function IngestWorkspace() {
|
|
|
89
92
|
|
|
90
93
|
function selectConnector(c: Connector) {
|
|
91
94
|
setActive(c);
|
|
92
|
-
setPickerOpen(false);
|
|
93
95
|
setValues({});
|
|
94
96
|
setSourceRef("");
|
|
95
97
|
setValidation(null);
|
|
@@ -207,7 +209,6 @@ export function IngestWorkspace() {
|
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
|
|
210
|
-
const ActiveIcon = active ? (KIND_ICONS[active.kind] ?? Database) : Database;
|
|
211
212
|
const vaultForKind = credentials.filter((c) => c.id.startsWith(active?.kind ?? "___"));
|
|
212
213
|
|
|
213
214
|
return (
|
|
@@ -227,48 +228,72 @@ export function IngestWorkspace() {
|
|
|
227
228
|
</div>
|
|
228
229
|
</div>
|
|
229
230
|
|
|
230
|
-
{/* Connector
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
<
|
|
236
|
-
|
|
231
|
+
{/* Connector browser: category sidebar + searchable connector grid.
|
|
232
|
+
Deliberately NOT an absolutely-positioned dropdown — .ws-card sets
|
|
233
|
+
overflow:hidden, which clipped the overlay to one visible row. */}
|
|
234
|
+
<div className="ws-card" style={{ padding: 18, display: "flex", flexDirection: "column", gap: 14 }}>
|
|
235
|
+
<div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
|
|
236
|
+
<div className="ws-label" style={{ margin: 0 }}>Connector</div>
|
|
237
|
+
<input className="ws-input" style={{ flex: 1, minWidth: 200 }}
|
|
238
|
+
placeholder="Search connectors…" value={search}
|
|
239
|
+
onChange={(e) => setSearch(e.target.value)} />
|
|
240
|
+
<span style={{ fontSize: 12, color: "var(--ws-text-muted)" }}>
|
|
241
|
+
{search
|
|
242
|
+
? `${categories.flatMap((c) => c.connectors).filter((c) => c.label.toLowerCase().includes(search.toLowerCase())).length} match`
|
|
243
|
+
: `${categories.reduce((n, c) => n + c.connectors.length, 0)} total`}
|
|
237
244
|
</span>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
<div style={{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
{cat.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
{c.extra_dependency ? (
|
|
259
|
-
<span title={`Extra dependency: ${c.extra_dependency}`}
|
|
260
|
-
style={{ fontSize: 10, opacity: 0.6, color: "#c9a227" }}>dep</span>
|
|
261
|
-
) : null}
|
|
262
|
-
</button>
|
|
263
|
-
);
|
|
264
|
-
})}
|
|
265
|
-
</div>
|
|
266
|
-
))}
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
<div style={{ display: "grid", gridTemplateColumns: "230px 1fr", gap: 14, alignItems: "start" }}>
|
|
248
|
+
{/* Category sidebar — always visible, never clipped */}
|
|
249
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
|
250
|
+
{categories.map((cat) => {
|
|
251
|
+
const isActiveCat = !search && activeCategory === cat.category;
|
|
252
|
+
const matches = search
|
|
253
|
+
? cat.connectors.filter((c) => c.label.toLowerCase().includes(search.toLowerCase())).length
|
|
254
|
+
: cat.connectors.length;
|
|
255
|
+
if (search && matches === 0) return null;
|
|
256
|
+
return (
|
|
257
|
+
<button key={cat.category} className="ws-btn" data-active={isActiveCat}
|
|
258
|
+
onClick={() => { setActiveCategory(cat.category); setSearch(""); }}
|
|
259
|
+
style={{ justifyContent: "space-between", fontSize: 12.5 }}>
|
|
260
|
+
<span>{cat.category}</span>
|
|
261
|
+
<span style={{ opacity: 0.6, fontSize: 11 }}>{matches}</span>
|
|
262
|
+
</button>
|
|
263
|
+
);
|
|
264
|
+
})}
|
|
267
265
|
</div>
|
|
268
|
-
|
|
266
|
+
|
|
267
|
+
{/* Connector grid — shows the active category, or search results */}
|
|
268
|
+
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(215px, 1fr))", gap: 8 }}>
|
|
269
|
+
{(search
|
|
270
|
+
? categories.flatMap((c) => c.connectors)
|
|
271
|
+
.filter((c) => c.label.toLowerCase().includes(search.toLowerCase()))
|
|
272
|
+
: categories.find((c) => c.category === activeCategory)?.connectors ?? []
|
|
273
|
+
).map((c) => {
|
|
274
|
+
const Icon = KIND_ICONS[c.kind] ?? Database;
|
|
275
|
+
const isSel = active?.kind === c.kind;
|
|
276
|
+
return (
|
|
277
|
+
<button key={c.kind} className="ws-btn" data-active={isSel}
|
|
278
|
+
onClick={() => selectConnector(c)}
|
|
279
|
+
style={{ justifyContent: "flex-start", fontSize: 12.5, textAlign: "left" }}>
|
|
280
|
+
<Icon size={14} />
|
|
281
|
+
<span style={{ flex: 1 }}>{c.label}</span>
|
|
282
|
+
{c.extra_dependency ? (
|
|
283
|
+
<span title={`Needs: ${c.extra_dependency}`}
|
|
284
|
+
style={{ fontSize: 10, color: "#c9a227" }}>dep</span>
|
|
285
|
+
) : null}
|
|
286
|
+
</button>
|
|
287
|
+
);
|
|
288
|
+
})}
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
269
291
|
|
|
270
292
|
{active ? (
|
|
271
|
-
<div style={{
|
|
293
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 4, paddingTop: 10, borderTop: "1px solid var(--ws-border)" }}>
|
|
294
|
+
<div style={{ fontSize: 12.5, fontWeight: 700, color: "var(--ws-text)" }}>
|
|
295
|
+
Selected: {active.label}
|
|
296
|
+
</div>
|
|
272
297
|
{active.credential_hint ? (
|
|
273
298
|
<div className="ws-body" style={{ fontSize: 12 }}>
|
|
274
299
|
<KeyRound size={12} style={{ verticalAlign: -2, marginRight: 6 }} />
|
package/package.json
CHANGED