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 />
} onClick={onDelete}>
Delete rack
diff --git a/src/types.ts b/src/types.ts
index 728ed09..5246ab7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -93,6 +93,9 @@ export interface RackContainer {
manufacturer: string;
model: string;
location: string;
+ locationArea: string;
+ locationRow: string;
+ locationColumn: string;
notes: string;
equipment: Equipment[];
}
diff --git a/src/utils/model.ts b/src/utils/model.ts
index e0612cf..e827a1f 100644
--- a/src/utils/model.ts
+++ b/src/utils/model.ts
@@ -27,6 +27,9 @@ export const createRack = (type: 'rack' | 'cabinet', index: number, sizeU = 42):
manufacturer: '',
model: '',
location: '',
+ locationArea: '',
+ locationRow: '',
+ locationColumn: '',
notes: '',
equipment: [],
});
@@ -157,6 +160,9 @@ export const normalizeDiagram = (value: unknown): DiagramData => {
manufacturer: rack.manufacturer || '',
model: rack.model || '',
location: rack.location || '',
+ locationArea: rack.locationArea || rack.location || '',
+ locationRow: rack.locationRow || '',
+ locationColumn: rack.locationColumn || '',
notes: rack.notes || '',
equipment: Array.isArray(rack.equipment)
? rack.equipment.map((item, itemIndex) => {