export function MemoryMetricsGrid()

in src/components/graphs/MemorySpecs/memoryMetricsGrid.tsx [122:375]


export function MemoryMetricsGrid() {
  const { toast } = useToast();
  const mode = useContext<ModeType>(ModeContext);
  const [ioTimeData, setIoTimeData] = useState([]);
  const [diskRWData, setDiskRWData] = useState([]);
  const [diskIOPSData, setDiskIOPSData] = useState([]);
  const [diskWaitTimeData, setDiskWaitTimeData] = useState([]);
  const [_, setLoadingDiskIOPS] = useState(false); // Loading state
  const [__, setErrorDiskIOPS] = useState(null); // Error state

  const fetchIoTimeData = async () => {
    if (mode === "offline") {
      setIoTimeData(TimeDuringIOData?.data);
      toast({
        title: "Offline Mode",
        description: "Using sample data in offline mode.",
        variant: "default",
      });
      return;
    }

    try {
      setLoadingDiskIOPS(true); // Set loading state
      setErrorDiskIOPS(null); // Clear errors

      const until = new Date().getTime(); // Current timestamp in ms
      const from = new Date(until - 1 * 60 * 60 * 1000).getTime(); // 1 hour ago

      // Fetch data from the backend
      const response = await middlewareApi.post(
        "/nodeExporter/getTimeSpentDoingIO",
        {
          from: parseFloat((from / 1000).toFixed(3)),
          until: parseFloat((until / 1000).toFixed(3)),
          step: 14,
        }
      );

      const data = response?.data?.data.map((item) => ({
        name: new Date(item.time).toLocaleTimeString(), // Format time
        value: Math.floor(item.value * 1000), // Convert seconds to milliseconds
      }));

      console.log("Disk IO Time Data:", data);
      setIoTimeData(data); // Update state with data
      setLoadingDiskIOPS(false); // Reset loading state
    } catch (error) {
      console.error("Error fetching Disk IO Time data:", error);
      setErrorDiskIOPS(error?.message || "Failed to fetch Disk IO Time data.");
      setLoadingDiskIOPS(false); // Reset loading on error
    }
  };

  const fetchDiskRWData = async () => {
    if (mode === "offline") {
      setDiskRWData(DiskRWData?.data?.writeMerged);
      return;
    }
    try {
      setLoadingDiskIOPS(true); // Indicate loading state
      setErrorDiskIOPS(null); // Clear previous errors

      const until = new Date().getTime(); // Current time
      const from = new Date(until - 1 * 60 * 60 * 1000).getTime(); // Last 1 hour
      const step = 14; // Step size in seconds

      // Call the backend API
      const response = await middlewareApi.post("/nodeExporter/getDiskRWData", {
        from: parseFloat((from / 1000).toFixed(3)),
        until: parseFloat((until / 1000).toFixed(3)),
        step,
      });

      // Format the data for the chart
      const processMetricData = (metricData, label) =>
        metricData.map(({ time, value }) => ({
          name: new Date(time).toLocaleTimeString(), // Format timestamp
          value: Math.floor(value * 1000), // Convert to milliseconds
          metric: label, // Identify metric type (read/write)
        }));

      const readMergedData = processMetricData(
        response?.data?.data?.readMerged,
        "Read Merged"
      );
      const writeMergedData = processMetricData(
        response?.data?.data?.writeMerged,
        "Write Merged"
      );

      // Combine data and update state
      setDiskRWData([...readMergedData, ...writeMergedData]);
      setLoadingDiskIOPS(false); // Reset loading state
    } catch (error) {
      console.error("Error fetching Disk Merged Data:", error);
      setErrorDiskIOPS(error?.message || "Failed to fetch Disk Merged Data.");
      setLoadingDiskIOPS(false); // Reset loading state on error
    }
  };

  const fetchDiskIOPSData = async () => {
    if (mode === "offline") {
      setDiskIOPSData(DiskIOPSData?.data);
      return;
    }
    try {
      setLoadingDiskIOPS(true); // Indicate loading state
      setErrorDiskIOPS(null); // Clear previous errors

      const until = new Date().getTime(); // Current time
      const from = new Date(until - 1 * 60 * 60 * 1000).getTime(); // Last 1 hour
      const step = 14; // Step size in seconds

      // Call the backend API
      const response = await middlewareApi.post("/nodeExporter/getDiskIOPS", {
        from: parseFloat((from / 1000).toFixed(3)),
        until: parseFloat((until / 1000).toFixed(3)),
        step,
      });

      // Format the data for the chart
      const processMetricData = (metricData) =>
        metricData.map(({ time, value }) => ({
          name: new Date(time).toLocaleTimeString(), // Format timestamp for X-axis
          value: parseFloat(value).toFixed(2), // Limit to 2 decimal places
        }));

      const formattedData = processMetricData(response?.data?.data || []);

      console.log("Formatted Disk IOPS Data:", formattedData);
      setDiskIOPSData(formattedData); // Update state with formatted data
      setLoadingDiskIOPS(false); // Reset loading state
    } catch (error) {
      console.error("Error fetching Disk IOPS data:", error);
      setErrorDiskIOPS(error?.message || "Failed to fetch Disk IOPS data.");
      setLoadingDiskIOPS(false); // Reset loading state on error
    }
  };

  const fetchDiskWaitTimeData = async () => {
    if (mode === "offline") {
      setDiskWaitTimeData(DiskWaitTimeData?.data?.writeWaitTime);
      return;
    }
    try {
      setLoadingDiskIOPS(true); // Indicate loading state
      setErrorDiskIOPS(null); // Clear previous errors

      const until = new Date().getTime(); // Current time
      const from = new Date(until - 1 * 60 * 60 * 1000).getTime(); // Last 1 hour
      const step = 14; // Step size in seconds

      // Call the backend API
      const response = await middlewareApi.post(
        "/nodeExporter/getDiskWaitTime",
        {
          from: parseFloat((from / 1000).toFixed(3)),
          until: parseFloat((until / 1000).toFixed(3)),
          step,
        }
      );

      // Format the data for the chart
      const processMetricData = (metricData, label) =>
        metricData.map(({ time, value }) => ({
          name: new Date(time).toLocaleTimeString(), // Format timestamp
          value: Math.floor(value * 1000), // Convert to milliseconds
          metric: label, // Identify metric type (read/write)
        }));

      const readData = processMetricData(
        response?.data?.data?.readWaitTime,
        "Read"
      );
      const writeData = processMetricData(
        response?.data?.data?.writeWaitTime,
        "Write"
      );

      // Combine data and update state
      setDiskWaitTimeData([...readData, ...writeData]);
      setLoadingDiskIOPS(false); // Reset loading state
    } catch (error) {
      console.error("Error fetching Disk Wait Time data:", error);
      setErrorDiskIOPS(
        error?.message || "Failed to fetch Disk Wait Time data."
      );
      setLoadingDiskIOPS(false); // Reset loading state on error
    }
  };

  useEffect(() => {
    fetchIoTimeData();
    fetchDiskRWData();
    fetchDiskIOPSData();
    fetchDiskWaitTimeData();
  }, [mode]);

  const metrics = [
    {
      title: "Time Spent Doing I/O",
      yAxisLabel: "ms",
      data: ioTimeData,
      info: "Percentage of elapsed time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100% for devices serving requests serially. But for devices serving requests in parallel, such as RAID arrays and modern SSDs, this number does not reflect their performance limits.",
      onRefresh: fetchIoTimeData,
    },
    {
      title: "Disk R/W Data",
      yAxisLabel: "B",
      data: diskRWData,
      info: "The number of bytes read from or written to the device per second",
      onRefresh: fetchDiskRWData,
    },
    {
      title: "Disk IOPS",
      yAxisLabel: "",
      data: diskIOPSData,
      info: "The number (after merges) of I/O requests completed per second for the device",
      onRefresh: fetchDiskIOPSData,
    },
    {
      title: "Disk Average Wait Time",
      yAxisLabel: "ms",
      data: diskWaitTimeData,
      info: "The average time for requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.",
      onRefresh: fetchDiskWaitTimeData,
    },
  ];

  return (
    <Card className="bg-slate-900 p-6">
      <CardHeader className="flex flex-row items-center justify-between pb-2">
        <div className="flex items-center gap-2">
          <MemoryStick className="w-6 h-6 text-blue-400" />
          <CardTitle className="text-2xl font-bold">Disk Metrics</CardTitle>
        </div>
      </CardHeader>
      <CardContent>
        <div className="grid grid-cols-2 gap-6">
          {metrics.map((metric) => (
            <MetricChart
              key={metric.title}
              title={metric.title}
              data={metric.data}
              yAxisLabel={metric.yAxisLabel}
              onRefresh={metric.onRefresh}
              info={metric.info}
            />
          ))}
        </div>
      </CardContent>
    </Card>
  );
}