Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,66 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { availableNavigation } from "../navigation";
|
||||
import { Icon } from "./Icon";
|
||||
import { Modal } from "./Modal";
|
||||
|
||||
export function CommandMenu({
|
||||
open,
|
||||
canReadAudit,
|
||||
navigate,
|
||||
onClose,
|
||||
}: {
|
||||
open: boolean;
|
||||
canReadAudit: boolean;
|
||||
navigate: (next: string) => void;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const [query, setQuery] = useState("");
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const items = useMemo(() => availableNavigation(canReadAudit), [canReadAudit]);
|
||||
const results = useMemo(() => {
|
||||
const needle = query.trim().toLowerCase();
|
||||
if (!needle) return items;
|
||||
return items.filter((item) => `${item.label} ${item.description}`.toLowerCase().includes(needle));
|
||||
}, [items, query]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setQuery("");
|
||||
const focusTimer = window.setTimeout(() => inputRef.current?.focus(), 0);
|
||||
return () => window.clearTimeout(focusTimer);
|
||||
}, [open]);
|
||||
|
||||
const select = (href: string) => {
|
||||
onClose();
|
||||
navigate(href);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open={open} title="Quick jump" onClose={onClose} className="command-modal">
|
||||
<label className="command-search">
|
||||
<span className="sr-only">Find a workspace</span>
|
||||
<Icon name="search" size={17} />
|
||||
<input
|
||||
ref={inputRef}
|
||||
value={query}
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
placeholder="Find projects, catalog, policies…"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<kbd>Esc</kbd>
|
||||
</label>
|
||||
<div className="command-results" aria-live="polite">
|
||||
{results.length ? results.map((item) => (
|
||||
<button type="button" className="command-result" key={item.href} onClick={() => select(item.href)}>
|
||||
<span className="command-result-icon"><Icon name={item.icon} /></span>
|
||||
<span><strong>{item.label}</strong><small>{item.description}</small></span>
|
||||
<Icon name="arrow" size={16} />
|
||||
</button>
|
||||
)) : (
|
||||
<div className="command-empty"><strong>No workspace found</strong><span>Try a broader name or capability.</span></div>
|
||||
)}
|
||||
</div>
|
||||
<p className="command-hint">Navigate without leaving the keyboard. Access-controlled destinations remain hidden.</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user