DataGrid - initial commit

This commit is contained in:
2026-06-11 18:21:15 +02:00
parent fdab7cd362
commit 2fc4648515
27 changed files with 1813 additions and 648 deletions

View File

@@ -8,6 +8,8 @@ import FormField from "../../components/FormField";
import LoadingFrame from "../../components/LoadingFrame";
import PageTitle from "../../components/PageTitle";
import StatusBadge from "../../components/StatusBadge";
import DismissibleAlert from "../../components/DismissibleAlert";
import DataGrid, { type DataGridColumn } from "../../components/table/DataGrid";
import { publishCampaignVersion, updateCampaignMetadata, type CampaignVersionListItem } from "../../api/campaigns";
import { useCampaignWorkspaceData } from "./hooks/useCampaignWorkspaceData";
import { canUnlockValidationVersion, formatDateTime, isFinalLockedVersion, isUserLockedVersion, isVersionReadyForDelivery, summaryValue } from "./utils/campaignView";
@@ -94,8 +96,8 @@ export default function CampaignOverviewPage({ settings, campaignId }: { setting
</div>
</div>
{error && <div className="alert danger">{error}</div>}
{message && <div className="alert success">{message}</div>}
{error && <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert>}
{message && <DismissibleAlert tone="success" resetKey={message}>{message}</DismissibleAlert>}
<LoadingFrame loading={loading} label="Loading campaign overview…">
<Card title="Campaign identity">
@@ -118,48 +120,15 @@ export default function CampaignOverviewPage({ settings, campaignId }: { setting
</Card>
<Card title="Version history">
<div className="app-table-wrap">
<table className="app-table version-history-table">
<thead>
<tr>
<th>Version</th>
<th>State</th>
<th>Lock</th>
<th>Validation</th>
<th>Build</th>
<th>Updated</th>
<th aria-label="Actions"></th>
</tr>
</thead>
<tbody>
{versions.length === 0 && (
<tr><td colSpan={7} className="muted">No versions found.</td></tr>
)}
{versions.map((version) => {
const isCurrentVersion = version.id === data.currentVersion?.id;
return (
<tr key={version.id} className={isCurrentVersion ? "current-version-row" : undefined}>
<td>#{version.version_number}</td>
<td><StatusBadge status={version.workflow_state ?? "editing"} /></td>
<td>{versionLockLabel(version)}</td>
<td>{validationLabel(version)}</td>
<td>{buildLabel(version)}</td>
<td>{formatDateTime(version.updated_at)}</td>
<td className="table-action-cell">
<div className="button-row compact-actions">
<Link to={`review?version=${version.id}`}><Button variant="primary">Open</Button></Link>
<Button
onClick={() => setLockingVersion(version)}
disabled={isUserLockedVersion(version) || isFinalLockedVersion(version) || canUnlockValidationVersion(version)}
>Lock</Button>
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
<DataGrid
id={`campaign-${campaignId}-versions`}
rows={versions}
columns={versionColumns(setLockingVersion)}
getRowKey={(version) => version.id}
emptyText="No versions found."
className="version-history-table"
rowClassName={(version) => version.id === data.currentVersion?.id ? "current-version-row" : undefined}
/>
</Card>
<Card title="Current version state">
@@ -186,6 +155,32 @@ export default function CampaignOverviewPage({ settings, campaignId }: { setting
);
}
function versionColumns(setLockingVersion: (version: CampaignVersionListItem) => void): DataGridColumn<CampaignVersionListItem>[] {
return [
{ id: "version", header: "Version", width: 110, sortable: true, filterable: true, sticky: "start", render: (version) => `#${version.version_number}`, value: (version) => version.version_number ?? 0 },
{ id: "state", header: "State", width: 140, sortable: true, filterable: true, render: (version) => <StatusBadge status={version.workflow_state ?? "editing"} />, value: (version) => version.workflow_state ?? "editing" },
{ id: "lock", header: "Lock", width: 170, sortable: true, filterable: true, render: versionLockLabel, value: versionLockLabel },
{ id: "validation", header: "Validation", width: 170, sortable: true, filterable: true, render: validationLabel, value: validationLabel },
{ id: "build", header: "Build", width: 140, sortable: true, filterable: true, render: buildLabel, value: buildLabel },
{ id: "updated", header: "Updated", width: 190, sortable: true, filterable: true, render: (version) => formatDateTime(version.updated_at), value: (version) => version.updated_at ?? "" },
{
id: "actions",
header: "Actions",
width: 190,
sticky: "end",
render: (version) => (
<div className="button-row compact-actions">
<Link to={`send?version=${version.id}`}><Button variant="primary">Open</Button></Link>
<Button
onClick={() => setLockingVersion(version)}
disabled={isUserLockedVersion(version) || isFinalLockedVersion(version) || canUnlockValidationVersion(version)}
>Lock</Button>
</div>
)
}
];
}
function versionLockLabel(version: CampaignVersionListItem): string {
if (isUserLockedVersion(version)) return "User locked";
if (isFinalLockedVersion(version)) return "Final";