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}
|
onPlantClick={onPlantClick}
|
||||||
highlightedTags={highlightedTags}
|
highlightedTags={highlightedTags}
|
||||||
dimMode={dimMode}
|
dimMode={dimMode}
|
||||||
|
hierarchy={{
|
||||||
|
facility: data.floor.property,
|
||||||
|
building: data.floor.building,
|
||||||
|
floor: data.floor.name,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { Text } from '@react-three/drei';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import type { Room3D } from '../../lib/layoutApi';
|
import type { Room3D } from '../../lib/layoutApi';
|
||||||
import { PlantPosition, VisMode, COLORS } from './types';
|
import { PlantPosition, VisMode, COLORS } from './types';
|
||||||
import { SmartRack } from './SmartRack';
|
import { SmartRack, HierarchyContext } from './SmartRack';
|
||||||
|
|
||||||
// Convert pixel coordinates to world units
|
// Convert pixel coordinates to world units
|
||||||
const SCALE = 0.1;
|
const SCALE = 0.1;
|
||||||
|
|
@ -28,9 +28,10 @@ interface RoomObjectProps {
|
||||||
onPlantClick: (plant: PlantPosition) => void;
|
onPlantClick: (plant: PlantPosition) => void;
|
||||||
highlightedTags?: string[];
|
highlightedTags?: string[];
|
||||||
dimMode?: boolean;
|
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);
|
const env = getMockRoomEnv(room.name);
|
||||||
|
|
||||||
// Scale room dimensions to world units
|
// Scale room dimensions to world units
|
||||||
|
|
@ -127,7 +128,7 @@ export function RoomObject({ room, visMode, onPlantClick, highlightedTags, dimMo
|
||||||
onPlantClick={onPlantClick}
|
onPlantClick={onPlantClick}
|
||||||
highlightedTags={highlightedTags}
|
highlightedTags={highlightedTags}
|
||||||
dimMode={dimMode}
|
dimMode={dimMode}
|
||||||
roomName={room.name}
|
hierarchy={{ ...hierarchy, room: room.name }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,27 @@ import { PlantPosition, VisMode } from './types';
|
||||||
import { PlantSystem } from './PlantSystem';
|
import { PlantSystem } from './PlantSystem';
|
||||||
|
|
||||||
// Convert pixel coordinates to world units
|
// 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;
|
const SCALE = 0.1;
|
||||||
|
|
||||||
|
// Hierarchy context passed down from FacilityScene
|
||||||
|
export interface HierarchyContext {
|
||||||
|
facility?: string;
|
||||||
|
building?: string;
|
||||||
|
floor?: string;
|
||||||
|
room?: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface SmartRackProps {
|
interface SmartRackProps {
|
||||||
section: Section3D;
|
section: Section3D;
|
||||||
visMode: VisMode;
|
visMode: VisMode;
|
||||||
onPlantClick: (plant: PlantPosition) => void;
|
onPlantClick: (plant: PlantPosition) => void;
|
||||||
highlightedTags?: string[];
|
highlightedTags?: string[];
|
||||||
dimMode?: boolean;
|
dimMode?: boolean;
|
||||||
roomName?: string;
|
hierarchy?: HierarchyContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, roomName }: SmartRackProps) {
|
export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dimMode, hierarchy }: SmartRackProps) {
|
||||||
// Section positions are RELATIVE to room, scale them
|
// Section positions are absolute (after our fix), scale them
|
||||||
const scaledSection = {
|
const scaledSection = {
|
||||||
posX: section.posX * SCALE,
|
posX: section.posX * SCALE,
|
||||||
posY: section.posY * SCALE,
|
posY: section.posY * SCALE,
|
||||||
|
|
@ -39,16 +45,21 @@ export function SmartRack({ section, visMode, onPlantClick, highlightedTags, dim
|
||||||
|
|
||||||
return section.positions.map((pos: Position3D) => ({
|
return section.positions.map((pos: Position3D) => ({
|
||||||
...pos,
|
...pos,
|
||||||
// Position plants WITHIN the section, starting from section origin
|
// Position plants WITHIN the section
|
||||||
x: scaledSection.posX + (pos.column * colSpacing),
|
x: scaledSection.posX + (pos.column * colSpacing),
|
||||||
z: scaledSection.posY + (pos.row * rowSpacing),
|
z: scaledSection.posY + (pos.row * rowSpacing),
|
||||||
y: 0.4 + (pos.tier * 0.6),
|
y: 0.4 + (pos.tier * 0.6),
|
||||||
|
// Full hierarchy breadcrumb
|
||||||
breadcrumb: {
|
breadcrumb: {
|
||||||
|
facility: hierarchy?.facility,
|
||||||
|
building: hierarchy?.building,
|
||||||
|
floor: hierarchy?.floor,
|
||||||
|
room: hierarchy?.room,
|
||||||
section: section.code || section.name,
|
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 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);
|
const distinctRows = [...new Set(positions.map(p => p.row))].sort((a, b) => a - b);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue