Add cityID in creation and update and edit some graphics in the map

This commit is contained in:
2025-08-19 09:24:29 +03:00
parent 50c6a2ef5b
commit a14bc4e73a
5 changed files with 158 additions and 52 deletions

View File

@@ -45,6 +45,10 @@ export const getDataCenters = () => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -201,6 +205,10 @@ export const createDataCenter = (dataCenterData) => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -241,6 +249,7 @@ export const createDataCenter = (dataCenterData) => {
ayposURL: dataCenterData.ayposURL || "", ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1, number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId || null, areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "", address: dataCenterData.address || "",
latitude: dataCenterData.latitude latitude: dataCenterData.latitude
? parseFloat(dataCenterData.latitude) ? parseFloat(dataCenterData.latitude)
@@ -331,6 +340,10 @@ export const updateDataCenter = (id, dataCenterData) => {
name name
} }
} }
city {
id
name
}
emissionScope { emissionScope {
id id
tag tag
@@ -372,6 +385,7 @@ export const updateDataCenter = (id, dataCenterData) => {
ayposURL: dataCenterData.ayposURL || "", ayposURL: dataCenterData.ayposURL || "",
number: parseInt(dataCenterData.number) || 1, number: parseInt(dataCenterData.number) || 1,
areaId: dataCenterData.areaId || null, areaId: dataCenterData.areaId || null,
cityId: dataCenterData.cityId || null,
address: dataCenterData.address || "", address: dataCenterData.address || "",
latitude: dataCenterData.latitude latitude: dataCenterData.latitude
? parseFloat(dataCenterData.latitude) ? parseFloat(dataCenterData.latitude)

View File

@@ -20,15 +20,14 @@ const DataCenter = () => {
const getAllPhysicalMachines = (dataCenter) => { const getAllPhysicalMachines = (dataCenter) => {
// Physical machines are directly in the dataCenter object, not in projects // Physical machines are directly in the dataCenter object, not in projects
const pms = dataCenter.physicalMachines || []; const pms = dataCenter.physicalMachines || [];
console.log(`Physical machines for ${dataCenter.dataCenter}:`, pms);
return pms; return pms;
}; };
// Table columns following your pattern // Table columns following your pattern
const initialColumns = [ const initialColumns = [
{ {
name: "Number", name: "External ID",
selector: (row) => row.number, selector: (row) => row.externalId,
sortable: true, sortable: true,
minWidth: "100px", minWidth: "100px",
}, },
@@ -39,32 +38,32 @@ const DataCenter = () => {
minWidth: "200px", minWidth: "200px",
}, },
// Projects - Based on API response, this field might not exist or be structured differently // Projects - Based on API response, this field might not exist or be structured differently
{ // {
name: "Projects", // name: "Projects",
selector: (row) => row.projects?.length || 0, // selector: (row) => row.projects?.length || 0,
sortable: true, // sortable: true,
minWidth: "200px", // minWidth: "200px",
cell: (row) => ( // cell: (row) => (
<div> // <div>
{row.projects && row.projects.length > 0 ? ( // {row.projects && row.projects.length > 0 ? (
<div className="d-flex flex-column"> // <div className="d-flex flex-column">
{row.projects.map((project, index) => ( // {row.projects.map((project, index) => (
<div // <div
key={project.id} // key={project.id}
className={`badge badge-light-primary ${ // className={`badge badge-light-primary ${
index > 0 ? "mt-1" : "" // index > 0 ? "mt-1" : ""
}`} // }`}
> // >
{project.name} // {project.name}
</div> // </div>
))} // ))}
</div> // </div>
) : ( // ) : (
<span className="text-muted">-</span> // <span className="text-muted">-</span>
)} // )}
</div> // </div>
), // ),
}, // },
// Physical Machines // Physical Machines
{ {
name: "Physical Machines", name: "Physical Machines",

View File

@@ -412,11 +412,11 @@ const DataCenterManagement = () => {
number: row.number?.toString(), number: row.number?.toString(),
address: row.address || "", address: row.address || "",
areaId: row.area?.id || null, areaId: row.area?.id || null,
cityId: null, cityId: row.city?.id || null,
latitude: row.latitude, latitude: row.latitude,
longitude: row.longitude, longitude: row.longitude,
ayposURL: row.ayposURL || "", ayposURL: row.ayposURL || "",
city: row.city || "", city: row.city?.name || "",
emissionScopeId: row.emissionScope?.id || null, emissionScopeId: row.emissionScope?.id || null,
sectorId: row.sector?.id || null, sectorId: row.sector?.id || null,
subSectorId: row.subSector?.id || null, subSectorId: row.subSector?.id || null,
@@ -611,6 +611,7 @@ const DataCenterManagement = () => {
number: parseInt(selectedDataCenter.number || "1"), number: parseInt(selectedDataCenter.number || "1"),
address: selectedDataCenter.address, address: selectedDataCenter.address,
areaId: selectedDataCenter.areaId, areaId: selectedDataCenter.areaId,
cityId: selectedDataCenter.cityId,
latitude: selectedDataCenter.latitude latitude: selectedDataCenter.latitude
? parseFloat(selectedDataCenter.latitude) ? parseFloat(selectedDataCenter.latitude)
: null, : null,

View File

@@ -95,17 +95,6 @@ function MainDataTables() {
size: 150, size: 150,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>, Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
}, },
{
header: t("Created Date"),
accessorKey: "createdDate",
size: 180,
Cell: ({ cell }) => (
<span>
{cell.getValue() ? new Date(cell.getValue()).toLocaleString() : "-"}
</span>
),
sortable: true,
},
{ {
header: t("Physical Machine"), header: t("Physical Machine"),
accessorKey: "physicalMachine", accessorKey: "physicalMachine",
@@ -142,6 +131,17 @@ function MainDataTables() {
size: 100, size: 100,
Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>, Cell: ({ cell }) => <span>{editNumbers(cell.getValue()) || "-"}</span>,
}, },
{
header: t("Created Date"),
accessorKey: "createdDate",
size: 180,
Cell: ({ cell }) => (
<span>
{cell.getValue() ? new Date(cell.getValue()).toLocaleString() : "-"}
</span>
),
sortable: true,
},
], ],
[t] [t]
); );
@@ -209,7 +209,7 @@ function MainDataTables() {
enableFilters={true} enableFilters={true}
enableGlobalFilter={true} enableGlobalFilter={true}
enablePagination={true} enablePagination={true}
enableColumnResizing={false} // Disable resizing for better performance enableColumnResizing={true} // Disable resizing for better performance
enableStickyHeader={true} enableStickyHeader={true}
enableRowVirtualization={true} // Enable virtualization for large datasets enableRowVirtualization={true} // Enable virtualization for large datasets
enableColumnVirtualization={false} // Keep columns visible enableColumnVirtualization={false} // Keep columns visible
@@ -248,7 +248,7 @@ function MainDataTables() {
}} }}
// Disable features that can slow down large tables // Disable features that can slow down large tables
enableRowSelection={false} enableRowSelection={false}
enableColumnOrdering={false} enableColumnOrdering={true}
enableColumnDragging={false} enableColumnDragging={false}
enableDensityToggle={false} enableDensityToggle={false}
enableFullScreenToggle={false} enableFullScreenToggle={false}

View File

@@ -41,6 +41,78 @@ import { ChromePicker } from "react-color";
import { customFilterForSelect } from "../utility/Utils"; import { customFilterForSelect } from "../utility/Utils";
import { permissionCheck } from "../components/permission-check"; import { permissionCheck } from "../components/permission-check";
import { getDataCenters } from "../redux/actions/dataCenter"; import { getDataCenters } from "../redux/actions/dataCenter";
import L from "leaflet";
// Custom data center icon
const dataCenterIcon = new L.Icon({
iconUrl:
"data:image/svg+xml;base64," +
btoa(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
<defs>
<linearGradient id="serverGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#4A90E2;stop-opacity:1" />
<stop offset="100%" style="stop-color:#2E5BBA;stop-opacity:1" />
</linearGradient>
<linearGradient id="rackGradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#F5F5F5;stop-opacity:1" />
<stop offset="100%" style="stop-color:#E0E0E0;stop-opacity:1" />
</linearGradient>
</defs>
<!-- Main server rack -->
<rect x="8" y="4" width="32" height="40" rx="2" ry="2" fill="url(#rackGradient)" stroke="#B0B0B0" stroke-width="1"/>
<!-- Server units -->
<rect x="10" y="6" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="12" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="18" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="24" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="30" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<rect x="10" y="36" width="28" height="4" rx="1" fill="url(#serverGradient)" stroke="#2E5BBA" stroke-width="0.5"/>
<!-- LED indicators -->
<circle cx="13" cy="8" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="14" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="20" r="0.8" fill="#FFFF00"/>
<circle cx="13" cy="26" r="0.8" fill="#00FF00"/>
<circle cx="13" cy="32" r="0.8" fill="#FF0000"/>
<circle cx="13" cy="38" r="0.8" fill="#00FF00"/>
<!-- Power indicators -->
<circle cx="35" cy="8" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="14" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="20" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="26" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="32" r="0.6" fill="#0080FF"/>
<circle cx="35" cy="38" r="0.6" fill="#0080FF"/>
<!-- Ventilation grilles -->
<rect x="16" y="7" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="8.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="13" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="14.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="19" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="20.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="25" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="26.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="31" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="32.5" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="37" width="16" height="0.5" fill="#1A4A8A"/>
<rect x="16" y="38.5" width="16" height="0.5" fill="#1A4A8A"/>
<!-- Base/feet -->
<rect x="6" y="42" width="4" height="2" rx="1" fill="#808080"/>
<rect x="38" y="42" width="4" height="2" rx="1" fill="#808080"/>
<!-- Shadow -->
<ellipse cx="24" cy="45" rx="18" ry="2" fill="#000000" opacity="0.2"/>
</svg>
`),
iconSize: [48, 48],
iconAnchor: [18, 36],
popupAnchor: [0, -36],
});
const ColorPicker = ({ selectedColors, setSelectedColors, index }) => { const ColorPicker = ({ selectedColors, setSelectedColors, index }) => {
const [showColorPicker, setShowColorPicker] = useState(false); const [showColorPicker, setShowColorPicker] = useState(false);
@@ -627,10 +699,25 @@ const Map = () => {
if (!dc.latitude || !dc.longitude) return null; if (!dc.latitude || !dc.longitude) return null;
return ( return (
<Marker key={dc.id} position={[dc.latitude, dc.longitude]}> <Marker
key={dc.id}
position={[dc.latitude, dc.longitude]}
icon={dataCenterIcon}
>
<Popup> <Popup>
<div className="data-center-popup"> <div className="data-center-popup">
<h5 className="mb-2">{dc.dataCenter}</h5> <h5 className="mb-2 text-primary">{dc.dataCenter}</h5>
<div className="mb-2">
<p className="mb-1">
<strong>{t("DataCenter.city")}:</strong>{" "}
<span>{dc.city?.name || "-"}</span>
</p>
{dc.address && (
<p className="mb-1 small text-muted">
<strong>{t("Address")}:</strong> {dc.address}
</p>
)}
</div>
<p className="mb-1"> <p className="mb-1">
<strong>{t("DataCenter.number")}:</strong> {dc.number} <strong>{t("DataCenter.number")}:</strong> {dc.number}
</p> </p>
@@ -638,20 +725,25 @@ const Map = () => {
<strong>{t("DataCenter.externalId")}:</strong>{" "} <strong>{t("DataCenter.externalId")}:</strong>{" "}
{dc.externalId} {dc.externalId}
</p> </p>
<p className="mb-1">
<strong>{t("DataCenter.city")}:</strong>{" "}
{dc.area?.cities?.map((city) => city.name).join(", ") ||
"-"}
</p>
{dc.area && ( {dc.area && (
<p className="mb-1"> <p className="mb-1">
<strong>{t("Area")}:</strong> {dc.area.tag} <strong>{t("Area")}:</strong> {dc.area.tag}
</p> </p>
)} )}
{dc.physicalMachines?.length > 0 && (
<p className="mb-1">
<strong>{t("Physical Machines")}:</strong>{" "}
<span className="badge badge-secondary">
{dc.physicalMachines.length}
</span>
</p>
)}
{dc.dataCenterEmissionSources?.length > 0 && ( {dc.dataCenterEmissionSources?.length > 0 && (
<p className="mb-1"> <p className="mb-1">
<strong>{t("EmissionSources.emissionSources")}:</strong>{" "} <strong>{t("EmissionSources.emissionSources")}:</strong>{" "}
<span className="badge badge-info">
{dc.dataCenterEmissionSources.length} {dc.dataCenterEmissionSources.length}
</span>
</p> </p>
)} )}
{dc.ayposURL && ( {dc.ayposURL && (