data and layout cleanup

This commit is contained in:
2026-03-15 21:26:08 -05:00
parent ac0c6e4365
commit 8029b308e9
4 changed files with 19 additions and 160 deletions

View File

@@ -58,6 +58,7 @@ This file is the running release and change log for MRP Codex. Keep it updated w
### Changed ### Changed
- Fresh bootstrap now creates only minimal system records; operational domains no longer start with seeded demo customers, vendors, inventory, BOMs, or warehouses
- Sales and purchasing detail pages now expose revision comparison directly alongside chronological revision history - Sales and purchasing detail pages now expose revision comparison directly alongside chronological revision history
- `ROADMAP.md` now tracks remaining work only, and shipped phase history now lives in `SHIPPED.md` - `ROADMAP.md` now tracks remaining work only, and shipped phase history now lives in `SHIPPED.md`
- Support logs now prune retained entries by age instead of only trimming by count, and admin diagnostics now reviews filtered support-log summaries instead of an unbounded flat dump - Support logs now prune retained entries by age instead of only trimming by count, and admin diagnostics now reviews filtered support-log summaries instead of an unbounded flat dump

View File

@@ -230,8 +230,7 @@ The current inventory foundation supports:
- item on-hand quantity, stock-by-location balances, and recent stock history - item on-hand quantity, stock-by-location balances, and recent stock history
- reserved and available quantity visibility by location - reserved and available quantity visibility by location
- item-level file attachments for drawings and support documents - item-level file attachments for drawings and support documents
- seeded sample inventory items and a starter assembly BOM during bootstrap - fresh bootstrap starts inventory and warehouse data empty so first-run environments do not include demo operational records
- seeded sample warehouse and stock locations during bootstrap
QOL direction: QOL direction:

View File

@@ -48,6 +48,9 @@ export function GanttPage() {
const links = timeline?.links ?? []; const links = timeline?.links ?? [];
const summary = timeline?.summary; const summary = timeline?.summary;
const exceptions = timeline?.exceptions ?? []; const exceptions = timeline?.exceptions ?? [];
const ganttCellHeight = 44;
const ganttScaleHeight = 56;
const ganttHeight = Math.max(420, tasks.length * ganttCellHeight + ganttScaleHeight);
return ( return (
<section className="space-y-4"> <section className="space-y-4">
@@ -104,7 +107,7 @@ export function GanttPage() {
</section> </section>
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_360px]"> <div className="grid gap-3 xl:grid-cols-[minmax(0,1.2fr)_360px]">
<div <div
className={`gantt-theme overflow-auto rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5 ${ className={`gantt-theme overflow-x-auto overflow-y-visible rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5 ${
mode === "dark" ? "wx-willow-dark-theme" : "wx-willow-theme" mode === "dark" ? "wx-willow-dark-theme" : "wx-willow-theme"
}`} }`}
> >
@@ -119,15 +122,19 @@ export function GanttPage() {
{tasks.length} schedule rows {tasks.length} schedule rows
</div> </div>
</div> </div>
<Gantt <div style={{ height: `${ganttHeight}px`, minWidth: "100%" }}>
tasks={tasks.map((task: GanttTaskDto) => ({ <Gantt
...task, tasks={tasks.map((task: GanttTaskDto) => ({
start: new Date(task.start), ...task,
end: new Date(task.end), start: new Date(task.start),
parent: task.parentId ?? undefined, end: new Date(task.end),
}))} parent: task.parentId ?? undefined,
links={links} }))}
/> links={links}
cellHeight={ganttCellHeight}
scaleHeight={ganttScaleHeight}
/>
</div>
</div> </div>
<aside className="space-y-3"> <aside className="space-y-3">
<section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5"> <section className="rounded-[20px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">

View File

@@ -122,152 +122,4 @@ export async function bootstrapAppData() {
}, },
}); });
} }
if ((await prisma.customer.count()) === 0) {
await prisma.customer.createMany({
data: [
{
name: "Acme Components",
email: "buyer@acme.example",
phone: "555-0101",
addressLine1: "1 Industrial Road",
addressLine2: "",
city: "Detroit",
state: "MI",
postalCode: "48201",
country: "USA",
notes: "Priority account",
},
{
name: "Northwind Fabrication",
email: "ops@northwind.example",
phone: "555-0120",
addressLine1: "42 Assembly Ave",
addressLine2: "",
city: "Milwaukee",
state: "WI",
postalCode: "53202",
country: "USA",
notes: "Requires ASN notice",
},
],
});
}
if ((await prisma.vendor.count()) === 0) {
await prisma.vendor.create({
data: {
name: "SteelSource Supply",
email: "sales@steelsource.example",
phone: "555-0142",
addressLine1: "77 Mill Street",
addressLine2: "",
city: "Gary",
state: "IN",
postalCode: "46402",
country: "USA",
notes: "Lead time 5 business days",
},
});
}
if ((await prisma.inventoryItem.count()) === 0) {
const plate = await prisma.inventoryItem.create({
data: {
sku: "RM-PLATE-AL-125",
name: "Aluminum Plate 1/8in",
description: "Raw aluminum plate stock for fabricated assemblies.",
type: "PURCHASED",
status: "ACTIVE",
unitOfMeasure: "EA",
isSellable: false,
isPurchasable: true,
defaultCost: 42.5,
defaultPrice: null,
notes: "Primary sheet stock for enclosure fabrication.",
},
});
const fastener = await prisma.inventoryItem.create({
data: {
sku: "HW-SCREW-832",
name: "8-32 Socket Head Screw",
description: "Standard socket head cap screw for enclosure assemblies.",
type: "PURCHASED",
status: "ACTIVE",
unitOfMeasure: "EA",
isSellable: false,
isPurchasable: true,
defaultCost: 0.18,
defaultPrice: null,
notes: "Bulk hardware item.",
},
});
const assembly = await prisma.inventoryItem.create({
data: {
sku: "FG-CTRL-BASE",
name: "Control Base Assembly",
description: "Base enclosure assembly for standard control packages.",
type: "ASSEMBLY",
status: "ACTIVE",
unitOfMeasure: "EA",
isSellable: true,
isPurchasable: false,
defaultCost: 118,
defaultPrice: 249,
notes: "Starter BOM for the inventory foundation slice.",
},
});
await prisma.inventoryBomLine.createMany({
data: [
{
parentItemId: assembly.id,
componentItemId: plate.id,
quantity: 2,
unitOfMeasure: "EA",
notes: "Side panel blanks",
position: 10,
},
{
parentItemId: assembly.id,
componentItemId: fastener.id,
quantity: 12,
unitOfMeasure: "EA",
notes: "General assembly hardware",
position: 20,
},
],
});
}
if ((await prisma.warehouse.count()) === 0) {
await prisma.warehouse.create({
data: {
code: "MAIN",
name: "Main Warehouse",
notes: "Primary stocking location for finished goods and purchased materials.",
locations: {
create: [
{
code: "RECV",
name: "Receiving",
notes: "Initial inbound inspection and receipt staging.",
},
{
code: "STOCK-A1",
name: "Aisle A1",
notes: "General rack storage for standard material.",
},
{
code: "FG-STAGE",
name: "Finished Goods Staging",
notes: "Outbound-ready finished assemblies.",
},
],
},
},
});
}
} }