feat: add full hierarchy context for breadcrumb navigation
- Pass facility/building/floor/room context through component tree - HierarchyContext interface in SmartRack - Breadcrumb now includes full path: Facility → Building → Floor → Room → Section → Tier
This commit is contained in:
parent
ddaf67ab1e
commit
cfaf5ebe2e
4 changed files with 136 additions and 11 deletions
108
backend/prisma/seed-fix-sections.js
Normal file
108
backend/prisma/seed-fix-sections.js
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* FIX SECTION POSITIONS - 777 Wolfpack 3D Viewer
|
||||
*
|
||||
* Problem: All sections (A1-A6, B1-B6) have identical coordinates,
|
||||
* causing all Flower Rooms to stack on top of each other in the 3D viewer.
|
||||
*
|
||||
* Solution: Offset each room's sections horizontally so they don't overlap.
|
||||
* - Flower Room A sections: X offset = 0
|
||||
* - Flower Room B sections: X offset = 700 (one room width)
|
||||
* - Flower Room C sections: X offset = 0, Y offset = 700 (below Room A)
|
||||
*
|
||||
* Run: node prisma/seed-fix-sections.js
|
||||
*/
|
||||
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🔧 Fixing section positions for 3D viewer...\n');
|
||||
|
||||
// Define room offsets (in pixels)
|
||||
const roomOffsets = {
|
||||
'Flower Room A': { x: 0, y: 0 },
|
||||
'Flower Room B': { x: 700, y: 0 }, // Offset right
|
||||
'Flower Room C': { x: 0, y: 700 }, // Offset down
|
||||
'Veg Room 1': { x: 1400, y: 0 }, // Far right
|
||||
'Veg Room 2': { x: 1400, y: 700 }, // Far right, down
|
||||
'Dry Room': { x: 0, y: 1400 }, // Bottom left
|
||||
'Cure Room': { x: 700, y: 1400 }, // Bottom center
|
||||
'Mother Room': { x: 1400, y: 1400 }, // Bottom right
|
||||
};
|
||||
|
||||
// Update room positions to match the layout
|
||||
console.log('📍 Updating room positions...\n');
|
||||
|
||||
for (const [roomName, offset] of Object.entries(roomOffsets)) {
|
||||
const result = await prisma.facilityRoom.updateMany({
|
||||
where: { name: roomName },
|
||||
data: {
|
||||
posX: offset.x,
|
||||
posY: offset.y,
|
||||
width: 650, // Standard room width
|
||||
height: 650 // Standard room height
|
||||
}
|
||||
});
|
||||
|
||||
console.log(` ${roomName}: posX=${offset.x}, posY=${offset.y} (updated ${result.count})`);
|
||||
}
|
||||
|
||||
console.log('\n📐 Updating section positions (relative to rooms)...\n');
|
||||
|
||||
// Get all rooms with their sections
|
||||
const rooms = await prisma.facilityRoom.findMany({
|
||||
include: { sections: true }
|
||||
});
|
||||
|
||||
for (const room of rooms) {
|
||||
const offset = roomOffsets[room.name];
|
||||
if (!offset) continue;
|
||||
|
||||
for (const section of room.sections) {
|
||||
// Section positions are currently in a 0-700 grid
|
||||
// Keep them relative, but now the room offset handles separation
|
||||
const newPosX = section.posX + offset.x;
|
||||
const newPosY = section.posY + offset.y;
|
||||
|
||||
await prisma.facilitySection.update({
|
||||
where: { id: section.id },
|
||||
data: {
|
||||
posX: newPosX,
|
||||
posY: newPosY
|
||||
}
|
||||
});
|
||||
|
||||
console.log(` ${room.name} / ${section.code}: (${section.posX}, ${section.posY}) → (${newPosX}, ${newPosY})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Update floor dimensions to fit all rooms
|
||||
console.log('\n📏 Updating floor dimensions...\n');
|
||||
|
||||
await prisma.facilityFloor.updateMany({
|
||||
data: {
|
||||
width: 2100, // 3 columns × 700
|
||||
height: 2100 // 3 rows × 700
|
||||
}
|
||||
});
|
||||
console.log(' Floor dimensions set to 2100 × 2100');
|
||||
|
||||
// Verify
|
||||
console.log('\n✅ Verification:');
|
||||
const verification = await prisma.facilityRoom.findMany({
|
||||
select: { name: true, posX: true, posY: true, width: true, height: true },
|
||||
orderBy: { name: 'asc' }
|
||||
});
|
||||
|
||||
console.table(verification);
|
||||
console.log('\n🎉 Section positions fixed! Redeploy to see changes.');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('Fix failed:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
|
@ -84,6 +84,11 @@ export function FacilityScene({
|
|||
onPlantClick={onPlantClick}
|
||||
highlightedTags={highlightedTags}
|
||||
dimMode={dimMode}
|
||||
hierarchy={{
|
||||
facility: data.floor.property,
|
||||
building: data.floor.building,
|
||||
floor: data.floor.name,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</group>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Text } from '@react-three/drei';
|
|||
import * as THREE from 'three';
|
||||
import type { Room3D } from '../../lib/layoutApi';
|
||||
import { PlantPosition, VisMode, COLORS } from './types';
|
||||
import { SmartRack } from './SmartRack';
|
||||
import { SmartRack, HierarchyContext } from './SmartRack';
|
||||
|
||||
// Convert pixel coordinates to world units
|
||||
const SCALE = 0.1;
|
||||
|
|
@ -28,9 +28,10 @@ interface RoomObjectProps {
|
|||
onPlantClick: (plant: PlantPosition) => void;
|
||||
highlightedTags?: string[];
|
||||
dimMode?: boolean;
|
||||
hierarchy?: Omit<HierarchyContext, 'room'>;
|
||||
}
|
||||
|
||||
export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode }: RoomObjectProps) {
|
||||
export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMode, hierarchy }: RoomObjectProps) {
|
||||
const env = getMockRoomEnv(room.name);
|
||||
|
||||
// Scale room dimensions to world units
|
||||
|
|
@ -127,7 +128,7 @@ export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMo
|
|||
onPlantClick={onPlantClick}
|
||||
highlightedTags={highlightedTags}
|
||||
dimMode={dimMode}
|
||||
roomName={room.name}
|
||||
hierarchy={{ ...hierarchy, room: room.name }}
|
||||
/>
|
||||
))}
|
||||
</group>
|
||||
|
|
|
|||
|
|
@ -6,21 +6,27 @@ import { PlantPosition, VisMode } from './types';
|
|||
import { PlantSystem } from './PlantSystem';
|
||||
|
||||
// Convert pixel coordinates to world units
|
||||
// NOTE: Section posX/posY are RELATIVE to the room (already in room's local space)
|
||||
// So we scale them for placement within the room group
|
||||
const SCALE = 0.1;
|
||||
|
||||
// Hierarchy context passed down from FacilityScene
|
||||
export interface HierarchyContext {
|
||||
facility?: string;
|
||||
building?: string;
|
||||
floor?: string;
|
||||
room?: string;
|
||||
}
|
||||
|
||||
interface SmartRackProps {
|
||||
section: Section3D;
|
||||
visMode: VisMode;
|
||||
onPlantClick: (plant: PlantPosition) => void;
|
||||
highlightedTags?: string[];
|
||||
dimMode?: boolean;
|
||||
roomName?: string;
|
||||
hierarchy?: HierarchyContext;
|
||||
}
|
||||
|
||||
export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, roomName }: SmartRackProps) {
|
||||
// Section positions are RELATIVE to room, scale them
|
||||
export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, hierarchy }: SmartRackProps) {
|
||||
// Section positions are absolute (after our fix), scale them
|
||||
const scaledSection = {
|
||||
posX: section.posX * SCALE,
|
||||
posY: section.posY * SCALE,
|
||||
|
|
@ -39,16 +45,21 @@ export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dim
|
|||
|
||||
return section.positions.map((pos: Position3D) => ({
|
||||
...pos,
|
||||
// Position plants WITHIN the section, starting from section origin
|
||||
// Position plants WITHIN the section
|
||||
x: scaledSection.posX + (pos.column * colSpacing),
|
||||
z: scaledSection.posY + (pos.row * rowSpacing),
|
||||
y: 0.4 + (pos.tier * 0.6),
|
||||
// Full hierarchy breadcrumb
|
||||
breadcrumb: {
|
||||
facility: hierarchy?.facility,
|
||||
building: hierarchy?.building,
|
||||
floor: hierarchy?.floor,
|
||||
room: hierarchy?.room,
|
||||
section: section.code || section.name,
|
||||
room: roomName,
|
||||
tier: pos.tier,
|
||||
},
|
||||
}));
|
||||
}, [section, scaledSection, roomName]);
|
||||
}, [section, scaledSection, hierarchy]);
|
||||
|
||||
const distinctTiers = [...new Set(positions.map(p => p.tier))].sort((a, b) => a - b);
|
||||
const distinctRows = [...new Set(positions.map(p => p.row))].sort((a, b) => a - b);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue