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,96 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import type { ResourceKind, ResourcePage, ResourceRecord } from "../contracts";
|
||||
import { Modal } from "./Modal";
|
||||
import { StatusPill } from "./StatusPill";
|
||||
|
||||
export type Density = "comfortable" | "compact";
|
||||
export type ColumnKey = "name" | "status" | "project" | "summary" | "risk" | "decision" | "actions";
|
||||
|
||||
const ALL_COLUMNS: Record<ResourceKind, ColumnKey[]> = {
|
||||
projects: ["name", "status", "project", "summary"],
|
||||
servers: ["name", "status", "project", "summary"],
|
||||
tools: ["name", "status", "project", "summary", "risk", "actions"],
|
||||
connectors: ["name", "status", "project", "summary"],
|
||||
clients: ["name", "status", "project", "summary", "actions"],
|
||||
policies: ["name", "status", "project", "summary"],
|
||||
audit: ["name", "status", "project", "summary", "decision"],
|
||||
};
|
||||
|
||||
export function columnsFor(kind: ResourceKind): ColumnKey[] { return ALL_COLUMNS[kind]; }
|
||||
|
||||
export function DataTable({
|
||||
data, kind, density, visibleColumns, onClientAction, onConfig, onTest,
|
||||
}: {
|
||||
data: ResourcePage;
|
||||
kind: ResourceKind;
|
||||
density: Density;
|
||||
visibleColumns: ColumnKey[];
|
||||
onClientAction: (id: string, action: "disable" | "revoke") => void;
|
||||
onConfig: (id: string) => void;
|
||||
onTest: (row: ResourceRecord) => void;
|
||||
}) {
|
||||
const show = (column: ColumnKey) => visibleColumns.includes(column);
|
||||
const [confirmingAction, setConfirmingAction] = useState<{ id: string; action: "disable" | "revoke"; name: string } | null>(null);
|
||||
const actions = (row: ResourceRecord) => {
|
||||
if (kind === "clients" && show("actions")) return <div className="inline-actions"><button className="button button-small" onClick={() => setConfirmingAction({ id: row.id, action: "disable", name: row.name })} disabled={row.status !== "healthy"}>Disable</button><button className="button button-small button-danger" onClick={() => setConfirmingAction({ id: row.id, action: "revoke", name: row.name })} disabled={row.status === "unavailable"}>Revoke</button><button className="button button-small button-secondary" onClick={() => onConfig(row.id)}>Config</button></div>;
|
||||
if (kind === "tools" && show("actions")) return <div className="inline-actions"><button className="button button-small button-secondary" onClick={() => onTest(row)}>Readiness</button></div>;
|
||||
return null;
|
||||
};
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={`table-wrap desktop-data-table table-kind-${kind} density-${density}`} role="region" tabIndex={0} aria-label={`${kind} records table`}>
|
||||
<table>
|
||||
<caption className="sr-only">{kind} records</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
{show("name") && <th>Name</th>}
|
||||
{show("status") && <th>Status</th>}
|
||||
{show("project") && <th>Project</th>}
|
||||
{show("summary") && <th>Summary</th>}
|
||||
{kind === "tools" && show("risk") && <th>Risk</th>}
|
||||
{kind === "audit" && show("decision") && <th>Decision / trace</th>}
|
||||
{(kind === "clients" || kind === "tools") && show("actions") && <th>Actions</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.rows.map((row) => (
|
||||
<tr key={row.id}>
|
||||
{show("name") && <td><strong className="long-name">{row.name}</strong><small>{row.id}</small></td>}
|
||||
{show("status") && <td><StatusPill value={row.status} /></td>}
|
||||
{show("project") && <td>{row.project ?? "—"}</td>}
|
||||
{show("summary") && <td>{row.summary}</td>}
|
||||
{kind === "tools" && show("risk") && <td>{row.risk ?? "R0"}</td>}
|
||||
{kind === "audit" && show("decision") && <td>{row.decision ?? "unknown"}{row.traceId && <small>{row.traceId}</small>}</td>}
|
||||
{(kind === "clients" || kind === "tools") && show("actions") && <td>{actions(row)}</td>}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="mobile-record-list" aria-label={`${kind} records`}>
|
||||
{data.rows.map((row) => <article className="mobile-record" key={row.id}><div className="mobile-record-heading"><div><strong>{row.name}</strong><small>{row.id}</small></div>{show("status") && <StatusPill value={row.status} />}</div><dl>{show("project") && <><dt>Project</dt><dd>{row.project ?? "—"}</dd></>}{show("summary") && <><dt>Summary</dt><dd>{row.summary}</dd></>}{kind === "tools" && show("risk") && <><dt>Risk</dt><dd><span className="risk-label" title="Risk classification">{row.risk ?? "R0"}</span></dd></>}{kind === "audit" && show("decision") && <><dt>Decision / trace</dt><dd>{row.decision ?? "unknown"}{row.traceId && <small>{row.traceId}</small>}</dd></>}</dl>{actions(row)}</article>)}
|
||||
</div>
|
||||
<Modal
|
||||
open={confirmingAction !== null}
|
||||
title={`${confirmingAction?.action === "disable" ? "Disable" : "Revoke"} ${confirmingAction?.name}?`}
|
||||
onClose={() => setConfirmingAction(null)}
|
||||
>
|
||||
<p>This action is logged and takes effect immediately.</p>
|
||||
<div className="state-actions">
|
||||
<button
|
||||
className="button"
|
||||
data-testid="confirm-action"
|
||||
onClick={() => {
|
||||
if (!confirmingAction) return;
|
||||
onClientAction(confirmingAction.id, confirmingAction.action);
|
||||
setConfirmingAction(null);
|
||||
}}
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
<button className="button button-secondary" onClick={() => setConfirmingAction(null)}>Cancel</button>
|
||||
</div>
|
||||
</Modal>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user