0d3cb498a3
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Waiting to run
Test and Publish Multi-arch Docker Image / test (push) Waiting to run
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Blocked by required conditions
Validate Renovate Config / Validate Renovate Configuration (push) Waiting to run
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
195 lines
6.8 KiB
TypeScript
195 lines
6.8 KiB
TypeScript
import React from 'react';
|
|
|
|
import { PLUGIN_CATEGORIES, PLUGINS } from './data/plugins';
|
|
import { getCategoryAnchor } from './utils/categoryUtils';
|
|
|
|
import type { Plugin, PluginCategory } from './data/plugins';
|
|
|
|
type GroupedPlugins = Record<PluginCategory, Plugin[]>;
|
|
|
|
interface PluginTableProps {
|
|
vulnerabilityType?: string;
|
|
shouldRenderCategory?: boolean;
|
|
shouldRenderDescription?: boolean;
|
|
shouldRenderPluginId?: boolean;
|
|
shouldGroupByCategory?: boolean;
|
|
showApplicationTypes?: boolean;
|
|
showRemoteStatus?: boolean;
|
|
}
|
|
|
|
const styles = {
|
|
table: {
|
|
width: '100%',
|
|
borderCollapse: 'collapse' as const,
|
|
tableLayout: 'fixed' as const,
|
|
},
|
|
th: {
|
|
padding: '12px 8px',
|
|
textAlign: 'left' as const,
|
|
whiteSpace: 'nowrap' as const,
|
|
borderBottom: '2px solid var(--ifm-table-border-color)',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
},
|
|
td: {
|
|
padding: '8px',
|
|
borderBottom: '1px solid var(--ifm-table-border-color)',
|
|
verticalAlign: 'top' as const,
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
},
|
|
// Column-specific widths
|
|
columns: {
|
|
category: { width: '15%', fontWeight: 'bold' },
|
|
name: { width: '20%', fontWeight: 'bold' },
|
|
description: { width: '40%', whiteSpace: 'normal' as const },
|
|
pluginId: { width: '15%' },
|
|
indicator: { width: '5%', textAlign: 'center' as const },
|
|
},
|
|
code: {
|
|
whiteSpace: 'nowrap' as const,
|
|
fontSize: '0.9em',
|
|
},
|
|
link: {
|
|
display: 'block',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
whiteSpace: 'nowrap' as const,
|
|
},
|
|
};
|
|
|
|
const PluginTable = ({
|
|
vulnerabilityType,
|
|
shouldRenderCategory = true,
|
|
shouldRenderDescription = true,
|
|
shouldRenderPluginId = true,
|
|
shouldGroupByCategory = false,
|
|
showApplicationTypes = false,
|
|
showRemoteStatus = false,
|
|
}: PluginTableProps) => {
|
|
let filteredPlugins = PLUGINS;
|
|
|
|
// Apply filters if specified
|
|
if (vulnerabilityType) {
|
|
filteredPlugins = filteredPlugins.filter(
|
|
(plugin) => plugin.vulnerabilityType === vulnerabilityType,
|
|
);
|
|
}
|
|
|
|
// Group plugins by category if needed
|
|
const groupedPlugins: GroupedPlugins = {} as GroupedPlugins;
|
|
if (shouldGroupByCategory) {
|
|
for (const category of PLUGIN_CATEGORIES) {
|
|
groupedPlugins[category] = filteredPlugins
|
|
.filter((plugin) => plugin.category === category)
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
}
|
|
|
|
return (
|
|
<table style={styles.table}>
|
|
<thead>
|
|
<tr>
|
|
{shouldRenderCategory && shouldGroupByCategory && (
|
|
<th style={{ ...styles.th, ...styles.columns.category }}>Category</th>
|
|
)}
|
|
<th style={{ ...styles.th, ...styles.columns.name }}>Plugin Name</th>
|
|
{shouldRenderDescription && (
|
|
<th style={{ ...styles.th, ...styles.columns.description }}>Description</th>
|
|
)}
|
|
{shouldRenderPluginId && (
|
|
<th style={{ ...styles.th, ...styles.columns.pluginId }}>Plugin ID</th>
|
|
)}
|
|
{showApplicationTypes && (
|
|
<>
|
|
<th style={{ ...styles.th, ...styles.columns.indicator }}>RAG</th>
|
|
<th style={{ ...styles.th, ...styles.columns.indicator }}>Agent</th>
|
|
<th style={{ ...styles.th, ...styles.columns.indicator }}>Chatbot</th>
|
|
</>
|
|
)}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{shouldGroupByCategory
|
|
? Object.entries(groupedPlugins).map(([category, categoryPlugins]) => (
|
|
<React.Fragment key={category}>
|
|
{categoryPlugins.map((plugin, index) => (
|
|
<tr key={plugin.pluginId}>
|
|
{index === 0 && shouldRenderCategory && (
|
|
<td
|
|
rowSpan={categoryPlugins.length}
|
|
style={{ ...styles.td, ...styles.columns.category }}
|
|
id={getCategoryAnchor(plugin.category).slice(1)}
|
|
>
|
|
{plugin.category}
|
|
</td>
|
|
)}
|
|
<td style={{ ...styles.td, ...styles.columns.name }}>
|
|
<a href={plugin.link} style={styles.link} title={plugin.name}>
|
|
{plugin.name}
|
|
</a>
|
|
</td>
|
|
{shouldRenderDescription && (
|
|
<td style={{ ...styles.td, ...styles.columns.description }}>
|
|
{plugin.description}
|
|
{showRemoteStatus && plugin.isRemote && (
|
|
<span title="Uses remote inference"> 🌐</span>
|
|
)}
|
|
</td>
|
|
)}
|
|
{shouldRenderPluginId && (
|
|
<td style={{ ...styles.td, ...styles.columns.pluginId }}>
|
|
<code style={styles.code}>{plugin.pluginId}</code>
|
|
</td>
|
|
)}
|
|
{showApplicationTypes && (
|
|
<>
|
|
<td style={{ ...styles.td, ...styles.columns.indicator }}>
|
|
{plugin.applicationTypes?.rag ? '🚨' : '✅'}
|
|
</td>
|
|
<td style={{ ...styles.td, ...styles.columns.indicator }}>
|
|
{plugin.applicationTypes?.agent ? '🚨' : '✅'}
|
|
</td>
|
|
<td style={{ ...styles.td, ...styles.columns.indicator }}>
|
|
{plugin.applicationTypes?.chat ? '🚨' : '✅'}
|
|
</td>
|
|
</>
|
|
)}
|
|
</tr>
|
|
))}
|
|
</React.Fragment>
|
|
))
|
|
: filteredPlugins.map((plugin) => (
|
|
<tr key={plugin.pluginId}>
|
|
<td style={styles.td}>
|
|
<a href={plugin.link}>{plugin.name}</a>
|
|
</td>
|
|
{shouldRenderDescription && (
|
|
<td style={styles.td}>
|
|
{plugin.description}
|
|
{showRemoteStatus && plugin.isRemote && (
|
|
<span title="Uses remote inference"> 🌐</span>
|
|
)}
|
|
</td>
|
|
)}
|
|
{shouldRenderPluginId && (
|
|
<td style={styles.td}>
|
|
<code style={styles.code}>{plugin.pluginId}</code>
|
|
</td>
|
|
)}
|
|
{showApplicationTypes && (
|
|
<>
|
|
<td style={styles.td}>{plugin.applicationTypes?.rag ? '🚨' : '✅'}</td>
|
|
<td style={styles.td}>{plugin.applicationTypes?.agent ? '🚨' : '✅'}</td>
|
|
<td style={styles.td}>{plugin.applicationTypes?.chat ? '🚨' : '✅'}</td>
|
|
</>
|
|
)}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
);
|
|
};
|
|
|
|
export default PluginTable;
|