diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9ee939c..c0c1708 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,7 @@ This file is the running release and change log for CODEXIUM. Keep it updated wh
- Continued density standardization across the SKU master builder and planning workbench, including tighter tree and board panels, denser exception and focus surfaces, shorter empty states, and less helper copy on those operational screens
- Continued density standardization across warehouse list/detail/editor screens and the manufacturing station surface, including tighter status blocks, denser location/station cards, and removal of older roomy header patterns
- Continued density standardization across company settings and deeper manufacturing detail surfaces, including tighter admin/profile/theme sections, denser work-order execution panels, and compact issue/completion history cards
+- Continued density standardization across project cockpit/detail internals, including tighter cockpit cards, denser purchasing and readiness panels, and compact milestone, manufacturing-link, and activity-timeline surfaces
- Project-side milestone and work-order rollups surfaced on project list and detail pages
- Inventory SKU master builder with family-level sequence codes, branch-aware taxonomy management, and generated SKU previews on the item form
- Thumbnail image attachment staging on inventory item create/edit pages, with upload-on-save and replacement/removal support
diff --git a/client/src/modules/projects/ProjectDetailPage.tsx b/client/src/modules/projects/ProjectDetailPage.tsx
index 2df7b6b..386171f 100644
--- a/client/src/modules/projects/ProjectDetailPage.tsx
+++ b/client/src/modules/projects/ProjectDetailPage.tsx
@@ -51,7 +51,7 @@ export function ProjectDetailPage() {
}, [projectId, token]);
if (!project) {
- return
{status}
;
+ return {status}
;
}
const sortedMilestones = [...project.milestones].sort((left, right) => {
@@ -172,16 +172,16 @@ export function ProjectDetailPage() {
- Customer
{project.customerName}
- Owner
{project.ownerName || "Unassigned"}
- Due Date
{project.dueDate ? new Date(project.dueDate).toLocaleDateString() : "Not set"}
- Created
{new Date(project.createdAt).toLocaleDateString()}
+ Customer
{project.customerName}
+ Owner
{project.ownerName || "Unassigned"}
+ Due Date
{project.dueDate ? new Date(project.dueDate).toLocaleDateString() : "Not set"}
+ Created
{new Date(project.createdAt).toLocaleDateString()}
- Milestones
{project.rollups.completedMilestoneCount}/{project.rollups.milestoneCount}
{project.rollups.openMilestoneCount} open
- Overdue Milestones
{project.rollups.overdueMilestoneCount}
- Linked Work Orders
{project.rollups.workOrderCount}
{project.rollups.activeWorkOrderCount} active
- Overdue Work Orders
{project.rollups.overdueWorkOrderCount}
{project.rollups.completedWorkOrderCount} complete
+ Milestones
{project.rollups.completedMilestoneCount}/{project.rollups.milestoneCount}
{project.rollups.openMilestoneCount} open
+ Overdue Milestones
{project.rollups.overdueMilestoneCount}
+ Linked Work Orders
{project.rollups.workOrderCount}
{project.rollups.activeWorkOrderCount} active
+ Overdue Work Orders
{project.rollups.overdueWorkOrderCount}
{project.rollups.completedWorkOrderCount} complete
@@ -284,88 +284,88 @@ export function ProjectDetailPage() {
{project.salesOrderId ?
Open purchasing : null}
{project.cockpit.purchasing.purchaseOrders.length === 0 ?
No linked purchase orders are tied to this project yet.
:
{project.cockpit.purchasing.purchaseOrders.slice(0, 5).map((purchaseOrder) => (
{purchaseOrder.documentNumber}
{purchaseOrder.vendorName} - {purchaseOrder.status.replaceAll("_", " ")}
${purchaseOrder.linkedLineValue.toFixed(2)} linked value
{purchaseOrder.totalReceivedQuantity}/{purchaseOrder.totalOrderedQuantity} received
))}
}
-
- Readiness Drivers
-
-
Risk posture
{project.cockpit.risk.riskLevel}
{project.cockpit.risk.outstandingPurchaseOrderCount} PO(s) still waiting on receipts.
-
Blocked milestones: {project.cockpit.risk.blockedMilestoneCount}
-
Overdue execution items: {project.cockpit.risk.overdueMilestoneCount + project.cockpit.risk.overdueWorkOrderCount}
-
Uncovered material quantity: {project.cockpit.risk.totalUncoveredQuantity}
+
+ READINESS DRIVERS
+
+
Risk posture
{project.cockpit.risk.riskLevel}
{project.cockpit.risk.outstandingPurchaseOrderCount} PO(s) still waiting on receipts.
+
Blocked milestones: {project.cockpit.risk.blockedMilestoneCount}
+
Overdue execution items: {project.cockpit.risk.overdueMilestoneCount + project.cockpit.risk.overdueWorkOrderCount}
+
Uncovered material quantity: {project.cockpit.risk.totalUncoveredQuantity}
-
- Vendor Exposure
- {project.cockpit.purchasing.vendors.length === 0 ? No supplier exposure exists until purchasing is linked.
: {project.cockpit.purchasing.vendors.slice(0, 4).map((vendor) => (
{vendor.vendorName}
{vendor.orderCount} linked order(s)
${vendor.linkedLineValue.toFixed(2)}
{vendor.outstandingQuantity} outstanding qty
))}
}
+
+ VENDOR EXPOSURE
+ {project.cockpit.purchasing.vendors.length === 0 ? No supplier exposure exists until purchasing is linked.
: {project.cockpit.purchasing.vendors.slice(0, 4).map((vendor) => (
{vendor.vendorName}
{vendor.orderCount} linked order(s)
${vendor.linkedLineValue.toFixed(2)}
{vendor.outstandingQuantity} outstanding qty
))}
}
-
- Recent Receipts
- {project.cockpit.purchasing.recentReceipts.length === 0 ? No purchase receipts have been posted against linked project supply.
: {project.cockpit.purchasing.recentReceipts.map((receipt) => (
{receipt.receiptNumber}
{receipt.vendorName} - {receipt.purchaseOrderNumber}
{new Date(receipt.receivedAt).toLocaleDateString()}
{receipt.totalQuantity} units received
))}
}
+
+ RECENT RECEIPTS
+ {project.cockpit.purchasing.recentReceipts.length === 0 ? No purchase receipts have been posted against linked project supply.
: {project.cockpit.purchasing.recentReceipts.map((receipt) => (
{receipt.receiptNumber}
{receipt.vendorName} - {receipt.purchaseOrderNumber}
{new Date(receipt.receivedAt).toLocaleDateString()}
{receipt.totalQuantity} units received
))}
}
-
- Customer Linkage
-
+
+ CUSTOMER LINKAGE
+
Account {project.customerName}
Email {project.customerEmail}
Phone {project.customerPhone}
-
- Program Notes
+
+ PROGRAM NOTES
{project.notes || "No project notes recorded."}
-
- Commercial + Delivery Links
-
+
+ COMMERCIAL + DELIVERY LINKS
+
Quote
{project.salesQuoteNumber ? {project.salesQuoteNumber} : "Not linked"}
Sales Order
{project.salesOrderNumber ? {project.salesOrderNumber} : "Not linked"}
Shipment
{project.shipmentNumber ? {project.shipmentNumber} : "Not linked"}
-
+
-
Milestones
Track project checkpoints, blockers, and completion progress.
+
{canManage ?
Edit milestones : null}
- {project.milestones.length === 0 ? No milestones are defined for this project yet.
: {project.milestones.map((milestone) => (
{milestone.title}
{milestone.status.replace("_", " ")} Due {milestone.dueDate ? new Date(milestone.dueDate).toLocaleDateString() : "not scheduled"} {milestone.completedAt ? Completed {new Date(milestone.completedAt).toLocaleDateString()} : null}
{milestone.notes ?
{milestone.notes}
: null}
{canManage ?
{milestoneQuickActions(milestone.status).map((action) => ( void updateMilestoneStatus(milestone.id, action.status)} disabled={updatingMilestoneId === milestone.id} className="rounded-2xl border border-line/70 px-2 py-2 text-xs font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">{updatingMilestoneId === milestone.id ? "Saving..." : action.label} ))}
: null}
))}
}
+ {project.milestones.length === 0 ? No milestones are defined for this project yet.
: {project.milestones.map((milestone) => (
{milestone.title}
{milestone.status.replace("_", " ")} Due {milestone.dueDate ? new Date(milestone.dueDate).toLocaleDateString() : "not scheduled"} {milestone.completedAt ? Completed {new Date(milestone.completedAt).toLocaleDateString()} : null}
{milestone.notes ?
{milestone.notes}
: null}
{canManage ?
{milestoneQuickActions(milestone.status).map((action) => ( void updateMilestoneStatus(milestone.id, action.status)} disabled={updatingMilestoneId === milestone.id} className="rounded-2xl border border-line/70 px-2 py-2 text-xs font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">{updatingMilestoneId === milestone.id ? "Saving..." : action.label} ))}
: null}
))}
}
{planning ? (
-
- Material Readiness
-
-
Build Qty
{planning.summary.totalBuildQuantity}
-
Buy Qty
{planning.summary.totalPurchaseQuantity}
-
Uncovered Qty
{planning.summary.totalUncoveredQuantity}
-
Shortage Items
{planning.summary.uncoveredItemCount}
+
+ MATERIAL READINESS
+
+
Build Qty
{planning.summary.totalBuildQuantity}
+
Buy Qty
{planning.summary.totalPurchaseQuantity}
+
Uncovered Qty
{planning.summary.totalUncoveredQuantity}
+
Shortage Items
{planning.summary.uncoveredItemCount}
-
+
{planning.items.filter((item) => item.recommendedBuildQuantity > 0 || item.recommendedPurchaseQuantity > 0 || item.uncoveredQuantity > 0).slice(0, 8).map((item) => (
-
{item.itemSku}
{item.itemName}
Build {item.recommendedBuildQuantity} - Buy {item.recommendedPurchaseQuantity} - Uncovered {item.uncoveredQuantity}
+
{item.itemSku}
{item.itemName}
Build {item.recommendedBuildQuantity} - Buy {item.recommendedPurchaseQuantity} - Uncovered {item.uncoveredQuantity}
))}
) : null}
-
+
-
Manufacturing Links
Work orders already linked to this project.
+
{canManage ?
New work order : null}
- {workOrders.length === 0 ? No work orders are linked to this project yet.
: {workOrders.map((workOrder) => (
{workOrder.workOrderNumber}
{workOrder.itemSku} - {workOrder.completedQuantity}/{workOrder.quantity} complete
{workOrder.status.replace("_", " ")}
))}
}
+ {workOrders.length === 0 ? No work orders are linked to this project yet.
: {workOrders.map((workOrder) => (
{workOrder.workOrderNumber}
{workOrder.itemSku} - {workOrder.completedQuantity}/{workOrder.quantity} complete
{workOrder.status.replace("_", " ")}
))}
}
-
+
-
Activity Timeline
Chronological project, milestone, purchasing, manufacturing, sales, and shipping history.
+
{project.timeline.length === 0 ? (
- No timeline activity is available for this project yet.
+ No timeline activity is available for this project yet.
) : (
-
+
{project.timeline.map((entry) => (
-