diff --git a/docker-compose.yml b/docker-compose.yml index d551e1f..c644cf2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: git \ ca-certificates rm -rf /var/lib/apt/lists/* + git config set advice.defaultBranchName false if [ -f /apps/package.json ] && [ -d /apps/.git ]; then cd /apps git reset --hard @@ -38,9 +39,10 @@ services: git fetch origin main git checkout -B main origin/main fi - npm install + npm install --include=dev npm run build - npm run start + npm prune --omit=dev + node server/index.js volumes: - dcm_data:/apps/data @@ -54,4 +56,4 @@ volumes: networks: dcm_internal: driver: overlay - attachable: true \ No newline at end of file + attachable: true diff --git a/src/App.tsx b/src/App.tsx index 3f42c3f..1eb209f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1314,59 +1314,61 @@ function RackView({ const rackHeight = rack.sizeU * RACK_ROW_HEIGHT; const horizontalEquipment = rack.equipment.filter((item) => !(item.type === 'pdu' && item.pduMount === 'vertical')); const verticalPdus = rack.equipment.filter((item) => item.type === 'pdu' && item.pduMount === 'vertical'); + const totalWatts = rack.equipment.reduce((sum, item) => sum + item.powerWatts, 0); + const locationDisplay = [rack.locationArea, rack.locationRow, rack.locationColumn].filter(Boolean).join(' / ') || 'Unassigned'; return ( - - selected?.kind === 'rack' && selected.rackId === rack.id - ? 'primary.main' - : theme.palette.mode === 'dark' - ? 'rgba(97, 255, 207, 0.16)' - : 'rgba(0, 108, 95, 0.24)', - bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(3, 8, 9, 0.72)' : 'rgba(238, 244, 236, 0.96)'), - borderRadius: 1, - boxShadow: (theme) => - selected?.kind === 'rack' && selected.rackId === rack.id - ? theme.palette.mode === 'dark' - ? '0 0 34px rgba(97, 255, 207, 0.2), 0 18px 40px rgba(0, 0, 0, 0.32)' - : '0 0 0 1px rgba(0, 108, 95, 0.18), 0 16px 34px rgba(23, 38, 33, 0.18)' - : theme.palette.mode === 'dark' - ? '0 18px 40px rgba(0, 0, 0, 0.24)' - : '0 14px 28px rgba(23, 38, 33, 0.14)', - clipPath: 'polygon(0 0, 96% 0, 100% 12px, 100% 100%, 4% 100%, 0 calc(100% - 12px))', - }} - > - + (theme.palette.mode === 'dark' ? 'rgba(9, 20, 20, 0.78)' : 'rgba(218, 232, 220, 0.96)'), - borderBottom: 1, - borderColor: 'divider', - backgroundImage: (theme) => - theme.palette.mode === 'dark' - ? 'linear-gradient(90deg, rgba(97, 255, 207, 0.12), rgba(240, 184, 77, 0.04))' - : 'linear-gradient(90deg, rgba(0, 108, 95, 0.12), rgba(156, 92, 12, 0.07))', + width: '100%', + overflow: 'hidden', + borderColor: (theme) => + selected?.kind === 'rack' && selected.rackId === rack.id + ? 'primary.main' + : theme.palette.mode === 'dark' + ? 'rgba(97, 255, 207, 0.16)' + : 'rgba(0, 108, 95, 0.24)', + bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(3, 8, 9, 0.72)' : 'rgba(238, 244, 236, 0.96)'), + borderRadius: 1, + boxShadow: (theme) => + selected?.kind === 'rack' && selected.rackId === rack.id + ? theme.palette.mode === 'dark' + ? '0 0 34px rgba(97, 255, 207, 0.2), 0 18px 40px rgba(0, 0, 0, 0.32)' + : '0 0 0 1px rgba(0, 108, 95, 0.18), 0 16px 34px rgba(23, 38, 33, 0.18)' + : theme.palette.mode === 'dark' + ? '0 18px 40px rgba(0, 0, 0, 0.24)' + : '0 14px 28px rgba(23, 38, 33, 0.14)', + clipPath: 'polygon(0 0, 96% 0, 100% 12px, 100% 100%, 4% 100%, 0 calc(100% - 12px))', }} > - - - - {rack.name} - - - {rack.sizeU}U {rack.type} - - - 85 ? 'warning' : 'default'} /> - - - + (theme.palette.mode === 'dark' ? 'rgba(9, 20, 20, 0.78)' : 'rgba(218, 232, 220, 0.96)'), + borderBottom: 1, + borderColor: 'divider', + backgroundImage: (theme) => + theme.palette.mode === 'dark' + ? 'linear-gradient(90deg, rgba(97, 255, 207, 0.12), rgba(240, 184, 77, 0.04))' + : 'linear-gradient(90deg, rgba(0, 108, 95, 0.12), rgba(156, 92, 12, 0.07))', + }} + > + + + + {rack.name} + + + {rack.sizeU}U {rack.type} + + + 85 ? 'warning' : 'default'} /> + + + + + selected?.kind === 'rack' && selected.rackId === rack.id + ? 'primary.main' + : theme.palette.mode === 'dark' + ? 'rgba(97, 255, 207, 0.18)' + : 'rgba(0, 108, 95, 0.24)', + bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'rgba(7, 17, 16, 0.72)' : 'rgba(244, 249, 241, 0.9)'), + backgroundImage: (theme) => + theme.palette.mode === 'dark' + ? 'linear-gradient(135deg, rgba(97, 255, 207, 0.08), rgba(240, 184, 77, 0.04))' + : 'linear-gradient(135deg, rgba(0, 108, 95, 0.08), rgba(156, 92, 12, 0.05))', + boxShadow: (theme) => + theme.palette.mode === 'dark' + ? '0 12px 28px rgba(0, 0, 0, 0.24), inset 0 1px 0 rgba(255, 255, 255, 0.05)' + : '0 10px 22px rgba(23, 38, 33, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.65)', + }} + > + + + + Location + + + {locationDisplay} + + + + + Total Watts + + + {totalWatts.toLocaleString()} W + + + + + ); } @@ -1654,7 +1700,41 @@ function PropertiesPanel({ /> onRackChange(selectedRack.id, { manufacturer: event.target.value })} fullWidth /> onRackChange(selectedRack.id, { model: event.target.value })} fullWidth /> - onRackChange(selectedRack.id, { location: event.target.value })} fullWidth /> + + + onRackChange(selectedRack.id, { + locationArea: event.target.value, + location: [event.target.value, selectedRack.locationRow, selectedRack.locationColumn].filter(Boolean).join('/'), + }) + } + fullWidth + /> + + onRackChange(selectedRack.id, { + locationRow: event.target.value, + location: [selectedRack.locationArea, event.target.value, selectedRack.locationColumn].filter(Boolean).join('/'), + }) + } + fullWidth + /> + + onRackChange(selectedRack.id, { + locationColumn: event.target.value, + location: [selectedRack.locationArea, selectedRack.locationRow, event.target.value].filter(Boolean).join('/'), + }) + } + fullWidth + /> + onRackChange(selectedRack.id, { notes: event.target.value })} multiline minRows={3} fullWidth />