2026-06-30 17:11:48 +01:00
|
|
|
import { useMemo } from "react";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
|
import {
|
2026-08-17 11:47:08 +00:00
|
|
|
column,
|
|
|
|
|
DataTable,
|
|
|
|
|
type DataTableColumn,
|
2026-06-30 17:11:48 +01:00
|
|
|
type StatusTone,
|
2026-07-03 14:20:02 +01:00
|
|
|
} from "@app/ui";
|
2026-09-02 16:08:15 +00:00
|
|
|
import { pipelineIcon } from "@portal/components/pipelines/pipelineIcon";
|
2026-06-30 17:11:48 +01:00
|
|
|
import type { PipelineStatus, PipelineView } from "@portal/api/pipelines";
|
|
|
|
|
|
|
|
|
|
const STATUS_TONE: Record<PipelineStatus, StatusTone> = {
|
|
|
|
|
active: "success",
|
|
|
|
|
paused: "neutral",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interface PipelinesTableProps {
|
|
|
|
|
pipelines: PipelineView[];
|
2026-07-08 16:23:04 +01:00
|
|
|
/** A row opens that pipeline's own page. */
|
2026-06-30 17:11:48 +01:00
|
|
|
onRowClick: (pipeline: PipelineView) => void;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-08 16:23:04 +01:00
|
|
|
export function PipelinesTable({ pipelines, onRowClick }: PipelinesTableProps) {
|
2026-06-30 17:11:48 +01:00
|
|
|
const { t } = useTranslation();
|
2026-08-17 11:47:08 +00:00
|
|
|
const columns = useMemo<DataTableColumn<PipelineView>[]>(
|
2026-06-30 17:11:48 +01:00
|
|
|
() => [
|
2026-08-17 11:47:08 +00:00
|
|
|
column.entity({
|
2026-06-30 17:11:48 +01:00
|
|
|
key: "name",
|
2026-07-03 14:20:02 +01:00
|
|
|
header: t("portal.pipelines.table.name"),
|
2026-08-17 11:47:08 +00:00
|
|
|
sortable: true,
|
2026-09-02 16:08:15 +00:00
|
|
|
icon: (p) => pipelineIcon(p.icon, "1.25rem"),
|
2026-08-17 11:47:08 +00:00
|
|
|
primary: (p) => p.name,
|
|
|
|
|
}),
|
2026-09-02 16:08:15 +00:00
|
|
|
column.text({
|
|
|
|
|
key: "type",
|
|
|
|
|
header: t("portal.pipelines.table.type", "Type"),
|
|
|
|
|
sortable: true,
|
|
|
|
|
get: (p) =>
|
|
|
|
|
p.required
|
|
|
|
|
? t("portal.pipelines.type.policy")
|
|
|
|
|
: t("portal.pipelines.type.pipeline"),
|
|
|
|
|
}),
|
2026-08-17 11:47:08 +00:00
|
|
|
column.text({
|
|
|
|
|
key: "trigger",
|
|
|
|
|
header: t("portal.pipelines.table.trigger", "Trigger"),
|
|
|
|
|
sortable: true,
|
|
|
|
|
get: (p) =>
|
|
|
|
|
t(`portal.pipelines.trigger.${p.trigger}`, {
|
|
|
|
|
defaultValue: p.trigger,
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
column.badge({
|
2026-06-30 17:11:48 +01:00
|
|
|
key: "status",
|
2026-07-03 14:20:02 +01:00
|
|
|
header: t("portal.pipelines.table.status"),
|
2026-08-17 11:47:08 +00:00
|
|
|
sortable: true,
|
|
|
|
|
get: (p) => ({
|
|
|
|
|
tone: STATUS_TONE[p.status],
|
|
|
|
|
label: t(`portal.pipelines.status.${p.status}`),
|
|
|
|
|
}),
|
|
|
|
|
}),
|
|
|
|
|
column.number({
|
2026-06-30 17:11:48 +01:00
|
|
|
key: "steps",
|
2026-07-03 14:20:02 +01:00
|
|
|
header: t("portal.pipelines.table.steps"),
|
2026-08-17 11:47:08 +00:00
|
|
|
sortable: true,
|
|
|
|
|
get: (p) => p.steps.length,
|
|
|
|
|
}),
|
|
|
|
|
column.number({
|
2026-06-30 17:11:48 +01:00
|
|
|
key: "sources",
|
2026-07-03 14:20:02 +01:00
|
|
|
header: t("portal.pipelines.table.sources"),
|
2026-08-17 11:47:08 +00:00
|
|
|
sortable: true,
|
|
|
|
|
get: (p) => p.sources.length,
|
|
|
|
|
}),
|
2026-06-30 17:11:48 +01:00
|
|
|
],
|
2026-07-08 16:23:04 +01:00
|
|
|
[t],
|
2026-06-30 17:11:48 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
2026-08-17 11:47:08 +00:00
|
|
|
<DataTable<PipelineView>
|
2026-06-30 17:11:48 +01:00
|
|
|
columns={columns}
|
|
|
|
|
rows={pipelines}
|
|
|
|
|
rowKey={(p) => p.id}
|
|
|
|
|
onRowClick={onRowClick}
|
2026-08-17 11:47:08 +00:00
|
|
|
rowAffordance="chevron"
|
2026-06-30 17:11:48 +01:00
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|