# Description of Changes Adds Editor source permanently available in the Sources list. Excludes it from the Pipelines list of available sources currently because it's not a real source on the backend, so attempting to connect to it causes an error. It'd be nice to extend in the future to be able to set up policies in the editor from the pipelines page, but this'll do for now.
92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { Chip, StatTile } from "@app/ui";
|
|
import type { SourceView } from "@portal/api/sources";
|
|
import { Sparkline } from "@portal/components/sources/Sparkline";
|
|
import { EDITOR_SOURCE_TYPE } from "@portal/components/sources/sourceTypes";
|
|
import "@portal/views/Sources.css";
|
|
|
|
interface SourceDetailPanelProps {
|
|
source: SourceView;
|
|
/** The 30-day daily series for the sparkline, fetched per source when expanded. */
|
|
docSeries: number[];
|
|
}
|
|
|
|
/**
|
|
* Expanded detail for a source row: its config (key/value), the documents it has
|
|
* fed into runs, and which policies reference it (a 0-reference source is called
|
|
* out as safe to delete).
|
|
*/
|
|
export function SourceDetailPanel({
|
|
source,
|
|
docSeries,
|
|
}: SourceDetailPanelProps) {
|
|
const { t } = useTranslation();
|
|
const isEditor = source.type === EDITOR_SOURCE_TYPE;
|
|
return (
|
|
<div className="portal-sources__detail">
|
|
{isEditor && (
|
|
<p className="portal-sources__muted">
|
|
{t("portal.sources.types.editor.description")}
|
|
</p>
|
|
)}
|
|
|
|
{source.config.length > 0 && (
|
|
<div className="portal-sources__stat-grid">
|
|
{source.config.map((row) => (
|
|
<StatTile key={row.label} label={row.label} value={row.value} />
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<div className="portal-sources__detail-section">
|
|
<span className="portal-sources__detail-heading">
|
|
{t("portal.sources.detail.usedBy")}
|
|
</span>
|
|
{source.referencingPolicies.length === 0 ? (
|
|
<p className="portal-sources__muted">
|
|
{t(
|
|
isEditor
|
|
? "portal.sources.types.editor.noPolicies"
|
|
: "portal.sources.detail.notReferenced",
|
|
)}
|
|
</p>
|
|
) : (
|
|
<div className="portal-sources__chips">
|
|
{source.referencingPolicies.map((policy) => (
|
|
<Chip key={policy.id} size="sm">
|
|
{policy.name}
|
|
</Chip>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="portal-sources__detail-section">
|
|
<span className="portal-sources__detail-heading">
|
|
{t("portal.sources.detail.documents")}
|
|
</span>
|
|
<div className="portal-sources__stat-grid">
|
|
<StatTile
|
|
label={t("portal.sources.detail.docsTotal")}
|
|
value={source.docsTotal.toLocaleString()}
|
|
/>
|
|
<StatTile
|
|
label={t("portal.sources.detail.docs24h")}
|
|
value={source.docs24h.toLocaleString()}
|
|
/>
|
|
<StatTile
|
|
label={t("portal.sources.detail.docs30d")}
|
|
value={source.docs30d.toLocaleString()}
|
|
/>
|
|
</div>
|
|
{docSeries.length > 0 && (
|
|
<Sparkline
|
|
data={docSeries}
|
|
ariaLabel={t("portal.sources.detail.docsTrend")}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|