SoftwareBrothers / adminjs

AdminJS is an admin panel for apps written in node.js
https://adminjs.co
MIT License
8.06k stars 646 forks source link

[Bug]: Custom Component is taking too long to load and resulting in heap memory out of usage. #1656

Open harshagr64 opened 2 months ago

harshagr64 commented 2 months ago

Contact Details

No response

What happened?

I have the below file containing my custom component, can you help me understand why Admin JS is taking so long to load the UI.

Before using this file in my code, Admin js loaded instantly, but now it is taking almost 1 minute to load the UI page.

import { ActionProps } from "adminjs";
import React from "react";
import {
  Card,
  CardContent,
  IconButton,
  ImageList,
  ImageListItem,
  ImageListItemBar,
  Stack,
  Typography,
} from "@mui/material";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import axios from "axios";
// import "./styles.css";

const CustomDetailsPage = (props: ActionProps) => {
  // Assuming 'data' is an object with properties: name, colonyId, number, images
  // const { name, colonyId, number, images } = props;
  const model = { Colony: "colonyModel", Property: "propertyModel" };
  const { record, action } = props;
  const params = record?.params ?? {};
  const images = [];
  const currentUrl = window.location.origin;

  const detailValue = (name) => {
    if (record?.populated?.[name]) {
      return record?.populated?.[name]?.params?.name;
    }
    return null;
  };

  const deleteImage = async (id, imageArray) => {
    // console.log(dbModel, id, imageArray);
    const { resourceId } = action;
    const result = imageArray.splice(id, 1);
    try {
      const response = await axios.post(`${currentUrl}/product/delete-image`, {
        model: model[resourceId],
        images: imageArray,
        id: params._id,
      });
      window.location.reload();
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  for (const key in params) {
    if (key.startsWith("images")) {
      images.push(params[key]);
      delete params[key]; // Remove individual "images" fields
    }
  }
  params.images = images;

  return (
    <Card>
      <CardContent>
        {Object.entries(params).map(([key, value]) => (
          <Stack direction="column" spacing={0.5} key={key} sx={{ mb: 3 }}>
            <Typography
              sx={{
                fontFamily: "Roboto, sans-serif",
                fontSize: "12px",
                color: "rgb(137, 138, 154)",
              }}
            >
              {key}:
            </Typography>
            {key?.includes("images") ? (
              <ImageList
                sx={{ width: 500, height: 450 }}
                rowHeight={164}
                cols={2}
              >
                {value?.map((item, id) => (
                  <ImageListItem key={id}>
                    <img
                      alt="testing"
                      loading="lazy"
                      src={`${currentUrl}/public/uploads/${item}`}
                    />
                    <ImageListItemBar
                      sx={{
                        background:
                          "linear-gradient(to bottom, rgba(0,0,0,0.7) 0%, " +
                          "rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)",
                      }}
                      position="top"
                      actionIcon={
                        <IconButton
                          sx={{ color: "white" }}
                          onClick={() => deleteImage(id, value)}
                        >
                          <DeleteOutlineIcon />
                        </IconButton>
                      }
                      actionPosition="right"
                    />
                  </ImageListItem>
                ))}
              </ImageList>
            ) : (
              <Typography
                sx={{
                  fontFamily: "Roboto, sans-serif",
                  fontSize: "14px",
                }}
              >
                {detailValue(key) ?? value}
              </Typography>
            )}
          </Stack>
        ))}
      </CardContent>
    </Card>
  );
};

export default CustomDetailsPage;

Bug prevalence

Multiple Times

AdminJS dependencies version

v7.2.0

What browsers do you see the problem on?

Firefox, Chrome, Safari, Microsoft Edge

Relevant log output

No response

Relevant code that's giving you issues

import { ActionProps } from "adminjs";
import React from "react";
import {
  Card,
  CardContent,
  IconButton,
  ImageList,
  ImageListItem,
  ImageListItemBar,
  Stack,
  Typography,
} from "@mui/material";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import axios from "axios";
// import "./styles.css";

const CustomDetailsPage = (props: ActionProps) => {
  // Assuming 'data' is an object with properties: name, colonyId, number, images
  // const { name, colonyId, number, images } = props;
  const model = { Colony: "colonyModel", Property: "propertyModel" };
  const { record, action } = props;
  const params = record?.params ?? {};
  const images = [];
  const currentUrl = window.location.origin;

  const detailValue = (name) => {
    if (record?.populated?.[name]) {
      return record?.populated?.[name]?.params?.name;
    }
    return null;
  };

  const deleteImage = async (id, imageArray) => {
    // console.log(dbModel, id, imageArray);
    const { resourceId } = action;
    const result = imageArray.splice(id, 1);
    try {
      const response = await axios.post(`${currentUrl}/product/delete-image`, {
        model: model[resourceId],
        images: imageArray,
        id: params._id,
      });
      window.location.reload();
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  for (const key in params) {
    if (key.startsWith("images")) {
      images.push(params[key]);
      delete params[key]; // Remove individual "images" fields
    }
  }
  params.images = images;

  return (
    <Card>
      <CardContent>
        {Object.entries(params).map(([key, value]) => (
          <Stack direction="column" spacing={0.5} key={key} sx={{ mb: 3 }}>
            <Typography
              sx={{
                fontFamily: "Roboto, sans-serif",
                fontSize: "12px",
                color: "rgb(137, 138, 154)",
              }}
            >
              {key}:
            </Typography>
            {key?.includes("images") ? (
              <ImageList
                sx={{ width: 500, height: 450 }}
                rowHeight={164}
                cols={2}
              >
                {value?.map((item, id) => (
                  <ImageListItem key={id}>
                    <img
                      alt="testing"
                      loading="lazy"
                      src={`${currentUrl}/public/uploads/${item}`}
                    />
                    <ImageListItemBar
                      sx={{
                        background:
                          "linear-gradient(to bottom, rgba(0,0,0,0.7) 0%, " +
                          "rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)",
                      }}
                      position="top"
                      actionIcon={
                        <IconButton
                          sx={{ color: "white" }}
                          onClick={() => deleteImage(id, value)}
                        >
                          <DeleteOutlineIcon />
                        </IconButton>
                      }
                      actionPosition="right"
                    />
                  </ImageListItem>
                ))}
              </ImageList>
            ) : (
              <Typography
                sx={{
                  fontFamily: "Roboto, sans-serif",
                  fontSize: "14px",
                }}
              >
                {detailValue(key) ?? value}
              </Typography>
            )}
          </Stack>
        ))}
      </CardContent>
    </Card>
  );
};

export default CustomDetailsPage;
dziraf commented 2 months ago

My guess is that your imports load the entire MUI bundle which is very heavy. You could try to use tree-shaking guidelines from their docs: https://mui.com/material-ui/guides/minimizing-bundle-size/

harshagr64 commented 2 months ago

Thanks @dziraf, its working now.